From eb7f283d66f1a9d34f70562b8a2984c826c56f76 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 27 Jan 2022 10:05:24 -0700 Subject: [PATCH 001/298] fix(secrets): actually set updated_at and updated_by fields (#578) * bug fix for secret metadata updated by field * make sure updated at gets same treatment --- secret/native/update.go | 6 ++++++ secret/native/update_test.go | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/secret/native/update.go b/secret/native/update.go index 6cefa3f94..7edbbf995 100644 --- a/secret/native/update.go +++ b/secret/native/update.go @@ -62,5 +62,11 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { sec.SetAllowCommand(s.GetAllowCommand()) } + // update updated_at if set + sec.SetUpdatedAt(s.GetUpdatedAt()) + + // update updated_by if set + sec.SetUpdatedBy(s.GetUpdatedBy()) + return c.Database.UpdateSecret(sec) } diff --git a/secret/native/update_test.go b/secret/native/update_test.go index 941df171f..419aead61 100644 --- a/secret/native/update_test.go +++ b/secret/native/update_test.go @@ -15,6 +15,22 @@ import ( func TestNative_Update(t *testing.T) { // setup types + original := new(library.Secret) + original.SetID(1) + original.SetOrg("foo") + original.SetRepo("bar") + original.SetTeam("") + original.SetName("baz") + original.SetValue("secretValue") + original.SetType("repo") + original.SetImages([]string{"foo", "baz"}) + original.SetEvents([]string{"foob", "bar"}) + original.SetAllowCommand(true) + original.SetCreatedAt(1) + original.SetCreatedBy("user") + original.SetUpdatedAt(1) + original.SetUpdatedBy("user") + want := new(library.Secret) want.SetID(1) want.SetOrg("foo") @@ -40,7 +56,7 @@ func TestNative_Update(t *testing.T) { _sql.Close() }() - _ = db.CreateSecret(want) + _ = db.CreateSecret(original) // run test s, err := New( From fefc192c09e4e394db897f15e0aa40a7c9f58e8e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 15:15:54 -0600 Subject: [PATCH 002/298] fix(deps): update deps (patch) (#579) Co-authored-by: Renovate Bot --- go.mod | 12 ++++++------ go.sum | 27 ++++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index cced08cac..b22b97d79 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.18.0 - github.com/aws/aws-sdk-go v1.42.27 + github.com/aws/aws-sdk-go v1.42.44 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 @@ -16,7 +16,7 @@ require ( github.com/go-redis/redis/v8 v8.11.4 github.com/go-vela/types v0.12.0-rc1 github.com/golang-jwt/jwt/v4 v4.2.0 - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.1 @@ -25,7 +25,7 @@ require ( github.com/hashicorp/vault/api v1.3.1 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.0 + github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.0 github.com/urfave/cli/v2 v2.3.0 @@ -35,8 +35,8 @@ require ( gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.2.3 gorm.io/driver/sqlite v1.2.6 - gorm.io/gorm v1.22.4 - k8s.io/apimachinery v0.23.1 + gorm.io/gorm v1.22.5 + k8s.io/apimachinery v0.23.3 ) require ( @@ -93,7 +93,7 @@ require ( github.com/jackc/pgtype v1.9.0 // indirect github.com/jackc/pgx/v4 v4.14.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.3 // indirect + github.com/jinzhu/now v1.1.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kr/pretty v0.3.0 // indirect diff --git a/go.sum b/go.sum index 771fa64d8..ee4928c80 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.42.27 h1:kxsBXQg3ee6LLbqjp5/oUeDgG7TENFrWYDmEVnd7spU= -github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.42.44 h1:vPlF4cUsdN5ETfvb7ewZFbFZyB6Rsfndt3kS2XqLXKo= +github.com/aws/aws-sdk-go v1.42.44/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -236,8 +236,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec= github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg= @@ -394,8 +395,8 @@ github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyX github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= -github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -525,8 +526,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1028,8 +1029,8 @@ gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM= -gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= +gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU= +gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1037,8 +1038,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo= -k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= +k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk= +k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= @@ -1046,12 +1047,12 @@ k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 15ba421ed7b2974db2d236ba5cbdee2620070604 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Wed, 2 Feb 2022 19:58:00 +0000 Subject: [PATCH 003/298] chore: update clone image to latest (#580) --- compiler/native/clone.go | 2 +- compiler/native/clone_test.go | 4 ++-- compiler/native/compile_test.go | 24 +++++++++++----------- compiler/native/testdata/clone_replace.yml | 2 +- queue/redis/redis_test.go | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/native/clone.go b/compiler/native/clone.go index f62f2da6f..08cfb3193 100644 --- a/compiler/native/clone.go +++ b/compiler/native/clone.go @@ -11,7 +11,7 @@ import ( const ( // default image for clone process. - cloneImage = "target/vela-git:v0.4.0" + cloneImage = "target/vela-git:v0.5.1" // default name for clone stage. cloneStageName = "clone" // default name for clone step. diff --git a/compiler/native/clone_test.go b/compiler/native/clone_test.go index fd0f137d2..890efc267 100644 --- a/compiler/native/clone_test.go +++ b/compiler/native/clone_test.go @@ -53,7 +53,7 @@ func TestNative_CloneStage(t *testing.T) { Name: "clone", Steps: yaml.StepSlice{ &yaml.Step{ - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Pull: "not_present", }, @@ -142,7 +142,7 @@ func TestNative_CloneStep(t *testing.T) { Version: "v1", Steps: yaml.StepSlice{ &yaml.Step{ - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Pull: "not_present", }, diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index f7a925c97..3de0c6ae2 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -129,7 +129,7 @@ func TestNative_Compile_StagesPipeline(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: cloneEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -485,7 +485,7 @@ func TestNative_Compile_StepsPipeline(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: cloneEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -702,7 +702,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -955,7 +955,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1147,7 +1147,7 @@ func TestNative_Compile_InvalidType(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1298,7 +1298,7 @@ func TestNative_Compile_Clone(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1337,7 +1337,7 @@ func TestNative_Compile_Clone(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: cloneEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "always", @@ -1452,7 +1452,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1496,7 +1496,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultGoEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1540,7 +1540,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultStarlarkEnv, - Image: "target/vela-git:v0.4.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "not_present", @@ -1724,7 +1724,7 @@ func Test_client_modifyConfig(t *testing.T) { }, &yaml.Step{ Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.3.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Pull: "not_present", }, @@ -1757,7 +1757,7 @@ func Test_client_modifyConfig(t *testing.T) { }, &yaml.Step{ Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.3.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Pull: "not_present", }, diff --git a/compiler/native/testdata/clone_replace.yml b/compiler/native/testdata/clone_replace.yml index 69ab9a369..e258910b6 100644 --- a/compiler/native/testdata/clone_replace.yml +++ b/compiler/native/testdata/clone_replace.yml @@ -5,7 +5,7 @@ metadata: steps: - name: clone - image: target/vela-git:v0.4.0 + image: target/vela-git:v0.5.1 parameters: depth: 5 pull: always diff --git a/queue/redis/redis_test.go b/queue/redis/redis_test.go index 1e607b856..d7faeedd3 100644 --- a/queue/redis/redis_test.go +++ b/queue/redis/redis_test.go @@ -121,7 +121,7 @@ var ( ID: "step_github_octocat_1_clone", Directory: "/home/github/octocat", Environment: map[string]string{"FOO": "bar"}, - Image: "target/vela-git:v0.3.0", + Image: "target/vela-git:v0.5.1", Name: "clone", Number: 2, Pull: "always", From 50122359697b43144b08070a1f15cfc45b6123bd Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 4 Feb 2022 19:55:23 +0000 Subject: [PATCH 004/298] chore(release): v0.12.0 (#582) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b22b97d79..0085b33d7 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.12.0-rc1 + github.com/go-vela/types v0.12.0 github.com/golang-jwt/jwt/v4 v4.2.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 diff --git a/go.sum b/go.sum index ee4928c80..a7c12ae8e 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.12.0-rc1 h1:/qXnZ10AAlJ7l4Rr/FkAfhGFz8G9ww1VkedAXJatHu8= -github.com/go-vela/types v0.12.0-rc1/go.mod h1:nMZJ/0tb0HO8/AVaJXHuR5slG9UPuP9or+CnkuyFcL4= +github.com/go-vela/types v0.12.0 h1:RnliZ5sZ0ceDRNyjp8o5uPKMIgLF7Gd7JRJWgOLgOPw= +github.com/go-vela/types v0.12.0/go.mod h1:nMZJ/0tb0HO8/AVaJXHuR5slG9UPuP9or+CnkuyFcL4= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From 7f0edfcbf9c15e1727e99661c383869e1c7ce019 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Feb 2022 10:22:43 -0600 Subject: [PATCH 005/298] fix(deps): update go.starlark.net commit hash to bb14e15 (#581) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0085b33d7..be6ef905c 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.0 github.com/urfave/cli/v2 v2.3.0 - go.starlark.net v0.0.0-20211203141949-70c0e40ae128 + go.starlark.net v0.0.0-20220203230714-bb14e151c28f golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index a7c12ae8e..bcd3dc5a6 100644 --- a/go.sum +++ b/go.sum @@ -613,8 +613,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20211203141949-70c0e40ae128 h1:bxH+EXOo87zEOwKDdZ8Tevgi6irRbqheRm/fr293c58= -go.starlark.net v0.0.0-20211203141949-70c0e40ae128/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220203230714-bb14e151c28f h1:aW4TkS39/naJa9wPSbIXtZUQOlvuUh8gxCsLRrJoByU= +go.starlark.net v0.0.0-20220203230714-bb14e151c28f/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From 09c50c25579da62c620ca3c44789baa8f7f42fb5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 14 Feb 2022 15:02:43 -0700 Subject: [PATCH 006/298] fix(build): increase error limit to 1000 (#584) --- database/postgres/ddl/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/postgres/ddl/build.go b/database/postgres/ddl/build.go index da8f60295..6ed08ec25 100644 --- a/database/postgres/ddl/build.go +++ b/database/postgres/ddl/build.go @@ -17,7 +17,7 @@ builds ( parent INTEGER, event VARCHAR(250), status VARCHAR(250), - error VARCHAR(500), + error VARCHAR(1000), enqueued INTEGER, created INTEGER, started INTEGER, From bf8dd80a928a6b1907b00ab06f44321bb70b508d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 09:30:46 -0600 Subject: [PATCH 007/298] fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.3.0 (#583) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index be6ef905c..daa6b5351 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 github.com/go-vela/types v0.12.0 - github.com/golang-jwt/jwt/v4 v4.2.0 + github.com/golang-jwt/jwt/v4 v4.3.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index bcd3dc5a6..b7d1cf14f 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= +github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= From 061b3679963b332fc264d157ed4f22dc10782f00 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 09:50:21 -0600 Subject: [PATCH 008/298] fix(deps): update go.starlark.net commit hash to c55a923 (#585) Co-authored-by: Renovate Bot Co-authored-by: Jordan Brockopp Co-authored-by: Kayla McKay <39921134+kaymckay@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index daa6b5351..3bf522772 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.0 github.com/urfave/cli/v2 v2.3.0 - go.starlark.net v0.0.0-20220203230714-bb14e151c28f + go.starlark.net v0.0.0-20220213143740-c55a923347b1 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index b7d1cf14f..b1f5ffe4a 100644 --- a/go.sum +++ b/go.sum @@ -613,8 +613,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220203230714-bb14e151c28f h1:aW4TkS39/naJa9wPSbIXtZUQOlvuUh8gxCsLRrJoByU= -go.starlark.net v0.0.0-20220203230714-bb14e151c28f/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220213143740-c55a923347b1 h1:CIAbrK9/d5xfj5LlSS+yLtP6BSCNZD3uvKcpahLzkX0= +go.starlark.net v0.0.0-20220213143740-c55a923347b1/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From ea8fadd3c76883df252fb3c3b60681deebd85e79 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:50:28 -0600 Subject: [PATCH 009/298] fix(deps): update deps (patch) (#587) Co-authored-by: Renovate Bot --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3bf522772..914ed04d0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.18.0 - github.com/aws/aws-sdk-go v1.42.44 + github.com/aws/aws-sdk-go v1.42.53 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 @@ -27,7 +27,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 - github.com/spf13/afero v1.8.0 + github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.3.0 go.starlark.net v0.0.0-20220213143740-c55a923347b1 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 diff --git a/go.sum b/go.sum index b1f5ffe4a..4e8da8741 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.42.44 h1:vPlF4cUsdN5ETfvb7ewZFbFZyB6Rsfndt3kS2XqLXKo= -github.com/aws/aws-sdk-go v1.42.44/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.42.53 h1:56T04NWcmc0ZVYFbUc6HdewDQ9iHQFlmS6hj96dRjJs= +github.com/aws/aws-sdk-go v1.42.53/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -571,8 +571,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= -github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.8.1 h1:izYHOT71f9iZ7iq37Uqjael60/vYC6vMtzedudZ0zEk= +github.com/spf13/afero v1.8.1/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= From 3f5f6281a1fa7c79ddd72701d1fd5981042ff9b8 Mon Sep 17 00:00:00 2001 From: Colin Dean Date: Wed, 16 Feb 2022 16:27:36 -0500 Subject: [PATCH 010/298] enhance: inform user what to do when the version property is missing (#577) * Inform user what to do when the version property is missing While setting up a new pipeline, I couldn't quite figure out what I was missing. Turns out, I'd missed something quite important when copypasting from an existing configuration, and neither the server nor the vela CLI could tell me what was wrong! This disambiguates that error message by providing a remedy. * Simplify error message and omit explicit version number Co-authored-by: Neal Co-authored-by: Kelly Merrick --- compiler/native/validate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/native/validate.go b/compiler/native/validate.go index 7d588a89f..482f3e09b 100644 --- a/compiler/native/validate.go +++ b/compiler/native/validate.go @@ -14,7 +14,7 @@ import ( func (c *client) Validate(p *yaml.Build) error { // check a version is provided if len(p.Version) == 0 { - return fmt.Errorf("no version provided") + return fmt.Errorf("no \"version:\" YAML property provided") } // check that stages or steps are provided From 3fe3d7eaabc3f1ee03d3a7636749bdc8009ff0ee Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 17 Feb 2022 14:28:56 -0700 Subject: [PATCH 011/298] fix(secrets): reject whitespace value secrets (#588) * fix(secrets): reject whitespace value secrets * edit error message Co-authored-by: Jordan Brockopp --- api/secret.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/api/secret.go b/api/secret.go index c870a1a7b..86b2c8181 100644 --- a/api/secret.go +++ b/api/secret.go @@ -81,6 +81,8 @@ import ( // CreateSecret represents the API handler to // create a secret in the configured backend. +// +// nolint: funlen // ignore funlen linter func CreateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -129,6 +131,16 @@ func CreateSecret(c *gin.Context) { return } + // reject secrets with solely whitespace characters as its value + trimmed := strings.TrimSpace(input.GetValue()) + if len(trimmed) == 0 { + retErr := fmt.Errorf("secret value must contain non-whitespace characters") + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + // update fields in secret object input.SetOrg(o) input.SetRepo(n) @@ -544,6 +556,8 @@ func GetSecret(c *gin.Context) { // "$ref": "#/definitions/Error" // UpdateSecret updates a secret for the provided secrets service. +// +// nolint: funlen // ignore funlen linter func UpdateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -595,6 +609,16 @@ func UpdateSecret(c *gin.Context) { return } + // reject secrets with solely whitespace characters as its value + trimmed := strings.TrimSpace(input.GetValue()) + if len(trimmed) == 0 { + retErr := fmt.Errorf("secret value must contain non-whitespace characters") + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + // update secret fields if provided input.SetName(s) input.SetOrg(o) From 4aa4a9f03b3d961226a46bff574d435c9784b6b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Feb 2022 10:45:02 -0600 Subject: [PATCH 012/298] fix(deps): update module gorm.io/driver/postgres to v1.3.1 (#591) Co-authored-by: Renovate Bot --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 914ed04d0..ea0eedb2f 100644 --- a/go.mod +++ b/go.mod @@ -33,9 +33,9 @@ require ( golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.2.3 + gorm.io/driver/postgres v1.3.1 gorm.io/driver/sqlite v1.2.6 - gorm.io/gorm v1.22.5 + gorm.io/gorm v1.23.1 k8s.io/apimachinery v0.23.3 ) @@ -90,8 +90,8 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.2.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.9.0 // indirect - github.com/jackc/pgx/v4 v4.14.0 // indirect + github.com/jackc/pgtype v1.9.1 // indirect + github.com/jackc/pgx/v4 v4.14.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum index 4e8da8741..0aee022f7 100644 --- a/go.sum +++ b/go.sum @@ -377,14 +377,14 @@ github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01C github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk= -github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= +github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc= -github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= +github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU= +github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -1024,13 +1024,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To= -gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs= +gorm.io/driver/postgres v1.3.1 h1:Pyv+gg1Gq1IgsLYytj/S2k7ebII3CzEdpqQkPOdH24g= +gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU= -gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.1 h1:aj5IlhDzEPsoIyOPtTRVI+SyaN1u6k613sbt4pwbxG0= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From d923c851ec52982935e35aa37e17c2797d298b2d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Feb 2022 12:00:55 -0600 Subject: [PATCH 013/298] fix(deps): update module k8s.io/apimachinery to v0.23.4 (#589) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ea0eedb2f..1dde60456 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( gorm.io/driver/postgres v1.3.1 gorm.io/driver/sqlite v1.2.6 gorm.io/gorm v1.23.1 - k8s.io/apimachinery v0.23.3 + k8s.io/apimachinery v0.23.4 ) require ( diff --git a/go.sum b/go.sum index 0aee022f7..ec339fc93 100644 --- a/go.sum +++ b/go.sum @@ -1038,8 +1038,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk= -k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= +k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= From 3fc439454e2de1930d1fb05b5a0daf1e22af2622 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Feb 2022 21:40:16 -0600 Subject: [PATCH 014/298] fix(deps): update module gorm.io/driver/sqlite to v1.3.1 (#592) Co-authored-by: Renovate Bot Co-authored-by: Kayla McKay <39921134+kaymckay@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 1dde60456..d4e566f81 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.1 - gorm.io/driver/sqlite v1.2.6 + gorm.io/driver/sqlite v1.3.1 gorm.io/gorm v1.23.1 k8s.io/apimachinery v0.23.4 ) diff --git a/go.sum b/go.sum index ec339fc93..796fd4d5a 100644 --- a/go.sum +++ b/go.sum @@ -394,7 +394,6 @@ github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZ github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -1026,9 +1025,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.3.1 h1:Pyv+gg1Gq1IgsLYytj/S2k7ebII3CzEdpqQkPOdH24g= gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= -gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= -gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= -gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk= +gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg= gorm.io/gorm v1.23.1 h1:aj5IlhDzEPsoIyOPtTRVI+SyaN1u6k613sbt4pwbxG0= gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 7db5e89ae4a3ca972070abaa1992552caeac80df Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 23 Feb 2022 08:56:37 -0700 Subject: [PATCH 015/298] enhance(api/build): adding the ability to search builds within time constraints (#586) * adding the ability to search builds within time constraints * correct swagger comment about param type * fixing swagger spec * remove api spec * ignore lll linter * change started to created * more descriptive API spec Co-authored-by: Jordan Brockopp Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/build.go | 38 +++++++++++++++++++++++++++- database/postgres/build_list.go | 4 ++- database/postgres/build_list_test.go | 17 +++++++++---- database/service.go | 3 ++- database/sqlite/build_list.go | 4 ++- database/sqlite/build_list_test.go | 5 +++- 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/api/build.go b/api/build.go index 0c5fb03fc..2cc92c1ea 100644 --- a/api/build.go +++ b/api/build.go @@ -407,6 +407,16 @@ func skipEmptyBuild(p *pipeline.Build) string { // type: integer // maximum: 100 // default: 10 +// - in: query +// name: before +// description: filter builds created before a certain time +// type: integer +// default: 1 +// - in: query +// name: after +// description: filter builds created after a certain time +// type: integer +// default: 0 // security: // - ApiKeyAuth: [] // responses: @@ -539,7 +549,33 @@ func GetBuilds(c *gin.Context) { // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) - b, t, err = database.FromContext(c).GetRepoBuildList(r, filters, page, perPage) + // capture before query parameter if present, default to now + // + // nolint: gomnd, lll // ignore magic number and long line length + before, err := strconv.ParseInt(c.DefaultQuery("before", strconv.FormatInt(time.Now().UTC().Unix(), 10)), 10, 64) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert before query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture after query parameter if present, default to 0 + // + // nolint: gomnd // ignore magic number + after, err := strconv.ParseInt(c.DefaultQuery("after", "0"), 10, 64) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert after query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + b, t, err = database.FromContext(c).GetRepoBuildList(r, filters, before, after, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get builds for repo %s: %w", r.GetFullName(), err) diff --git a/database/postgres/build_list.go b/database/postgres/build_list.go index a40cb93c3..670c6b7b4 100644 --- a/database/postgres/build_list.go +++ b/database/postgres/build_list.go @@ -131,7 +131,7 @@ func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, pag // GetRepoBuildList gets a list of all builds by repo ID from the database. // // nolint: lll // ignore long line length due to variable names -func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { +func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -159,6 +159,8 @@ func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{ err = c.Postgres. Table(constants.TableBuild). Where("repo_id = ?", r.GetID()). + Where("created < ?", before). + Where("created > ?", after). Where(filters). Order("number DESC"). Limit(perPage). diff --git a/database/postgres/build_list_test.go b/database/postgres/build_list_test.go index 247e4c282..031c9a110 100644 --- a/database/postgres/build_list_test.go +++ b/database/postgres/build_list_test.go @@ -7,6 +7,7 @@ package postgres import ( "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" @@ -372,12 +373,14 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { _buildOne.SetRepoID(1) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) + _buildOne.SetCreated(1) _buildTwo := testBuild() _buildTwo.SetID(2) _buildTwo.SetRepoID(1) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) + _buildTwo.SetCreated(2) _repo := testRepo() _repo.SetID(1) @@ -396,7 +399,7 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + _rows := sqlmock.NewRows([]string{"count"}).AddRow(3) // ensure the mock expects the query _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE repo_id = $1`).WillReturnRows(_rows) @@ -404,19 +407,23 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + ).AddRow(1, 1, 1, 0, "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, 2, 0, "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query - _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 ORDER BY number DESC LIMIT 10`).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND created < $2 AND created > $3 ORDER BY number DESC LIMIT 10`).WillReturnRows(_rows) // setup tests tests := []struct { failure bool + before int64 + after int64 want []*library.Build }{ { failure: false, + before: time.Now().UTC().Unix(), + after: 0, want: []*library.Build{_buildOne, _buildTwo}, }, } @@ -425,7 +432,7 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { // run tests for _, test := range tests { - got, _, err := _database.GetRepoBuildList(_repo, filters, 1, 10) + got, _, err := _database.GetRepoBuildList(_repo, filters, test.before, test.after, 1, 10) if test.failure { if err == nil { diff --git a/database/service.go b/database/service.go index 314f434e1..071437d29 100644 --- a/database/service.go +++ b/database/service.go @@ -42,7 +42,8 @@ type Service interface { GetDeploymentBuildList(string) ([]*library.Build, error) // GetRepoBuildList defines a function that // gets a list of builds by repo ID. - GetRepoBuildList(*library.Repo, map[string]interface{}, int, int) ([]*library.Build, int64, error) + // nolint: lll // ignore long line length + GetRepoBuildList(*library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) // GetOrgBuildList defines a function that // gets a list of builds by org. GetOrgBuildList(string, map[string]interface{}, int, int) ([]*library.Build, int64, error) diff --git a/database/sqlite/build_list.go b/database/sqlite/build_list.go index e5ca79cc0..a10c29d93 100644 --- a/database/sqlite/build_list.go +++ b/database/sqlite/build_list.go @@ -131,7 +131,7 @@ func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, pag // GetRepoBuildList gets a list of all builds by repo ID from the database. // // nolint: lll // ignore long line length due to variable names -func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { +func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -160,6 +160,8 @@ func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{ err = c.Sqlite. Table(constants.TableBuild). Where("repo_id = ?", r.GetID()). + Where("created < ?", before). + Where("created > ?", after). Where(filters). Order("number DESC"). Limit(perPage). diff --git a/database/sqlite/build_list_test.go b/database/sqlite/build_list_test.go index 1a07c291c..28f646fb5 100644 --- a/database/sqlite/build_list_test.go +++ b/database/sqlite/build_list_test.go @@ -8,6 +8,7 @@ import ( "log" "reflect" "testing" + "time" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/types/constants" @@ -444,12 +445,14 @@ func TestSqlite_Client_GetRepoBuildList(t *testing.T) { _buildOne.SetRepoID(1) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) + _buildOne.SetCreated(1) _buildTwo := testBuild() _buildTwo.SetID(2) _buildTwo.SetRepoID(1) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) + _buildTwo.SetCreated(2) _repo := testRepo() _repo.SetID(1) @@ -502,7 +505,7 @@ func TestSqlite_Client_GetRepoBuildList(t *testing.T) { } } - got, _, err := _database.GetRepoBuildList(_repo, filters, 1, 10) + got, _, err := _database.GetRepoBuildList(_repo, filters, time.Now().UTC().Unix(), 0, 1, 10) if test.failure { if err == nil { From 466d048ddbc4c16230cd7965309662dfaeae60d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Feb 2022 10:29:11 -0600 Subject: [PATCH 016/298] fix(deps): update go.starlark.net commit hash to 243c749 (#595) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d4e566f81..331efa392 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.3.0 - go.starlark.net v0.0.0-20220213143740-c55a923347b1 + go.starlark.net v0.0.0-20220223235035-243c74974e97 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 796fd4d5a..4572f9a66 100644 --- a/go.sum +++ b/go.sum @@ -612,8 +612,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220213143740-c55a923347b1 h1:CIAbrK9/d5xfj5LlSS+yLtP6BSCNZD3uvKcpahLzkX0= -go.starlark.net v0.0.0-20220213143740-c55a923347b1/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220223235035-243c74974e97 h1:ghIB+2LQvihWROIGpcAVPq/ce5O2uMQersgxXiOeTS4= +go.starlark.net v0.0.0-20220223235035-243c74974e97/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From 700c56fa81fa9de2149c954f8c465dd3a6179f44 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 08:56:32 -0600 Subject: [PATCH 017/298] fix(deps): update module github.com/aws/aws-sdk-go to v1.43.10 (#602) --- go.mod | 4 ++-- go.sum | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 331efa392..b4badce11 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.18.0 - github.com/aws/aws-sdk-go v1.42.53 + github.com/aws/aws-sdk-go v1.43.10 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 @@ -125,7 +125,7 @@ require ( github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect diff --git a/go.sum b/go.sum index 4572f9a66..a27b0c30f 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.42.53 h1:56T04NWcmc0ZVYFbUc6HdewDQ9iHQFlmS6hj96dRjJs= -github.com/aws/aws-sdk-go v1.42.53/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.43.10 h1:lFX6gzTBltYBnlJBjd2DWRCmqn2CbTcs6PW99/Dme7k= +github.com/aws/aws-sdk-go v1.43.10/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -721,8 +721,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -807,10 +807,12 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From d71799c2c0c0680ddbf2f557b822fcc7259d2982 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 3 Mar 2022 08:40:42 -0700 Subject: [PATCH 018/298] get rid of whitespace check for secret updating (#598) --- api/secret.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/api/secret.go b/api/secret.go index 86b2c8181..3f29eedb8 100644 --- a/api/secret.go +++ b/api/secret.go @@ -609,16 +609,6 @@ func UpdateSecret(c *gin.Context) { return } - // reject secrets with solely whitespace characters as its value - trimmed := strings.TrimSpace(input.GetValue()) - if len(trimmed) == 0 { - retErr := fmt.Errorf("secret value must contain non-whitespace characters") - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - // update secret fields if provided input.SetName(s) input.SetOrg(o) From 8d35d0817cf83272c918130fb5c79220d761879e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Mar 2022 07:14:48 +0000 Subject: [PATCH 019/298] chore(deps): update actions/checkout action to v3 (#604) Co-authored-by: Renovate Bot --- .github/workflows/build.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/reviewdog.yml | 4 ++-- .github/workflows/spec.yml | 2 +- .github/workflows/test.yml | 2 +- .github/workflows/validate.yml | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bfceca316..1840ce8f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: build run: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b78566d35..e9c2f66e5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 0ea5d35f5..28646bc50 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -15,7 +15,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # ensures we fetch tag history for the repository fetch-depth: 0 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 96d3d5e96..85a430292 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,7 +14,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # ensures we fetch tag history for the repository fetch-depth: 0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1619efbc4..ca89ae115 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: tags run: | diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 94d21fce1..1e0515d0f 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -13,7 +13,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 @@ -30,7 +30,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index 0411ccf59..9cc2d9cce 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -14,7 +14,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: tags run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b2f98b560..f6f20f5bd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: test run: | diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 374ec0b89..844bc7938 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -14,7 +14,7 @@ jobs: image: golang:1.17 steps: - name: clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: tags run: | From e25d9405c22bd264f8f063dbc7a034deaef6d968 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 4 Mar 2022 01:33:49 -0600 Subject: [PATCH 020/298] refactor: docs for local setup (#594) --- .env.example | 32 ++++++++++++++++++----------- DOCS.md | 50 +++++++++++++++++++++++++++++----------------- docker-compose.yml | 11 ++++++---- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/.env.example b/.env.example index 8ab90001b..c5bf492e9 100644 --- a/.env.example +++ b/.env.example @@ -9,23 +9,32 @@ # # ################## -# These are used by the ui service -# defined in the docker compose stack +# These are used by the ui service defined in the docker compose stack -# customize the location where you want users to provide feedback +# customize the location for the Vela server address # -# default: https://github.com/go-vela/ui/issues/new -# VELA_FEEDBACK_URL= +# Should match the "VELA_ADDR" value in docker-compose.yml when running locally. +VELA_API=http://localhost:8080 # customize the location where users can review documentation # # default: https://go-vela.github.io/docs # VELA_DOCS_URL= -# customize the location for the Vela server address +# customize the location where you want users to provide feedback # -# Should match the "VELA_ADDR" value in docker-compose.yml when running locally. -VELA_API=http://localhost:8080 +# default: https://github.com/go-vela/ui/issues/new +# VELA_FEEDBACK_URL= + +# customize the number of bytes for size of logs the UI will attempt to render +# +# default: 20000 (2 MB) +# VELA_LOG_BYTES_LIMIT= + +# customize the number of concurrent builds for a repo the UI will allow configuring +# +# default: 30 +# VELA_MAX_BUILD_LIMIT= ############################################################ # _______ _______ ______ __ __ _______ ______ # @@ -38,8 +47,7 @@ VELA_API=http://localhost:8080 # # ############################################################ -# These are used by the server service -# defined in the docker compose stack +# These are used by the server service defined in the docker compose stack # github web url (only required if using GitHub Enterprise) # @@ -47,7 +55,7 @@ VELA_API=http://localhost:8080 # VELA_SCM_ADDR= # github client id from oauth application -VELA_SCM_CLIENT= +# VELA_SCM_CLIENT= # github client secret from oauth application -VELA_SCM_SECRET= +# VELA_SCM_SECRET= \ No newline at end of file diff --git a/DOCS.md b/DOCS.md index 07e7d224a..940ee02ba 100644 --- a/DOCS.md +++ b/DOCS.md @@ -2,7 +2,7 @@ This document intends to provide information on how to get the Vela application running locally. -For more information, please see our [installation docs](https://go-vela.github.io/docs/install/). +For more information, please see our [administration docs](https://go-vela.github.io/docs/administration/). ## Prerequisites @@ -10,7 +10,7 @@ This section covers the dependencies required to get the Vela application runnin * [Docker](https://docs.docker.com/install/) - building block for local development * [Docker Compose](https://docs.docker.com/compose/install/) - start up local development -* [Github OAuth Client](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) - building block for local development +* [GitHub OAuth Client](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) - building block for local development * [Golang](https://golang.org/dl/) - for source code and [dependency management](https://github.com/golang/go/wiki/Modules) * [Make](https://www.gnu.org/software/make/) - start up local development @@ -34,26 +34,26 @@ git clone git@github.com:go-vela/server.git $HOME/go-vela/server cd $HOME/go-vela/server ``` -* If using GitHub Enterprise (default: `https://github.com/`), add the Web URL to a local `.env` file: +* If using GitHub Enterprise (default: `https://github.com`), add the Web URL to a local `.env` file: ```bash # add Github Enterprise Web URL to local `.env` file for `docker-compose` -echo "VELA_SOURCE_ADDR=" >> .env +echo "VELA_SCM_ADDR=" >> .env ``` * Create an [OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) and obtain secrets for local development: * `Application name` = `Vela - local` (name of the OAuth application shouldn't matter) - * `Homepage URL` = `http://localhost:8080` (base URL of the server) + * `Homepage URL` = `http://localhost:8888` (base URL of the web UI) * `Authorization callback URL` = `http://localhost:8080/authenticate` (authenticate endpoint of the base URL of the server) * Add OAuth client secrets to a local `.env` file: ```bash # add Github Client ID to local `.env` file for `docker-compose` -echo "VELA_SOURCE_CLIENT=" >> .env +echo "VELA_SCM_CLIENT=" >> .env # add Github Client Secret to local `.env` file for `docker-compose` -echo "VELA_SOURCE_SECRET=" >> .env +echo "VELA_SCM_SECRET=" >> .env ``` ## Start @@ -93,15 +93,15 @@ In order to run a build in Vela, you'll need to add a repo to the locally runnin

1. Navigate to the `Source Repositories` page @ http://localhost:8888/account/source-repos - * For conveinence, you can reference our documentation to [learn how to enable a repo](https://go-vela.github.io/docs/usage/enable_repo/). + * For convenience, you can reference our documentation to [learn how to enable a repo](https://go-vela.github.io/docs/usage/enable_repo/). -2. Click the blue drop down arrow on the left side next to the org that contains the repo you want to enable. +2. Click the blue drop-down arrow on the left side next to the org that contains the repo you want to enable. -3. Find the repo you want to enable in the drop down list and click the blue `Enable` button on the right side. - * You should received a `success` message telling you `/ enabled.` +3. Find the repo you want to enable in the drop-down list and click the blue `Enable` button on the right side. + * You should receive a `success` message telling you `/ enabled.` 4. Click the blue `View` button to navigate directly to the repo. - * You should be redirected to http://localhost:8888// + * You should be redirected to http://localhost:8888//

@@ -116,7 +116,7 @@ In order to run a build in Vela, you'll need to add a pipeline to the repo that

1. Create a Vela [pipeline](https://go-vela.github.io/docs/tour/) to define a workflow for Vela to run. - * For convenience, you can reference our documentation to use [one of our example pipelines](https://go-vela.github.io/docs/usage/examples/). + * For convenience, you can reference our documentation to use [one of our example pipelines](https://go-vela.github.io/docs/usage/examples/). 2. Add the pipeline to the repo that was enabled above. @@ -137,8 +137,8 @@ In order to run a build in Vela, you'll need to capture a valid webhook payload 2. Find the [recent delivery](https://developer.github.com/webhooks/testing/#listing-recent-deliveries) for the pipeline that was added to your repo. 3. Create a request locally for http://localhost:8080/webhook and replicate all parts from the recent delivery. - * You should use whatever tool feels most comfortable and natural to you (`curl`, `Postman`, `Insomnia` etc.). - * You should replicate all the request headers and the request body from the recent delivery. + * You should use whatever tool feels most comfortable and natural to you (`curl`, `Postman`, `Insomnia` etc.). + * You should replicate all the request headers and the request body from the recent delivery. 4. Send the request and navigate directly to the repo (http://localhost:8888//) to watch the build run live. @@ -156,19 +156,33 @@ This section covers the different services in the stack when the Vela applicatio The `server` Docker compose service hosts the Vela server and API. -This component is used for processing web requests and managing resources in the database and publishing builds to the FIFO queue. +Known as the brains of the Vela application, this service is responsible for managing the state of application resources. + +This includes managing resources in the system (repositories, users etc.) and storing resource data in the database. + +Additionally, the server responds to event-driven requests (webhooks) which creates new builds to run on a worker. + +For more information, please review [the official documentation](https://go-vela.github.io/docs/administration/server/). ### Worker The `worker` Docker compose service hosts the Vela build daemon. -This component is used for pulling builds from the FIFO queue and executing them based off their configuration. +Known as the brawn of the Vela application, this service is responsible for managing the state of build resources. + +This includes pulling the build, provided by the server, from the queue to be run. + +For more information, please review [the official documentation](https://go-vela.github.io/docs/administration/worker/). ### UI The `ui` Docker compose service hosts the Vela UI. -This component is used for providing a user-friendly interface for triggering actions in the Vela system. +Known as the user interface for the Vela application, often referred to as the Vela UI, this service provides a means for utilizing and interacting with the Vela platform. + +The Vela UI aims to provide users with an easy-to-use toolbox that supplies most of the functionality necessary for managing, investigating, and successfully troubleshooting Vela pipelines. + +For more information, please review [the official documentation](https://go-vela.github.io/docs/administration/ui/). ### Redis diff --git a/docker-compose.yml b/docker-compose.yml index 7d34df72f..2132da2a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: # managing resources in the database and publishing # builds to the FIFO queue. # - # https://go-vela.github.io/docs/concepts/infrastructure/server/ + # https://go-vela.github.io/docs/administration/server/ server: build: context: . @@ -56,23 +56,26 @@ services: # This component is used for pulling builds from the FIFO # queue and executing them based off their configuration. # - # https://go-vela.github.io/docs/concepts/infrastructure/worker/ + # https://go-vela.github.io/docs/administration/worker/ worker: container_name: worker image: target/vela-worker:latest networks: - vela environment: + EXECUTOR_DRIVER: linux + EXECUTOR_LOG_METHOD: 'time-chunks' QUEUE_DRIVER: redis QUEUE_ADDR: 'redis://redis:6379' VELA_BUILD_LIMIT: 1 VELA_BUILD_TIMEOUT: 30m VELA_LOG_LEVEL: trace VELA_RUNTIME_DRIVER: docker + VELA_RUNTIME_PRIVILEGED_IMAGES: 'target/vela-docker' VELA_SERVER_ADDR: 'http://server:8080' VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' WORKER_ADDR: 'http://worker:8080' - WORKER_CHECK_IN: 15m + WORKER_CHECK_IN: 5m restart: always ports: - '8081:8080' @@ -86,7 +89,7 @@ services: # This component is used for providing a user-friendly # interface for triggering actions in the Vela system. # - # https://go-vela.github.io/docs/concepts/infrastructure/ui/ + # https://go-vela.github.io/docs/administration/ui/ ui: container_name: ui image: target/vela-ui:latest From 04b97e29acf8afd23f5bfd265f8f17840e2f4fce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Mar 2022 13:24:34 -0600 Subject: [PATCH 021/298] fix(deps): update golang.org/x/oauth2 commit hash to ee48083 (#601) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b4badce11..b9e0994dd 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.3.0 go.starlark.net v0.0.0-20220223235035-243c74974e97 - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.1 diff --git a/go.sum b/go.sum index a27b0c30f..e4c86a0b1 100644 --- a/go.sum +++ b/go.sum @@ -733,8 +733,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 01cf76c33ab2a5afbb222b949d0d3b051db36388 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Mar 2022 13:28:51 -0600 Subject: [PATCH 022/298] fix(deps): update go.starlark.net commit hash to 5411bad (#600) Co-authored-by: Renovate Bot Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b9e0994dd..7d3acd8fb 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.3.0 - go.starlark.net v0.0.0-20220223235035-243c74974e97 + go.starlark.net v0.0.0-20220302181546-5411bad688d1 golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index e4c86a0b1..bff408ec9 100644 --- a/go.sum +++ b/go.sum @@ -612,8 +612,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220223235035-243c74974e97 h1:ghIB+2LQvihWROIGpcAVPq/ce5O2uMQersgxXiOeTS4= -go.starlark.net v0.0.0-20220223235035-243c74974e97/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220302181546-5411bad688d1 h1:i0Sz4b+qJi5xwOaFZqZ+RNHkIpaKLDofei/Glt+PMNc= +go.starlark.net v0.0.0-20220302181546-5411bad688d1/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From 61358d2df68207f980a7845270193f50e0eb5709 Mon Sep 17 00:00:00 2001 From: Kayla McKay <39921134+kaymckay@users.noreply.github.com> Date: Wed, 9 Mar 2022 14:06:20 -0600 Subject: [PATCH 023/298] chore: Update golangci-linter config and clean repo (#605) * Clean wsl linting * clean wsl -> structcheck * lint goheader & goimports * lint funlen & remove falsepositives * lint errorlint * clean govet & dupl * lint noctx * lint staticcheck: possibly go back and replace deprecated, false pos for now * remove nolintlints * add new golangci file * go mody tidy * lint nilerr * remove false positives * add missing headers * remove changelog code * revert commented changes Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> Co-authored-by: Kelly Merrick --- .chglog/CHANGELOG.tpl.md | 30 ---- .chglog/config.yml | 28 --- .github/workflows/release.yml | 53 ------ .golangci.yml | 164 ++++++++++-------- api/admin/build.go | 1 - api/admin/deployment.go | 2 - api/authenticate.go | 2 - api/build.go | 107 ++++-------- api/build_test.go | 6 + api/deployment.go | 4 +- api/hook.go | 4 - api/log.go | 12 +- api/metrics.go | 11 +- api/pagination.go | 1 - api/pipeline.go | 21 ++- api/repo.go | 13 +- api/scm.go | 3 +- api/secret.go | 20 +-- api/service.go | 7 - api/step.go | 6 +- api/stream.go | 2 - api/user.go | 6 +- api/webhook.go | 61 +++---- cmd/vela-server/main.go | 33 ++-- cmd/vela-server/server.go | 1 - cmd/vela-server/validate.go | 4 - compiler/engine.go | 4 +- compiler/native/compile.go | 4 +- compiler/native/compile_test.go | 12 ++ compiler/native/environment.go | 10 -- compiler/native/environment_test.go | 4 + compiler/native/expand.go | 20 ++- compiler/native/expand_test.go | 1 + compiler/native/native.go | 1 + compiler/native/parse.go | 13 +- compiler/native/parse_test.go | 6 + compiler/native/script_test.go | 2 + compiler/native/substitute.go | 6 +- compiler/native/validate.go | 5 +- compiler/native/validate_test.go | 2 +- compiler/registry/github/github.go | 1 + compiler/registry/github/github_test.go | 1 + compiler/registry/github/parse.go | 3 - compiler/registry/github/template.go | 10 +- compiler/registry/github/template_test.go | 15 ++ compiler/template/native/convert.go | 8 +- compiler/template/native/convert_test.go | 8 + compiler/template/native/render.go | 15 +- compiler/template/native/render_test.go | 4 + compiler/template/starlark/convert.go | 3 + compiler/template/starlark/convert_test.go | 14 ++ compiler/template/starlark/render.go | 36 ++-- compiler/template/starlark/render_test.go | 4 + compiler/template/starlark/starlark.go | 12 +- compiler/template/starlark/starlark_test.go | 9 + database/context_test.go | 2 + database/postgres/build_count_test.go | 5 + database/postgres/build_list.go | 6 - database/postgres/build_list_test.go | 6 + database/postgres/build_test.go | 8 +- database/postgres/driver_test.go | 1 + database/postgres/hook_count_test.go | 1 + database/postgres/hook_list_test.go | 2 + database/postgres/hook_test.go | 6 +- database/postgres/log.go | 4 +- database/postgres/log_test.go | 7 +- database/postgres/ping_test.go | 2 +- database/postgres/postgres.go | 42 +++-- database/postgres/postgres_test.go | 7 +- database/postgres/repo.go | 4 +- database/postgres/repo_count_test.go | 4 + database/postgres/repo_list.go | 2 - database/postgres/repo_list_test.go | 4 + database/postgres/repo_test.go | 5 +- database/postgres/secret.go | 8 +- database/postgres/secret_count.go | 2 +- database/postgres/secret_count_test.go | 4 + database/postgres/secret_list.go | 5 +- database/postgres/secret_list_test.go | 5 + database/postgres/secret_test.go | 7 +- database/postgres/service_count_test.go | 5 +- database/postgres/service_list.go | 2 - database/postgres/service_list_test.go | 2 + database/postgres/service_test.go | 5 +- database/postgres/step_count_test.go | 5 +- database/postgres/step_list_test.go | 2 + database/postgres/step_test.go | 5 +- database/postgres/user.go | 4 +- database/postgres/user_count_test.go | 1 + database/postgres/user_list_test.go | 2 + database/postgres/user_test.go | 5 +- database/postgres/worker_count_test.go | 1 + database/postgres/worker_list_test.go | 1 + database/postgres/worker_test.go | 6 +- database/service.go | 1 - database/setup.go | 4 - database/sqlite/build_count_test.go | 5 + database/sqlite/build_list.go | 7 +- database/sqlite/build_list_test.go | 6 + database/sqlite/build_test.go | 7 + database/sqlite/driver_test.go | 1 + database/sqlite/hook_count_test.go | 1 + database/sqlite/hook_list_test.go | 2 + database/sqlite/hook_test.go | 5 + database/sqlite/log.go | 4 +- database/sqlite/log_test.go | 6 + database/sqlite/ping_test.go | 1 + database/sqlite/repo.go | 4 +- database/sqlite/repo_count_test.go | 4 + database/sqlite/repo_list.go | 2 - database/sqlite/repo_list_test.go | 4 + database/sqlite/repo_test.go | 4 + database/sqlite/secret.go | 8 +- database/sqlite/secret_count.go | 2 +- database/sqlite/secret_count_test.go | 4 + database/sqlite/secret_list.go | 5 +- database/sqlite/secret_list_test.go | 5 + database/sqlite/secret_test.go | 7 + database/sqlite/service_count_test.go | 5 +- database/sqlite/service_list.go | 2 - database/sqlite/service_list_test.go | 2 + database/sqlite/service_test.go | 4 + database/sqlite/sqlite.go | 42 +++-- database/sqlite/sqlite_test.go | 7 +- database/sqlite/step_count_test.go | 5 +- database/sqlite/step_list_test.go | 2 + database/sqlite/step_test.go | 4 + database/sqlite/user.go | 4 +- database/sqlite/user_count_test.go | 1 + database/sqlite/user_list_test.go | 2 + database/sqlite/user_test.go | 5 + database/sqlite/worker_count_test.go | 1 + database/sqlite/worker_list_test.go | 1 + database/sqlite/worker_test.go | 6 + mock/server/hook.go | 1 + mock/server/secret.go | 1 + mock/server/service.go | 1 + mock/server/step.go | 1 + mock/server/user.go | 1 + queue/context.go | 2 +- queue/context_test.go | 6 +- queue/queue_test.go | 1 - queue/redis/driver_test.go | 1 - queue/redis/opts_test.go | 3 - queue/redis/pop.go | 9 +- queue/redis/pop_test.go | 1 - queue/redis/push_test.go | 1 - queue/redis/redis_test.go | 1 - queue/setup_test.go | 1 - random/random.go | 4 + router/middleware/build/build.go | 6 +- router/middleware/build/build_test.go | 1 + router/middleware/database_test.go | 1 + router/middleware/default_build_limit_test.go | 1 + router/middleware/default_timeout_test.go | 1 + router/middleware/executors/executors.go | 8 +- router/middleware/header.go | 7 +- router/middleware/logger.go | 1 + router/middleware/max_build_limit_test.go | 1 + router/middleware/org/org.go | 1 + router/middleware/org/org_test.go | 2 +- router/middleware/perm/perm.go | 11 -- router/middleware/repo/repo.go | 4 +- router/middleware/repo/repo_test.go | 3 + router/middleware/secret.go | 1 + router/middleware/secret_test.go | 1 + router/middleware/secure_cookie_test.go | 2 + router/middleware/service/service.go | 8 +- router/middleware/service/service_test.go | 1 + router/middleware/step/step.go | 8 +- router/middleware/step/step_test.go | 1 + router/middleware/token/token.go | 4 +- router/middleware/token/token_test.go | 10 +- router/middleware/user/user_test.go | 3 + router/middleware/webhook_validation_test.go | 2 + router/middleware/worker/worker.go | 5 +- router/middleware/worker/worker_test.go | 1 + router/middleware/worker_test.go | 1 + scm/flags.go | 1 - scm/github/authentication.go | 7 +- scm/github/authentication_test.go | 1 + scm/github/changeset.go | 4 +- scm/github/deployment.go | 6 +- scm/github/repo.go | 5 +- scm/github/repo_test.go | 1 + scm/github/webhook.go | 13 +- scm/github/webhook_test.go | 35 ++-- secret/context_test.go | 2 + secret/native/create.go | 1 - secret/native/delete.go | 1 - secret/native/delete_test.go | 1 + secret/native/driver_test.go | 1 + secret/native/get_test.go | 1 + secret/native/list.go | 2 - secret/native/native_test.go | 1 + secret/native/opts_test.go | 1 + secret/native/update.go | 1 - secret/native/update_test.go | 1 + secret/secret_test.go | 1 + secret/setup_test.go | 2 + secret/vault/count_test.go | 14 ++ secret/vault/create.go | 1 - secret/vault/create_test.go | 12 ++ secret/vault/delete_test.go | 11 ++ secret/vault/driver_test.go | 1 + secret/vault/get.go | 1 - secret/vault/get_test.go | 10 ++ secret/vault/list_test.go | 14 ++ secret/vault/refresh.go | 7 +- secret/vault/refresh_test.go | 4 + secret/vault/update.go | 3 - secret/vault/update_test.go | 14 ++ secret/vault/vault_test.go | 6 + version/version.go | 4 +- 214 files changed, 857 insertions(+), 687 deletions(-) delete mode 100755 .chglog/CHANGELOG.tpl.md delete mode 100755 .chglog/config.yml delete mode 100644 .github/workflows/release.yml diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md deleted file mode 100755 index 60a67d5bc..000000000 --- a/.chglog/CHANGELOG.tpl.md +++ /dev/null @@ -1,30 +0,0 @@ -{{ range .Versions }} - -## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) - -{{ range .CommitGroups -}} -### {{ .Title }} - -{{ range .Commits -}} -* {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} -{{ end }} -{{ end -}} - -{{- if .RevertCommits -}} -### Reverts - -{{ range .RevertCommits -}} -* {{ .Revert.Header }} -{{ end }} -{{ end -}} - -{{- if .NoteGroups -}} -{{ range .NoteGroups -}} -### {{ .Title }} - -{{ range .Notes }} -{{ .Body }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml deleted file mode 100755 index 1553f6198..000000000 --- a/.chglog/config.yml +++ /dev/null @@ -1,28 +0,0 @@ -style: github -template: CHANGELOG.tpl.md -info: - title: CHANGELOG - repository_url: https://github.com/go-vela/server -options: - commits: - # filters: - # Type: - # - feat - # - fix - # - perf - # - refactor - commit_groups: - # title_maps: - # feat: Features - # fix: Bug Fixes - # perf: Performance Improvements - # refactor: Code Refactoring - header: - pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" - pattern_maps: - - Type - - Scope - - Subject - notes: - keywords: - - BREAKING CHANGE \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index ca89ae115..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,53 +0,0 @@ -# name of the action -name: release - -# trigger on push events with `v*` in tag -# ignore push events with `v*-rc*` in tag -on: - push: - tags: - - 'v*' - - '!v*-rc*' - -# pipeline to execute -jobs: - release: - runs-on: ubuntu-latest - container: - image: golang:1.17 - steps: - - name: clone - uses: actions/checkout@v3 - - - name: tags - run: | - git fetch --tags - - - name: version - id: version - run: | - echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/} - - - name: install - run: | - go get github.com/git-chglog/git-chglog/cmd/git-chglog - go get github.com/github-release/github-release - - - name: changelog - run: | - # https://github.com/git-chglog/git-chglog#git-chglog - $(go env GOPATH)/bin/git-chglog \ - -o $GITHUB_WORKSPACE/CHANGELOG.md \ - ${{ steps.version.outputs.VERSION }} - - - name: release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # https://github.com/github-release/github-release#how-to-use - $(go env GOPATH)/bin/github-release edit \ - --user go-vela \ - --repo server \ - --tag ${{ steps.version.outputs.VERSION }} \ - --name ${{ steps.version.outputs.VERSION }} \ - --description "$(cat $GITHUB_WORKSPACE/CHANGELOG.md)" diff --git a/.golangci.yml b/.golangci.yml index f97da06b6..97b6d15a3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -28,19 +28,16 @@ linters-settings: # https://github.com/ultraware/funlen funlen: - lines: 100 - statements: 50 + # accounting for comments + lines: 160 + statements: 70 - # https://github.com/tommy-muehle/go-mnd - gomnd: - settings: - mnd: - # don't include the "operation" and "assign" - checks: argument,case,condition,return - - # https://github.com/walle/lll - lll: - line-length: 100 + # https://github.com/denis-tingaikin/go-header + goheader: + template: |- + Copyright (c) {{ YEAR }} Target Brands, Inc. All rights reserved. + + Use of this source code is governed by the LICENSE file in this repository. # https://github.com/client9/misspell misspell: @@ -48,10 +45,10 @@ linters-settings: # https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint nolintlint: - allow-leading-space: true # allow non-"machine-readable" format (ie. with leading space) - allow-unused: false # allow nolint directives that don't address a linting issue - require-explanation: true # require an explanation for nolint directives - require-specific: true # require nolint directives to be specific about which linter is being skipped + allow-leading-space: true # allow non-"machine-readable" format (ie. with leading space) + allow-unused: false # allow nolint directives that don't address a linting issue + require-explanation: true # require an explanation for nolint directives + require-specific: true # require nolint directives to be specific about which linter is being skipped # This section provides the configuration for which linters # golangci will execute. Several of them were disabled by @@ -62,57 +59,91 @@ linters: # enable a specific set of linters to run enable: - - bodyclose - - deadcode # enabled by default - - dupl - - errcheck # enabled by default - - funlen - - goconst - - gocyclo - - godot - - gofmt - - goimports - - revive - - gomnd - - goprintffuncname - - gosec - - gosimple # enabled by default - - govet # enabled by default - - ineffassign # enabled by default - - lll - - misspell - - nakedret - - nolintlint - - staticcheck # enabled by default - - structcheck # enabled by default - - stylecheck - - typecheck # enabled by default - - unconvert - - unparam - - unused # enabled by default - - varcheck # enabled by default - - whitespace - + - bidichk # checks for dangerous unicode character sequences + - bodyclose # checks whether HTTP response body is closed successfully + - contextcheck # check the function whether use a non-inherited context + - deadcode # finds unused code + - dupl # code clone detection + - errcheck # checks for unchecked errors + - errorlint # find misuses of errors + - exportloopref # check for exported loop vars + - funlen # detects long functions + - goconst # finds repeated strings that could be replaced by a constant + - gocyclo # computes and checks the cyclomatic complexity of functions + - godot # checks if comments end in a period + - gofmt # checks whether code was gofmt-ed + - goheader # checks is file header matches to pattern + - goimports # fixes imports and formats code in same style as gofmt + - gomoddirectives # manage the use of 'replace', 'retract', and 'excludes' directives in go.mod + - goprintffuncname # checks that printf-like functions are named with f at the end + - gosec # inspects code for security problems + - gosimple # linter that specializes in simplifying a code + - govet # reports suspicious constructs, ex. Printf calls whose arguments don't align with the format string + - ineffassign # detects when assignments to existing variables aren't used + - makezero # finds slice declarations with non-zero initial length + - misspell # finds commonly misspelled English words in comments + - nakedret # finds naked returns in functions greater than a specified function length + - nilerr # finds the code that returns nil even if it checks that the error is not nil + - noctx # noctx finds sending http request without context.Context + - nolintlint # reports ill-formed or insufficient nolint directives + - revive # linter for go + - staticcheck # applies static analysis checks, go vet on steroids + - structcheck # finds unused struct fields + - stylecheck # replacement for golint + - tenv # analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - typecheck # parses and type-checks go code, like the front-end of a go compiler + - unconvert # remove unnecessary type conversions + - unparam # reports unused function parameters + - unused # checks for unused constants, variables, functions and types + - varcheck # finds unused global variables and constants + - whitespace # detects leading and trailing whitespace + - wsl # forces code to use empty lines + # static list of linters we know golangci can run but we've # chosen to leave disabled for now - # - asciicheck - # - depguard - # - dogsled - # - exhaustive - # - gochecknoinits - # - gochecknoglobals - # - gocognit - # - gocritic - # - godox - # - goerr113 - # - interfacer - # - nestif - # - noctx - # - prealloc - # - rowserrcheck - # - scopelint - # - testpackage - # - wsl + # - asciicheck - non-critical + # - cyclop - unused complexity metric + # - depguard - unused + # - dogsled - blanks allowed + # - durationcheck - unused + # - errname - unused + # - exhaustive - unused + # - exhaustivestruct - style preference + # - forbidigo - unused + # - forcetypeassert - unused + # - gci - use goimports + # - gochecknoinits - unused + # - gochecknoglobals - global variables allowed + # - gocognit - unused complexity metric + # - gocritic - style preference + # - godox - to be used in the future + # - goerr113 - to be used in the future + # - golint - archived, replaced with revive + # - gofumpt - use gofmt + # - gomnd - get too many false-positives + # - gomodguard - unused + # - ifshort - use both styles + # - ireturn - allow interfaces to be returned + # - importas - want flexibility with naming + # - lll - not too concerned about line length + # - interfacer - archived + # - nestif - non-critical + # - nilnil - style preference + # - nlreturn - style preference + # - maligned - archived, replaced with govet 'fieldalignment' + # - paralleltest - false-positives + # - prealloc - don't use + # - predeclared - unused + # - promlinter - style preference + # - rowserrcheck - unused + # - scopelint - deprecated - replaced with exportloopref + # - sqlclosecheck - unused + # - tagliatelle - use a mix of variable naming + # - testpackage - don't use this style of testing + # - thelper - false-positives + # - varnamelen - unused + # - wastedassign - duplicate functionality + # - wrapcheck - style preference # This section provides the configuration for how golangci # will report the issues it finds. @@ -126,6 +157,3 @@ issues: - funlen - goconst - gocyclo - - gomnd - - lll - - revive diff --git a/api/admin/build.go b/api/admin/build.go index c61e1995c..e7680d66f 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -92,7 +92,6 @@ func AllBuildsQueue(c *gin.Context) { logrus.Info("Admin: reading running and pending builds") // default timestamp to 24 hours ago if user did not provide it as query parameter - // nolint: gomnd // ignore magic number after := c.DefaultQuery("after", strconv.FormatInt(time.Now().UTC().Add(-24*time.Hour).Unix(), 10)) // send API call to capture pending and running builds diff --git a/api/admin/deployment.go b/api/admin/deployment.go index 8d3f2b367..94fe009a2 100644 --- a/api/admin/deployment.go +++ b/api/admin/deployment.go @@ -27,7 +27,6 @@ import ( // AllDeployments represents the API handler to // captures all deployments stored in the database. func AllDeployments(c *gin.Context) { - // nolint: lll // ignore long line length due to return message c.JSON(http.StatusNotImplemented, "The server does not support the functionality required to fulfill the request.") } @@ -48,6 +47,5 @@ func AllDeployments(c *gin.Context) { // UpdateDeployment represents the API handler to // update any deployment stored in the database. func UpdateDeployment(c *gin.Context) { - // nolint: lll // ignore long line length due to return message c.JSON(http.StatusNotImplemented, "The server does not support the functionality required to fulfill the request.") } diff --git a/api/authenticate.go b/api/authenticate.go index b484a4643..a31903f72 100644 --- a/api/authenticate.go +++ b/api/authenticate.go @@ -64,8 +64,6 @@ import ( // Authenticate represents the API handler to // process a user logging in to Vela from // the API or UI. -// -// nolint: funlen // ignore function length due to comments func Authenticate(c *gin.Context) { var err error diff --git a/api/build.go b/api/build.go index 2cc92c1ea..f70491bd0 100644 --- a/api/build.go +++ b/api/build.go @@ -5,6 +5,7 @@ package api import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -83,10 +84,8 @@ import ( // schema: // "$ref": "#/definitions/Error" -// CreateBuild represents the API handler to -// create a build in the configured backend. -// -// nolint: funlen // ignore function length due to comments +// CreateBuild represents the API handler to create a build in the configured backend. +// nolint: funlen // ignore statement count func CreateBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) @@ -122,7 +121,6 @@ func CreateBuild(c *gin.Context) { (input.GetEvent() == constants.EventPull && !r.GetAllowPull()) || (input.GetEvent() == constants.EventTag && !r.GetAllowTag()) || (input.GetEvent() == constants.EventDeploy && !r.GetAllowDeploy()) { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: %s does not have %s events enabled", r.GetFullName(), input.GetEvent()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -148,7 +146,6 @@ func CreateBuild(c *gin.Context) { // send API call to capture the number of pending or running builds for the repo builds, err := database.FromContext(c).GetRepoBuildCount(r, filters) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: unable to get count of builds for repo %s", r.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -158,7 +155,6 @@ func CreateBuild(c *gin.Context) { // check if the number of pending and running builds exceeds the limit for the repo if builds >= r.GetBuildLimit() { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -204,7 +200,6 @@ func CreateBuild(c *gin.Context) { // send API call to capture list of files changed for the commit files, err = scm.FromContext(c).Changeset(u, r, input.GetCommit()) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -218,7 +213,6 @@ func CreateBuild(c *gin.Context) { // capture number from build number, err := getPRNumberFromBuild(input) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: failed to get pull_request number for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -229,7 +223,6 @@ func CreateBuild(c *gin.Context) { // send API call to capture list of files changed for the pull request files, err = scm.FromContext(c).ChangesetPR(u, r, number) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -241,7 +234,6 @@ func CreateBuild(c *gin.Context) { // send API call to capture the pipeline configuration file config, err := scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to get pipeline configuration for %s/%d: %w", r.GetFullName(), input.GetNumber(), err) util.HandleError(c, http.StatusNotFound, retErr) @@ -258,7 +250,6 @@ func CreateBuild(c *gin.Context) { WithUser(u). Compile(config) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to compile pipeline configuration for %s/%d: %w", r.GetFullName(), input.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -275,11 +266,11 @@ func CreateBuild(c *gin.Context) { // send API call to set the status on the commit err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) if err != nil { - // nolint: lll // ignore long line length due to error message logger.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), input.GetNumber(), err) } c.JSON(http.StatusOK, skip) + return } @@ -299,7 +290,6 @@ func CreateBuild(c *gin.Context) { // send API call to set the status on the commit err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) if err != nil { - // nolint: lll // ignore long line length due to error message logger.Errorf("unable to set commit status for build %s/%d: %v", r.GetFullName(), input.GetNumber(), err) } @@ -316,7 +306,6 @@ func CreateBuild(c *gin.Context) { // skipEmptyBuild checks if the build should be skipped due to it // not containing any steps besides init or clone. -// // nolint: goconst // ignore init and clone constants func skipEmptyBuild(p *pipeline.Build) string { if len(p.Stages) == 1 { @@ -325,7 +314,6 @@ func skipEmptyBuild(p *pipeline.Build) string { } } - // nolint: gomnd // ignore magic number if len(p.Stages) == 2 { if p.Stages[0].Name == "init" && p.Stages[1].Name == "clone" { return "skipping build since only init and clone stages found" @@ -338,7 +326,6 @@ func skipEmptyBuild(p *pipeline.Build) string { } } - // nolint: gomnd // ignore magic number if len(p.Steps) == 2 { if p.Steps[0].Name == "init" && p.Steps[1].Name == "clone" { return "skipping build since only init and clone steps found" @@ -444,8 +431,6 @@ func skipEmptyBuild(p *pipeline.Build) string { // GetBuilds represents the API handler to capture a // list of builds for a repo from the configured backend. -// -// nolint: funlen // ignore function length due to comments func GetBuilds(c *gin.Context) { // variables that will hold the build list, build list filters and total count var ( @@ -525,7 +510,6 @@ func GetBuilds(c *gin.Context) { // capture page query parameter if present page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -536,7 +520,6 @@ func GetBuilds(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -545,16 +528,11 @@ func GetBuilds(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // capture before query parameter if present, default to now - // - // nolint: gomnd, lll // ignore magic number and long line length before, err := strconv.ParseInt(c.DefaultQuery("before", strconv.FormatInt(time.Now().UTC().Unix(), 10)), 10, 64) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert before query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -563,11 +541,8 @@ func GetBuilds(c *gin.Context) { } // capture after query parameter if present, default to 0 - // - // nolint: gomnd // ignore magic number after, err := strconv.ParseInt(c.DefaultQuery("after", "0"), 10, 64) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert after query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -647,8 +622,6 @@ func GetBuilds(c *gin.Context) { // GetOrgBuilds represents the API handler to capture a // list of builds associated with an org from the configured backend. -// -// nolint: funlen // ignore function length due to comments func GetOrgBuilds(c *gin.Context) { // variables that will hold the build list, build list filters and total count var ( @@ -736,8 +709,6 @@ func GetOrgBuilds(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // See if the user is an org admin to bypass individual permission checks @@ -876,10 +847,8 @@ func GetBuild(c *gin.Context) { // schema: // "$ref": "#/definitions/Error" -// RestartBuild represents the API handler to -// restart an existing build in the configured backend. -// -// nolint: funlen // ignore function length due to comments +// RestartBuild represents the API handler to restart an existing build in the configured backend. +// nolint: funlen // ignore statement count func RestartBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) @@ -920,7 +889,6 @@ func RestartBuild(c *gin.Context) { // send API call to capture the number of pending or running builds for the repo builds, err := database.FromContext(c).GetRepoBuildCount(r, filters) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to restart build: unable to get count of builds for repo %s", r.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -930,7 +898,6 @@ func RestartBuild(c *gin.Context) { // check if the number of pending and running builds exceeds the limit for the repo if builds >= r.GetBuildLimit() { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to restart build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -980,7 +947,6 @@ func RestartBuild(c *gin.Context) { // send API call to capture list of files changed for the commit files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to process webhook: failed to get changeset for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -994,7 +960,6 @@ func RestartBuild(c *gin.Context) { // capture number from build number, err := getPRNumberFromBuild(b) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to restart build: failed to get pull_request number for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -1005,7 +970,6 @@ func RestartBuild(c *gin.Context) { // send API call to capture list of files changed for the pull request files, err = scm.FromContext(c).ChangesetPR(u, r, number) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -1053,6 +1017,7 @@ func RestartBuild(c *gin.Context) { } c.JSON(http.StatusOK, skip) + return } @@ -1067,8 +1032,7 @@ func RestartBuild(c *gin.Context) { // send API call to update repo for ensuring counter is incremented err = database.FromContext(c).UpdateRepo(r) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %v", r.GetFullName(), err) + retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) return @@ -1143,7 +1107,6 @@ func RestartBuild(c *gin.Context) { // UpdateBuild represents the API handler to update // a build for a repo in the configured backend. -// nolint: funlen // ignore long function line length func UpdateBuild(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -1324,7 +1287,7 @@ func DeleteBuild(c *gin.Context) { // send API call to remove the build err := database.FromContext(c).DeleteBuild(b.GetID()) if err != nil { - retErr := fmt.Errorf("unable to delete build %s: %v", entry, err) + retErr := fmt.Errorf("unable to delete build %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -1346,8 +1309,6 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { } // just being safe to avoid out of range index errors - // - // nolint:gomnd // magic number of 3 used once if len(parts) < 3 { return 0, fmt.Errorf("invalid ref: %s", b.GetRef()) } @@ -1359,8 +1320,6 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { // planBuild is a helper function to plan the build for // execution. This creates all resources, like steps // and services, for the build in the configured backend. -// -// nolint: lll // ignore long line length due to variable names func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) @@ -1371,7 +1330,7 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r // clean up the objects from the pipeline in the database cleanBuild(database, b, nil, nil) - return fmt.Errorf("unable to create new build for %s: %v", r.GetFullName(), err) + return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) } // send API call to capture the created build @@ -1402,8 +1361,6 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r // without execution. This will kill all resources, // like steps and services, for the build in the // configured backend. -// -// nolint: lll // ignore long line length due to variable names func cleanBuild(database database.Service, b *library.Build, services []*library.Service, steps []*library.Step) { // update fields in build object b.SetError("unable to publish build to queue") @@ -1484,10 +1441,8 @@ func cleanBuild(database database.Service, b *library.Build, services []*library // schema: // "$ref": "#/definitions/Error" -// CancelBuild represents the API handler to -// cancel a running build. -// -// nolint: funlen // ignore function length due to comments +// CancelBuild represents the API handler to cancel a running build. +// nolint: funlen // ignore statement count func CancelBuild(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -1524,27 +1479,25 @@ func CancelBuild(c *gin.Context) { if err != nil { retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) + return } 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 - // - // nolint:whitespace // ignore leading newline to improve readability - if strings.EqualFold(executor.Repo.GetFullName(), r.GetFullName()) && - *executor.GetBuild().Number == b.GetNumber() { - + // 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() { // prepare the request to the worker client := http.DefaultClient client.Timeout = 30 * time.Second // set the API endpoint path we send the request to u := fmt.Sprintf("%s/api/v1/executors/%d/build/cancel", w.GetAddress(), executor.GetID()) - req, err := http.NewRequest("DELETE", u, nil) + + req, err := http.NewRequestWithContext(context.Background(), "DELETE", u, nil) if err != nil { retErr := fmt.Errorf("unable to form a request to %s: %w", u, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -1556,6 +1509,7 @@ func CancelBuild(c *gin.Context) { if err != nil { retErr := fmt.Errorf("unable to connect to %s: %w", u, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } defer resp.Body.Close() @@ -1565,6 +1519,7 @@ func CancelBuild(c *gin.Context) { if err != nil { retErr := fmt.Errorf("unable to read response from %s: %w", u, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -1572,10 +1527,12 @@ func CancelBuild(c *gin.Context) { if err != nil { retErr := fmt.Errorf("unable to parse response from %s: %w", u, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } c.JSON(resp.StatusCode, b) + return } } @@ -1583,10 +1540,12 @@ func CancelBuild(c *gin.Context) { // build has been abandoned // update the status in the build table b.SetStatus(constants.StatusCanceled) + err = database.FromContext(c).UpdateBuild(b) if err != nil { retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) + return } @@ -1594,12 +1553,14 @@ func CancelBuild(c *gin.Context) { steps := []*library.Step{} page := 1 perPage := 100 + for page > 0 { // retrieve build steps (per page) from the database stepsPart, err := database.FromContext(c).GetBuildStepList(b, page, perPage) if err != nil { retErr := fmt.Errorf("unable to retrieve steps for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -1607,8 +1568,6 @@ func CancelBuild(c *gin.Context) { steps = append(steps, stepsPart...) // assume no more pages exist if under 100 results are returned - // - // nolint: gomnd // ignore magic number if len(stepsPart) < 100 { page = 0 } else { @@ -1619,13 +1578,14 @@ func CancelBuild(c *gin.Context) { // iterate over each step for the build // setting anything running or pending to canceled for _, step := range steps { - if step.GetStatus() == constants.StatusRunning || - step.GetStatus() == constants.StatusPending { + if step.GetStatus() == constants.StatusRunning || step.GetStatus() == constants.StatusPending { step.SetStatus(constants.StatusCanceled) + err = database.FromContext(c).UpdateStep(step) if err != nil { retErr := fmt.Errorf("unable to update step %s for build %s: %w", step.GetName(), entry, err) util.HandleError(c, http.StatusNotFound, retErr) + return } } @@ -1634,12 +1594,14 @@ func CancelBuild(c *gin.Context) { // retrieve the services for the build from the service table services := []*library.Service{} page = 1 + for page > 0 { // retrieve build services (per page) from the database servicesPart, err := database.FromContext(c).GetBuildServiceList(b, page, perPage) if err != nil { retErr := fmt.Errorf("unable to retrieve services for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -1647,8 +1609,6 @@ func CancelBuild(c *gin.Context) { services = append(services, servicesPart...) // assume no more pages exist if under 100 results are returned - // - // nolint: gomnd // ignore magic number if len(servicesPart) < 100 { page = 0 } else { @@ -1659,9 +1619,9 @@ func CancelBuild(c *gin.Context) { // iterate over each service for the build // setting anything running or pending to canceled for _, service := range services { - if service.GetStatus() == constants.StatusRunning || - service.GetStatus() == constants.StatusPending { + if service.GetStatus() == constants.StatusRunning || service.GetStatus() == constants.StatusPending { service.SetStatus(constants.StatusCanceled) + err = database.FromContext(c).UpdateService(service) if err != nil { retErr := fmt.Errorf("unable to update service %s for build %s: %w", @@ -1670,6 +1630,7 @@ func CancelBuild(c *gin.Context) { err, ) util.HandleError(c, http.StatusNotFound, retErr) + return } } diff --git a/api/build_test.go b/api/build_test.go index 43253c108..b92802303 100644 --- a/api/build_test.go +++ b/api/build_test.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package api import ( @@ -10,6 +14,7 @@ func Test_skipEmptyBuild(t *testing.T) { type args struct { p *pipeline.Build } + tests := []struct { name string args args @@ -64,6 +69,7 @@ func Test_skipEmptyBuild(t *testing.T) { }, }}}, ""}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := skipEmptyBuild(tt.args.p); got != tt.want { diff --git a/api/deployment.go b/api/deployment.go index 33f43b6f8..fda280d15 100644 --- a/api/deployment.go +++ b/api/deployment.go @@ -195,7 +195,6 @@ func GetDeployments(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -204,8 +203,6 @@ func GetDeployments(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of deployments for the repo @@ -229,6 +226,7 @@ func GetDeployments(c *gin.Context) { } dWithBs := []*library.Deployment{} + for _, deployment := range d { b, err := database.FromContext(c).GetDeploymentBuildList(*deployment.URL) if err != nil { diff --git a/api/hook.go b/api/hook.go index f1b7da600..50efde981 100644 --- a/api/hook.go +++ b/api/hook.go @@ -206,7 +206,6 @@ func GetHooks(c *gin.Context) { // capture page query parameter if present page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -217,7 +216,6 @@ func GetHooks(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -226,8 +224,6 @@ func GetHooks(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of webhooks for the repo diff --git a/api/log.go b/api/log.go index eafc9d0db..4327b296c 100644 --- a/api/log.go +++ b/api/log.go @@ -95,7 +95,6 @@ func GetBuildLogs(c *gin.Context) { c.JSON(http.StatusOK, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services CreateServiceLogs // @@ -206,7 +205,6 @@ func CreateServiceLog(c *gin.Context) { c.JSON(http.StatusCreated, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services GetServiceLogs // @@ -284,7 +282,6 @@ func GetServiceLog(c *gin.Context) { c.JSON(http.StatusOK, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services UpdateServiceLog // @@ -404,7 +401,6 @@ func UpdateServiceLog(c *gin.Context) { c.JSON(http.StatusOK, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services DeleteServiceLogs // @@ -484,7 +480,6 @@ func DeleteServiceLog(c *gin.Context) { c.JSON(http.StatusOK, fmt.Sprintf("logs deleted for service %s", entry)) } -// nolint: lll // ignore long line length due to API path // // swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps CreateStepLog // @@ -595,7 +590,6 @@ func CreateStepLog(c *gin.Context) { c.JSON(http.StatusCreated, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps GetStepLog // @@ -674,7 +668,6 @@ func GetStepLog(c *gin.Context) { c.JSON(http.StatusOK, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps UpdateStepLog // @@ -765,7 +758,7 @@ func UpdateStepLog(c *gin.Context) { err = c.Bind(input) if err != nil { - retErr := fmt.Errorf("unable to decode JSON for step %s: %v", entry, err) + retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -781,7 +774,7 @@ func UpdateStepLog(c *gin.Context) { // send API call to update the log err = database.FromContext(c).UpdateLog(l) if err != nil { - retErr := fmt.Errorf("unable to update logs for step %s: %v", entry, err) + retErr := fmt.Errorf("unable to update logs for step %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -794,7 +787,6 @@ func UpdateStepLog(c *gin.Context) { c.JSON(http.StatusOK, l) } -// nolint: lll // ignore long line length due to API path // // swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps DeleteStepLog // diff --git a/api/metrics.go b/api/metrics.go index 59a5f5f37..4c94cb4c4 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -72,8 +72,6 @@ func CustomMetrics(c *gin.Context) { } // helper function to get the totals of resource types. -// -// nolint: funlen // ignore function length due to comments func recordGauges(c *gin.Context) { // send API call to capture the total number of users u, err := database.FromContext(c).GetUserCount() @@ -173,9 +171,12 @@ func recordGauges(c *gin.Context) { totals.WithLabelValues("build", "status", "error").Set(float64(bErr)) // Add worker metrics - var buildLimit int64 - var activeWorkers int64 - var inactiveWorkers int64 + var ( + buildLimit int64 + activeWorkers int64 + inactiveWorkers int64 + ) + // get the unix time from worker_active_interval ago before := time.Now().UTC().Add(-c.Value("worker_active_interval").(time.Duration)).Unix() for _, worker := range workers { diff --git a/api/pagination.go b/api/pagination.go index e7261d563..b9bb4c2cb 100644 --- a/api/pagination.go +++ b/api/pagination.go @@ -70,7 +70,6 @@ func (p *Pagination) SetHeaderLink(c *gin.Context) { l = append(l, ls) } - // nolint: gomnd // ignore magic number c.Header("X-Total-Count", strconv.FormatInt(p.Total, 10)) c.Header("Link", strings.Join(l, ", ")) } diff --git a/api/pipeline.go b/api/pipeline.go index fdae72790..a6ae3f825 100644 --- a/api/pipeline.go +++ b/api/pipeline.go @@ -93,6 +93,7 @@ func GetPipeline(ctx *gin.Context) { pipeline, _, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } @@ -162,6 +163,7 @@ func GetTemplates(ctx *gin.Context) { pipeline, _, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } @@ -170,6 +172,7 @@ func GetTemplates(ctx *gin.Context) { if err != nil { retErr := fmt.Errorf("unable to set template links for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) + return } @@ -240,11 +243,13 @@ func ExpandPipeline(ctx *gin.Context) { pipeline, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } if err := expandPipeline(ctx, pipeline, comp, false); err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } @@ -313,6 +318,7 @@ func ValidatePipeline(ctx *gin.Context) { pipeline, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } @@ -320,6 +326,7 @@ func ValidatePipeline(ctx *gin.Context) { if ok, _ := strconv.ParseBool(ctx.DefaultQuery("template", "true")); ok { if err := expandPipeline(ctx, pipeline, comp, false); err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } } @@ -328,6 +335,7 @@ func ValidatePipeline(ctx *gin.Context) { if err = comp.Validate(pipeline); err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) + return } @@ -379,7 +387,6 @@ func ValidatePipeline(ctx *gin.Context) { // CompilePipeline represents the API handler to capture, // expand and compile a pipeline configuration. -// func CompilePipeline(ctx *gin.Context) { // capture middleware values o := org.Retrieve(ctx) @@ -398,11 +405,13 @@ func CompilePipeline(ctx *gin.Context) { pipeline, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } if err := expandPipeline(ctx, pipeline, comp, true); err != nil { util.HandleError(ctx, http.StatusBadRequest, err) + return } @@ -410,6 +419,7 @@ func CompilePipeline(ctx *gin.Context) { if err = comp.Validate(pipeline); err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) + return } @@ -445,7 +455,6 @@ func getUnprocessedPipeline(ctx *gin.Context) (*yaml.Build, compiler.Engine, err pipeline, err := comp.Parse(config) if err != nil { - // nolint: lll // ignore long line length due to error message return nil, nil, fmt.Errorf("unable to parse pipeline configuration for %s: %w", repoName(ctx), err) } @@ -454,16 +463,16 @@ func getUnprocessedPipeline(ctx *gin.Context) (*yaml.Build, compiler.Engine, err // getTemplateLinks helper function that retrieves source provider links // for a list of templates and returns a map of library templates. -// -// nolint: lll // ignore long line length due to variable names func getTemplateLinks(ctx *gin.Context, templates yaml.TemplateSlice) (map[string]*library.Template, error) { r := repo.Retrieve(ctx) + u, err := database.FromContext(ctx).GetUser(r.GetUserID()) if err != nil { return nil, err } m := make(map[string]*library.Template) + for _, t := range templates { // convert to library type tmpl := t.ToLibrary() @@ -523,8 +532,6 @@ func writeOutput(ctx *gin.Context, pipeline interface{}) { // expandPipeline uses a given pipeline and compiler to expand stages and steps // in the pipeline along with optionally substituting the environmental variables. -// -// nolint: lll // ignore long line length due to variable names func expandPipeline(ctx *gin.Context, pipeline *yaml.Build, comp compiler.Engine, substituteEnv bool) error { // create map of templates for easy lookup templates := pipeline.Templates.Map() @@ -542,7 +549,6 @@ func expandPipeline(ctx *gin.Context, pipeline *yaml.Build, comp compiler.Engine // inject the substituted environment variables into the stages pipeline.Stages, err = comp.SubstituteStages(pipeline.Stages) if err != nil { - // nolint: lll // ignore long line length due to error message return fmt.Errorf("unable to substitute stages in pipeline configuration for %s: %w", repoName(ctx), err) } } @@ -557,7 +563,6 @@ func expandPipeline(ctx *gin.Context, pipeline *yaml.Build, comp compiler.Engine // inject the substituted environment variables into the steps pipeline.Steps, err = comp.SubstituteSteps(pipeline.Steps) if err != nil { - // nolint: lll // ignore long line length due to error message return fmt.Errorf("unable to substitute steps in pipeline configuration for %s: %w", repoName(ctx), err) } } diff --git a/api/repo.go b/api/repo.go index 6fd5476ad..1e86dc7e7 100644 --- a/api/repo.go +++ b/api/repo.go @@ -174,7 +174,6 @@ func CreateRepo(c *gin.Context) { if input.GetPipelineType() != constants.PipelineTypeYAML && input.GetPipelineType() != constants.PipelineTypeGo && input.GetPipelineType() != constants.PipelineTypeStarlark { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new repo %s: invalid pipeline_type provided %s", r.GetFullName(), input.GetPipelineType()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -355,7 +354,6 @@ func GetRepos(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -364,8 +362,6 @@ func GetRepos(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of repos for the user @@ -482,7 +478,6 @@ func GetOrgRepos(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -491,8 +486,6 @@ func GetOrgRepos(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // See if the user is an org admin to bypass individual permission checks @@ -633,8 +626,7 @@ func GetRepo(c *gin.Context) { // UpdateRepo represents the API handler to update // a repo in the configured backend. -// -// nolint: funlen // ignore function length due to comments and conditionals +// nolint: funlen // ignore line length func UpdateRepo(c *gin.Context) { // capture middleware values o := org.Retrieve(c) @@ -772,6 +764,7 @@ func UpdateRepo(c *gin.Context) { return } + r.SetPipelineType(input.GetPipelineType()) } @@ -892,7 +885,7 @@ func DeleteRepo(c *gin.Context) { // Comment out actual delete until delete mechanism is fleshed out // err = database.FromContext(c).DeleteRepo(r.ID) // if err != nil { - // retErr := fmt.Errorf("Error while deleting repo %s: %v", r.FullName, err) + // retErr := fmt.Errorf("Error while deleting repo %s: %w", r.FullName, err) // util.HandleError(c, http.StatusInternalServerError, retErr) // return // } diff --git a/api/scm.go b/api/scm.go index 69ed13e2c..fe072fc0a 100644 --- a/api/scm.go +++ b/api/scm.go @@ -88,7 +88,6 @@ func SyncRepos(c *gin.Context) { repos := []*library.Repo{} page := 0 // capture all repos belonging to a certain org in database - // nolint: gomnd // ignore magic number for orgRepos := int64(0); orgRepos < t; orgRepos += 100 { r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, 100) if err != nil { @@ -98,7 +97,9 @@ func SyncRepos(c *gin.Context) { return } + repos = append(repos, r...) + page++ } diff --git a/api/secret.go b/api/secret.go index 3f29eedb8..ab293b58c 100644 --- a/api/secret.go +++ b/api/secret.go @@ -23,7 +23,6 @@ import ( "github.com/sirupsen/logrus" ) -// nolint: lll // ignore long line length due to description // // swagger:operation POST /api/v1/secrets/{engine}/{type}/{org}/{name} secrets CreateSecret // @@ -81,8 +80,6 @@ import ( // CreateSecret represents the API handler to // create a secret in the configured backend. -// -// nolint: funlen // ignore funlen linter func CreateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -189,7 +186,6 @@ func CreateSecret(c *gin.Context) { c.JSON(http.StatusOK, s.Sanitize()) } -// nolint: lll // ignore long line length due to description // // swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name} secrets GetSecrets // @@ -261,8 +257,6 @@ func CreateSecret(c *gin.Context) { // GetSecrets represents the API handler to capture // a list of secrets from the configured backend. -// -// nolint: funlen // ignore function length due to comments func GetSecrets(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -275,9 +269,10 @@ func GetSecrets(c *gin.Context) { // get list of user's teams if type is shared secret and team is '*' if t == constants.SecretShared && n == "*" { var err error + teams, err = scm.FromContext(c).ListUsersTeamsForOrg(u, o) if err != nil { - retErr := fmt.Errorf("unable to get users %s teams for org %s: %v", u.GetName(), o, err) + retErr := fmt.Errorf("unable to get users %s teams for org %s: %w", u.GetName(), o, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -316,7 +311,6 @@ func GetSecrets(c *gin.Context) { // capture page query parameter if present page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert page query parameter for %s from %s service: %w", entry, e, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -327,7 +321,6 @@ func GetSecrets(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for %s from %s service: %w", entry, e, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -346,8 +339,6 @@ func GetSecrets(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the list of secrets @@ -383,7 +374,6 @@ func GetSecrets(c *gin.Context) { c.JSON(http.StatusOK, secrets) } -// nolint: lll // ignore long line length due to description // // swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets GetSecret // @@ -494,7 +484,6 @@ func GetSecret(c *gin.Context) { c.JSON(http.StatusOK, secret.Sanitize()) } -// nolint: lll // ignore long line length due to description // // swagger:operation PUT /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets UpdateSecrets // @@ -556,8 +545,6 @@ func GetSecret(c *gin.Context) { // "$ref": "#/definitions/Error" // UpdateSecret updates a secret for the provided secrets service. -// -// nolint: funlen // ignore funlen linter func UpdateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -602,7 +589,7 @@ func UpdateSecret(c *gin.Context) { err := c.Bind(input) if err != nil { - retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %v", entry, e, err) + retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %w", entry, e, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -654,7 +641,6 @@ func UpdateSecret(c *gin.Context) { c.JSON(http.StatusOK, secret.Sanitize()) } -// nolint: lll // ignore long line length due to description // // swagger:operation DELETE /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets DeleteSecret // diff --git a/api/service.go b/api/service.go index 29ece1604..3438036a1 100644 --- a/api/service.go +++ b/api/service.go @@ -236,8 +236,6 @@ func GetServices(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of services for the build @@ -272,7 +270,6 @@ func GetServices(c *gin.Context) { c.JSON(http.StatusOK, s) } -// nolint: lll // ignore long line length due to API path // // swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services GetService // @@ -342,7 +339,6 @@ func GetService(c *gin.Context) { c.JSON(http.StatusOK, s) } -// nolint: lll // ignore long line length due to API path // // swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services UpdateService // @@ -471,7 +467,6 @@ func UpdateService(c *gin.Context) { c.JSON(http.StatusOK, s) } -// nolint: lll // ignore long line length due to API path // // swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services DeleteService // @@ -554,8 +549,6 @@ func DeleteService(c *gin.Context) { // 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. -// -// nolint: lll // ignore long line length due to variable names func planServices(database database.Service, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { // variable to store planned services services := []*library.Service{} diff --git a/api/step.go b/api/step.go index 32c111af5..a62182462 100644 --- a/api/step.go +++ b/api/step.go @@ -233,8 +233,6 @@ func GetSteps(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of steps for the build @@ -407,7 +405,7 @@ func UpdateStep(c *gin.Context) { err := c.Bind(input) if err != nil { - retErr := fmt.Errorf("unable to decode JSON for step %s: %v", entry, err) + retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -552,8 +550,6 @@ func DeleteStep(c *gin.Context) { // 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. -// -// nolint: funlen,lll // ignore function length and long line length func planSteps(database database.Service, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { // variable to store planned steps steps := []*library.Step{} diff --git a/api/stream.go b/api/stream.go index 22cf1e5b7..6ffcc7989 100644 --- a/api/stream.go +++ b/api/stream.go @@ -27,7 +27,6 @@ import ( const logUpdateInterval = 1 * time.Second -// nolint:lll // due to api endpoint parameters // swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/service/{service}/stream stream PostServiceStream // // Stream the logs for a service @@ -182,7 +181,6 @@ func PostServiceStream(c *gin.Context) { c.JSON(http.StatusNoContent, nil) } -// nolint:lll // due to api endpoint parameters // swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/stream stream PostStepStream // // Stream the logs for a step diff --git a/api/user.go b/api/user.go index d9aaba8a0..a08df523d 100644 --- a/api/user.go +++ b/api/user.go @@ -172,8 +172,6 @@ func GetUsers(c *gin.Context) { } // ensure per_page isn't above or below allowed values - // - // nolint: gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the total number of users @@ -447,9 +445,9 @@ func GetUserSourceRepos(c *gin.Context) { // capture source repos from the database backend, grouped by org page := 1 filters := map[string]string{} + for page > 0 { // send API call to capture the list of repos for the org - // nolint: gomnd // ignore magic number dbReposPart, err := database.FromContext(c).GetOrgRepoList(org, filters, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) @@ -463,8 +461,6 @@ func GetUserSourceRepos(c *gin.Context) { dbRepos = append(dbRepos, dbReposPart...) // assume no more pages exist if under 100 results are returned - // - // nolint: gomnd // ignore magic number if len(dbReposPart) < 100 { page = 0 } else { diff --git a/api/webhook.go b/api/webhook.go index d5641e677..882a23331 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -98,7 +98,7 @@ func PostWebhook(c *gin.Context) { // read the request body for duplication _, err := buf.ReadFrom(c.Request.Body) if err != nil { - retErr := fmt.Errorf("unable to read webhook body: %v", err) + retErr := fmt.Errorf("unable to read webhook body: %w", err) util.HandleError(c, http.StatusBadRequest, retErr) return @@ -116,8 +116,9 @@ func PostWebhook(c *gin.Context) { // comment, number, h, r, b webhook, err := scm.FromContext(c).ProcessWebhook(c.Request) if err != nil { - retErr := fmt.Errorf("unable to parse webhook: %v", err) + retErr := fmt.Errorf("unable to parse webhook: %w", err) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -164,8 +165,10 @@ func PostWebhook(c *gin.Context) { util.HandleError(c, http.StatusBadRequest, err) h.SetStatus(constants.StatusFailure) h.SetError(err.Error()) + return } + return } @@ -173,7 +176,7 @@ func PostWebhook(c *gin.Context) { r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) if err != nil { - retErr := fmt.Errorf("%s: failed to get repo %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -189,7 +192,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture the last hook for the repo lastHook, err := database.FromContext(c).GetLastHook(r) if err != nil { - retErr := fmt.Errorf("unable to get last hook for repo %s: %v", r.GetFullName(), err) + retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -208,7 +211,7 @@ func PostWebhook(c *gin.Context) { // send API call to create the webhook err = database.FromContext(c).CreateHook(h) if err != nil { - retErr := fmt.Errorf("unable to create webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err) + retErr := fmt.Errorf("unable to create webhook %s/%d: %w", r.GetFullName(), h.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -224,7 +227,7 @@ func PostWebhook(c *gin.Context) { if c.Value("webhookvalidation").(bool) { err = scm.FromContext(c).VerifyWebhook(dupRequest, r) if err != nil { - retErr := fmt.Errorf("unable to verify webhook: %v", err) + retErr := fmt.Errorf("unable to verify webhook: %w", err) util.HandleError(c, http.StatusUnauthorized, retErr) h.SetStatus(constants.StatusFailure) @@ -251,7 +254,6 @@ func PostWebhook(c *gin.Context) { (b.GetEvent() == constants.EventComment && !r.GetAllowComment()) || (b.GetEvent() == constants.EventTag && !r.GetAllowTag()) || (b.GetEvent() == constants.EventDeploy && !r.GetAllowDeploy()) { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("%s: %s does not have %s events enabled", baseErr, r.GetFullName(), b.GetEvent()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -275,7 +277,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture repo owner u, err := database.FromContext(c).GetUser(r.GetUserID()) if err != nil { - retErr := fmt.Errorf("%s: failed to get owner for %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get owner for %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -303,7 +305,6 @@ func PostWebhook(c *gin.Context) { // check if the number of pending and running builds exceeds the limit for the repo if builds >= r.GetBuildLimit() { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("%s: repo %s has exceeded the concurrent build limit of %d", baseErr, r.GetFullName(), r.GetBuildLimit()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -322,8 +323,7 @@ func PostWebhook(c *gin.Context) { if strings.EqualFold(b.GetEvent(), constants.EventComment) && webhook.PRNumber > 0 { commit, branch, baseref, headref, err := scm.FromContext(c).GetPullRequest(u, r, webhook.PRNumber) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("%s: failed to get pull request info for %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get pull request info for %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -347,7 +347,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture list of files changed for the commit files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) if err != nil { - retErr := fmt.Errorf("%s: failed to get changeset for %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -363,7 +363,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture list of files changed for the pull request files, err = scm.FromContext(c).ChangesetPR(u, r, webhook.PRNumber) if err != nil { - retErr := fmt.Errorf("%s: failed to get changeset for %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -376,8 +376,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture the pipeline configuration file config, err := scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("%s: failed to get pipeline configuration for %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusNotFound, retErr) h.SetStatus(constants.StatusFailure) @@ -402,7 +401,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture repo for the counter r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) if err != nil { - retErr := fmt.Errorf("%s: failed to get repo %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -445,12 +444,12 @@ func PostWebhook(c *gin.Context) { Compile(config) if err != nil { // format the error message with extra information - err = fmt.Errorf("unable to compile pipeline configuration for %s: %v", r.GetFullName(), err) + err = fmt.Errorf("unable to compile pipeline configuration for %s: %w", r.GetFullName(), err) // log the error for traceability logrus.Error(err.Error()) - retErr := fmt.Errorf("%s: %v", baseErr, err) + retErr := fmt.Errorf("%s: %w", baseErr, err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -472,6 +471,7 @@ func PostWebhook(c *gin.Context) { } c.JSON(http.StatusOK, skip) + return } @@ -492,7 +492,7 @@ func PostWebhook(c *gin.Context) { continue } - retErr := fmt.Errorf("%s: %v", baseErr, err) + retErr := fmt.Errorf("%s: %w", baseErr, err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -508,7 +508,7 @@ func PostWebhook(c *gin.Context) { // send API call to update repo for ensuring counter is incremented err = database.FromContext(c).UpdateRepo(r) if err != nil { - retErr := fmt.Errorf("%s: failed to update repo %s: %v", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -520,8 +520,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture the triggered build b, err = database.FromContext(c).GetBuild(b.GetNumber(), r) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("%s: failed to get new build %s/%d: %v", baseErr, r.GetFullName(), b.GetNumber(), err) + retErr := fmt.Errorf("%s: failed to get new build %s/%d: %w", baseErr, r.GetFullName(), b.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -552,8 +551,6 @@ func PostWebhook(c *gin.Context) { // publishToQueue is a helper function that creates // a build item and publishes it to the queue. -// -// nolint: lll // ignore long line length due to variables func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { item := types.ToItem(p, b, r, u) @@ -618,11 +615,12 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { // get the repo from the database that matches the old name dbR, err := database.FromContext(c).GetRepo(r.GetOrg(), previousName) if err != nil { - // nolint: lll // ignore long line for error formatting retErr := fmt.Errorf("%s: failed to get repo %s/%s from database", baseErr, r.GetOrg(), previousName) util.HandleError(c, http.StatusBadRequest, retErr) + h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) + return retErr } @@ -636,38 +634,40 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { // update the repo in the database err = database.FromContext(c).UpdateRepo(dbR) if err != nil { - // nolint: lll // ignore long line for error formatting retErr := fmt.Errorf("%s: failed to update repo %s/%s in database", baseErr, r.GetOrg(), previousName) util.HandleError(c, http.StatusBadRequest, retErr) + h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) + return retErr } // get total number of secrets associated with repository - // nolint: lll // ignore long line due to extensive function arguments + t, err := database.FromContext(c).GetTypeSecretCount(constants.SecretRepo, r.GetOrg(), previousName, []string{}) if err != nil { return fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) } - secrets := []*library.Secret{} + secrets := []*library.Secret{} page := 1 // capture all secrets belonging to certain repo in database - // nolint: gomnd // ignore magic number for repoSecrets := int64(0); repoSecrets < t; repoSecrets += 100 { - // nolint: lll // ignore long line due to extensive function arguments s, err := database.FromContext(c).GetTypeSecretList(constants.SecretRepo, r.GetOrg(), previousName, page, 100, []string{}) if err != nil { return fmt.Errorf("unable to get secret list for repo %s/%s: %w", r.GetOrg(), previousName, err) } + secrets = append(secrets, s...) + page++ } // update secrets to point to the new repository name for _, secret := range secrets { secret.SetRepo(r.GetName()) + err = database.FromContext(c).UpdateSecret(secret) if err != nil { return fmt.Errorf("unable to update secret for repo %s/%s: %w", r.GetOrg(), previousName, err) @@ -675,5 +675,6 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { } c.JSON(http.StatusOK, r) + return nil } diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 31f0b4286..60b89126e 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -23,7 +23,7 @@ import ( _ "github.com/joho/godotenv/autoload" ) -// nolint: funlen // ignore function length due to flags +// nolint: funlen // ignore line length func main() { // capture application version information v := version.New() @@ -41,7 +41,6 @@ func main() { app.Name = "vela-server" app.Action = server app.Version = v.Semantic() - app.Flags = []cli.Flag{ &cli.StringFlag{ EnvVars: []string{"VELA_LOG_LEVEL", "LOG_LEVEL"}, @@ -85,7 +84,7 @@ func main() { &cli.BoolFlag{ EnvVars: []string{"VELA_DISABLE_WEBHOOK_VALIDATION"}, Name: "vela-disable-webhook-validation", - // nolint: lll // ignore long line length due to description + Usage: "determines whether or not webhook validation is disabled. useful for local development.", Value: false, }, @@ -113,9 +112,7 @@ func main() { Usage: "override default build timeout (minutes)", Value: constants.BuildTimeoutDefault, }, - // Security Flags - &cli.DurationFlag{ EnvVars: []string{"VELA_ACCESS_TOKEN_DURATION", "ACCESS_TOKEN_DURATION"}, Name: "access-token-duration", @@ -128,9 +125,7 @@ func main() { Usage: "sets the duration of the refresh token", Value: 8 * time.Hour, }, - // Compiler Flags - &cli.BoolFlag{ EnvVars: []string{"VELA_COMPILER_GITHUB", "COMPILER_GITHUB"}, Name: "github-driver", @@ -146,7 +141,6 @@ func main() { Name: "github-token", Usage: "github token, used by compiler, for pulling registry templates", }, - &cli.StringFlag{ EnvVars: []string{"VELA_MODIFICATION_ADDR", "MODIFICATION_ADDR"}, Name: "modification-addr", @@ -155,24 +149,23 @@ func main() { &cli.StringFlag{ EnvVars: []string{"VELA_MODIFICATION_SECRET", "MODIFICATION_SECRET"}, Name: "modification-secret", - // nolint: lll // ignore long line length due to description + Usage: "modification secret, used by compiler, secret to allow connectivity between compiler and modification endpoint", }, &cli.DurationFlag{ EnvVars: []string{"VELA_MODIFICATION_TIMEOUT", "MODIFICATION_TIMEOUT"}, Name: "modification-timeout", - // nolint: lll // ignore long line length due to description + Usage: "modification timeout, used by compiler, duration that the modification http request will timeout after", Value: 8 * time.Second, }, &cli.IntFlag{ EnvVars: []string{"VELA_MODIFICATION_RETRIES", "MODIFICATION_RETRIES"}, Name: "modification-retries", - // nolint: lll // ignore long line length due to description + Usage: "modification retries, used by compiler, number of http requires that the modification http request will fail after", Value: 5, }, - &cli.DurationFlag{ EnvVars: []string{"VELA_WORKER_ACTIVE_INTERVAL", "WORKER_ACTIVE_INTERVAL"}, Name: "worker-active-interval", @@ -180,28 +173,22 @@ func main() { Value: 5 * time.Minute, }, } - - // Database Flags - + // Add Database Flags app.Flags = append(app.Flags, database.Flags...) - // Queue Flags - + // Add Queue Flags app.Flags = append(app.Flags, queue.Flags...) - // Secret Flags - + // Add Secret Flags app.Flags = append(app.Flags, secret.Flags...) - // Source Flags - + // Add Source Flags app.Flags = append(app.Flags, scm.Flags...) // set logrus to log in JSON format logrus.SetFormatter(&logrus.JSONFormatter{}) - err = app.Run(os.Args) - if err != nil { + if err = app.Run(os.Args); err != nil { logrus.Fatal(err) } } diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 9de6747c6..80d68f313 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -21,7 +21,6 @@ import ( "gopkg.in/tomb.v2" ) -// nolint: funlen // ignore function length func server(c *cli.Context) error { // validate all input err := validate(c) diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index 4098b6a42..70b06d90d 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -31,8 +31,6 @@ func validate(c *cli.Context) error { } // helper function to validate the core CLI configuration. -// -// nolint:lll // ignoring line length check to avoid breaking up error messages func validateCore(c *cli.Context) error { logrus.Trace("Validating core CLI configuration") @@ -84,8 +82,6 @@ func validateCore(c *cli.Context) error { } // helper function to validate the compiler CLI configuration. -// -// nolint:lll // ignoring line length check to avoid breaking up error messages func validateCompiler(c *cli.Context) error { logrus.Trace("Validating compiler CLI configuration") diff --git a/compiler/engine.go b/compiler/engine.go index 86c0c7b37..96b29696e 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -66,11 +66,11 @@ type Engine interface { // ExpandStages defines a function that injects the template // for each templated step in every stage in a yaml configuration. - // nolint: lll // ignore long line length due to return args + ExpandStages(*yaml.Build, map[string]*yaml.Template) (yaml.StageSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) // ExpandSteps defines a function that injects the template // for each templated step in a yaml configuration. - // nolint: lll // ignore long line length due to return args + ExpandSteps(*yaml.Build, map[string]*yaml.Template) (yaml.StepSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) // Init Compiler Interface Functions diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 1ab2ccd8d..c58146315 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -243,15 +243,13 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { // errorHandler ensures the error contains the number of request attempts. func errorHandler(resp *http.Response, err error, attempts int) (*http.Response, error) { if err != nil { - // nolint:lll // detailed error message - err = fmt.Errorf("giving up connecting to modification endpoint after %d attempts due to: %v", attempts, err) + err = fmt.Errorf("giving up connecting to modification endpoint after %d attempts due to: %w", attempts, err) } return resp, err } // modifyConfig sends the configuration to external http endpoint for modification. -// nolint:lll // parameter struct references push line limit func (c *client) modifyConfig(build *yaml.Build, libraryBuild *library.Build, repo *library.Repo) (*yaml.Build, error) { // create request to send to endpoint data, err := yml.Marshal(build) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 3de0c6ae2..5fbfc07a2 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -301,6 +301,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { libraryBuild *library.Build repo *library.Repo } + tests := []struct { name string args args @@ -317,6 +318,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { endpoint: fmt.Sprintf("%s/%s", s.URL, "config/bad"), }, true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { compiler := client{ @@ -367,6 +369,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { libraryBuild *library.Build repo *library.Repo } + tests := []struct { name string args args @@ -383,6 +386,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { endpoint: fmt.Sprintf("%s/%s", s.URL, "config/bad"), }, true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { compiler := client{ @@ -1357,6 +1361,7 @@ func TestNative_Compile_Clone(t *testing.T) { type args struct { file string } + tests := []struct { name string args args @@ -1373,6 +1378,7 @@ func TestNative_Compile_Clone(t *testing.T) { file: "testdata/clone_replace.yml", }, wantReplace, false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // run test @@ -1561,6 +1567,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { file string pipelineType string } + tests := []struct { name string args args @@ -1571,6 +1578,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { {"golang", args{file: "testdata/pipeline_type_go.yml", pipelineType: "go"}, wantGo, false}, {"starlark", args{file: "testdata/pipeline_type.star", pipelineType: "starlark"}, wantStarlark, false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // run test @@ -1617,6 +1625,7 @@ func TestNative_Compile_NoStepsorStages(t *testing.T) { if err != nil { t.Errorf("Creating compiler returned err: %v", err) } + compiler.repo = &library.Repo{Name: &author} compiler.build = &library.Build{Author: &name, Number: &number} @@ -1648,6 +1657,7 @@ func TestNative_Compile_StepsandStages(t *testing.T) { if err != nil { t.Errorf("Creating compiler returned err: %v", err) } + compiler.repo = &library.Repo{Name: &author} compiler.build = &library.Build{Author: &name, Number: &number} @@ -1851,6 +1861,7 @@ func Test_client_modifyConfig(t *testing.T) { libraryBuild *library.Build repo *library.Repo } + tests := []struct { name string args args @@ -1894,6 +1905,7 @@ func Test_client_modifyConfig(t *testing.T) { endpoint: fmt.Sprintf("%s/%s", s.URL, "config/empty"), }, nil, true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { compiler := client{ diff --git a/compiler/native/environment.go b/compiler/native/environment.go index bfe26262a..b6765cf47 100644 --- a/compiler/native/environment.go +++ b/compiler/native/environment.go @@ -18,7 +18,6 @@ import ( // EnvironmentStages injects environment variables // for each stage in a yaml configuration. -// nolint:lll // ignore function line length func (c *client) EnvironmentStages(s yaml.StageSlice, globalEnv raw.StringSliceMap) (yaml.StageSlice, error) { // iterate through all stages for _, stage := range s { @@ -33,7 +32,6 @@ func (c *client) EnvironmentStages(s yaml.StageSlice, globalEnv raw.StringSliceM // EnvironmentStage injects environment variables // for each stage in a yaml configuration. -// nolint:lll // ignore function line length func (c *client) EnvironmentStage(s *yaml.Stage, globalEnv raw.StringSliceMap) (*yaml.Stage, error) { // make empty map of environment variables env := make(map[string]string) @@ -74,7 +72,6 @@ func (c *client) EnvironmentStage(s *yaml.Stage, globalEnv raw.StringSliceMap) ( // EnvironmentSteps injects environment variables // for each step in a stage for the yaml configuration. -// nolint:lll // ignore function line length func (c *client) EnvironmentSteps(s yaml.StepSlice, stageEnv raw.StringSliceMap) (yaml.StepSlice, error) { // iterate through all steps for _, step := range s { @@ -101,7 +98,6 @@ func (c *client) EnvironmentStep(s *yaml.Step, stageEnv raw.StringSliceMap) (*ya // capture all environment variables from the local environment for _, e := range os.Environ() { // split the environment variable on = into a key value pair - // nolint: gomnd // ignore magic number parts := strings.SplitN(e, "=", 2) env[parts[0]] = parts[1] @@ -150,7 +146,6 @@ func (c *client) EnvironmentStep(s *yaml.Step, stageEnv raw.StringSliceMap) (*ya // EnvironmentServices injects environment variables // for each service in a yaml configuration. -// nolint:lll // ignore function line length func (c *client) EnvironmentServices(s yaml.ServiceSlice, globalEnv raw.StringSliceMap) (yaml.ServiceSlice, error) { // iterate through all services for _, service := range s { @@ -186,7 +181,6 @@ func (c *client) EnvironmentServices(s yaml.ServiceSlice, globalEnv raw.StringSl // EnvironmentSecrets injects environment variables // for each secret plugin in a yaml configuration. -// nolint:lll // ignore function line length func (c *client) EnvironmentSecrets(s yaml.SecretSlice, globalEnv raw.StringSliceMap) (yaml.SecretSlice, error) { // iterate through all secrets for _, secret := range s { @@ -205,7 +199,6 @@ func (c *client) EnvironmentSecrets(s yaml.SecretSlice, globalEnv raw.StringSlic // capture all environment variables from the local environment for _, e := range os.Environ() { // split the environment variable on = into a key value pair - // nolint: gomnd // ignore magic number parts := strings.SplitN(e, "=", 2) env[parts[0]] = parts[1] @@ -264,7 +257,6 @@ func (c *client) EnvironmentBuild() map[string]string { // capture all environment variables from the local environment for _, e := range os.Environ() { // split the environment variable on = into a key value pair - // nolint: gomnd // ignore magic number parts := strings.SplitN(e, "=", 2) env[parts[0]] = parts[1] @@ -292,8 +284,6 @@ func appendMap(originalMap, otherMap map[string]string) map[string]string { } // helper function that creates the standard set of environment variables for a pipeline. -// -// nolint: lll // ignore line length due to number of parameters provided func environment(b *library.Build, m *types.Metadata, r *library.Repo, u *library.User) map[string]string { // set default workspace workspace := constants.WorkspaceDefault diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index 8ad6c7ccd..151abaa8a 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -611,6 +611,7 @@ func Test_mergeMap(t *testing.T) { combinedMap map[string]string loopMap map[string]string } + tests := []struct { name string args args @@ -632,6 +633,7 @@ func Test_mergeMap(t *testing.T) { "VELA_TEST": "foo", }}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := appendMap(tt.args.combinedMap, tt.args.loopMap); !reflect.DeepEqual(got, tt.want) { @@ -659,12 +661,14 @@ func Test_client_EnvironmentBuild(t *testing.T) { // deployment deploy := "deployment" target := "production" + type fields struct { build *library.Build metadata *types.Metadata repo *library.Repo user *library.User } + tests := []struct { name string fields fields diff --git a/compiler/native/expand.go b/compiler/native/expand.go index 0b68c5f02..14d6aac35 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -19,8 +19,6 @@ import ( // ExpandStages injects the template for each // templated step in every stage in a yaml configuration. -// -// nolint: lll // ignore long line length due to variable names func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (yaml.StageSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) { // iterate through all stages for _, stage := range s.Stages { @@ -42,12 +40,13 @@ func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (y // ExpandSteps injects the template for each // templated step in a yaml configuration. // -// nolint: lll,funlen,gocyclo // ignore long line length due to variable names +// nolint: funlen,gocyclo // ignore long line length due to variable names func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (yaml.StepSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) { steps := yaml.StepSlice{} secrets := s.Secrets services := s.Services environment := s.Environment + if len(environment) == 0 { environment = make(raw.StringSliceMap) } @@ -100,7 +99,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // parse source from template src, err := c.Github.Parse(tmpl.Source) if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("invalid template source provided for %s: %v", step.Template.Name, err) + return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("invalid template source provided for %s: %w", step.Template.Name, err) } // pull from github without auth when the host isn't provided or is set to github.com @@ -111,6 +110,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya "path": src.Name, "host": src.Host, }).Tracef("Using GitHub client to pull template") + bytes, err = c.Github.Template(nil, src) if err != nil { return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err @@ -134,10 +134,12 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya continue } - var tmplSteps yaml.StepSlice - var tmplSecrets yaml.SecretSlice - var tmplServices yaml.ServiceSlice - var tmplEnvironment raw.StringSliceMap + var ( + tmplSteps yaml.StepSlice + tmplSecrets yaml.SecretSlice + tmplServices yaml.ServiceSlice + tmplEnvironment raw.StringSliceMap + ) // TODO: provide friendlier error messages with file type mismatches switch tmpl.Format { @@ -177,6 +179,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // loop over services within template for _, service := range tmplServices { found := false + for _, serv := range services { if serv.Name == service.Name { found = true @@ -192,6 +195,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // loop over environment within template for key, value := range tmplEnvironment { found := false + for env := range environment { if key == env { found = true diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index 5dae3f99a..714e9cd59 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -160,6 +160,7 @@ func TestNative_ExpandStages(t *testing.T) { if diff := cmp.Diff(services, wantServices); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } + if diff := cmp.Diff(environment, wantEnvironment); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } diff --git a/compiler/native/native.go b/compiler/native/native.go index 5a231dd68..4c0ca1d42 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -46,6 +46,7 @@ type client struct { // nolint: revive // ignore returning unexported client func New(ctx *cli.Context) (*client, error) { logrus.Debug("Creating registry clients from CLI configuration") + c := new(client) if ctx.String("modification-addr") != "" { diff --git a/compiler/native/parse.go b/compiler/native/parse.go index 71b449e59..a84d6631c 100644 --- a/compiler/native/parse.go +++ b/compiler/native/parse.go @@ -53,6 +53,7 @@ func (c *client) Parse(v interface{}) (*types.Build, error) { if err != nil { return nil, err } + p, err = native.RenderBuild(parsedRaw, c.EnvironmentBuild()) if err != nil { return nil, err @@ -63,6 +64,7 @@ func (c *client) Parse(v interface{}) (*types.Build, error) { if err != nil { return nil, err } + p, err = starlark.RenderBuild(parsedRaw, c.EnvironmentBuild()) if err != nil { return nil, err @@ -89,7 +91,6 @@ func (c *client) Parse(v interface{}) (*types.Build, error) { return nil, fmt.Errorf("unable to parse yaml: unrecognized type %T", v) } default: - // nolint:lll // detailed error message return nil, fmt.Errorf("unable to parse config: unrecognized pipeline_type of %s", c.repo.GetPipelineType()) } @@ -103,7 +104,7 @@ func ParseBytes(b []byte) (*types.Build, error) { // unmarshal the bytes into the yaml configuration err := yaml.Unmarshal(b, config) if err != nil { - return nil, fmt.Errorf("unable to unmarshal yaml: %v", err) + return nil, fmt.Errorf("unable to unmarshal yaml: %w", err) } return config, nil @@ -124,7 +125,7 @@ func ParsePath(p string) (*types.Build, error) { // open the file for reading f, err := os.Open(p) if err != nil { - return nil, fmt.Errorf("unable to open yaml file %s: %v", p, err) + return nil, fmt.Errorf("unable to open yaml file %s: %w", p, err) } defer f.Close() @@ -137,7 +138,7 @@ func ParsePathRaw(p string) (string, error) { // open the file for reading f, err := os.Open(p) if err != nil { - return "", fmt.Errorf("unable to open yaml file %s: %v", p, err) + return "", fmt.Errorf("unable to open yaml file %s: %w", p, err) } defer f.Close() @@ -150,7 +151,7 @@ func ParseReader(r io.Reader) (*types.Build, error) { // read all the bytes from the reader b, err := ioutil.ReadAll(r) if err != nil { - return nil, fmt.Errorf("unable to read bytes for yaml: %v", err) + return nil, fmt.Errorf("unable to read bytes for yaml: %w", err) } return ParseBytes(b) @@ -161,7 +162,7 @@ func ParseReaderRaw(r io.Reader) (string, error) { // read all the bytes from the reader b, err := ioutil.ReadAll(r) if err != nil { - return "", fmt.Errorf("unable to read bytes for yaml: %v", err) + return "", fmt.Errorf("unable to read bytes for yaml: %w", err) } return string(b), nil diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index d1dcb3c39..1a04b6e68 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -859,10 +859,12 @@ func Test_client_Parse(t *testing.T) { }, }, } + type args struct { pipelineType string file string } + tests := []struct { name string args args @@ -876,6 +878,7 @@ func Test_client_Parse(t *testing.T) { {"nil", args{pipelineType: "nil", file: "testdata/pipeline_type_default.yml"}, want, false}, {"invalid", args{pipelineType: "foo", file: "testdata/pipeline_type_default.yml"}, nil, true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { content, err := ioutil.ReadFile(tt.args.file) @@ -909,9 +912,11 @@ func Test_client_ParseRaw(t *testing.T) { if err != nil { t.Errorf("Reading file returned err: %v", err) } + type args struct { kind string } + tests := []struct { name string args args @@ -925,6 +930,7 @@ func Test_client_ParseRaw(t *testing.T) { {"path", args{kind: "path"}, string(expected), false}, {"unexpected", args{kind: "foo"}, "", true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var content interface{} diff --git a/compiler/native/script_test.go b/compiler/native/script_test.go index a7f9517a2..bde8adcda 100644 --- a/compiler/native/script_test.go +++ b/compiler/native/script_test.go @@ -120,6 +120,7 @@ func TestNative_ScriptSteps(t *testing.T) { type args struct { s yaml.StepSlice } + tests := []struct { name string args args @@ -234,6 +235,7 @@ func TestNative_ScriptSteps(t *testing.T) { }, }, false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { compiler, err := New(c) diff --git a/compiler/native/substitute.go b/compiler/native/substitute.go index c0a4be6de..35f458b81 100644 --- a/compiler/native/substitute.go +++ b/compiler/native/substitute.go @@ -42,7 +42,7 @@ func (c *client) SubstituteSteps(s types.StepSlice) (types.StepSlice, error) { // marshal step configuration body, err := yaml.Marshal(step) if err != nil { - return nil, fmt.Errorf("unable to marshal configuration: %v", err) + return nil, fmt.Errorf("unable to marshal configuration: %w", err) } // create substitute function @@ -67,13 +67,13 @@ func (c *client) SubstituteSteps(s types.StepSlice) (types.StepSlice, error) { // substitute the environment variables subStep, err := envsubst.Eval(string(body), subFunc) if err != nil { - return nil, fmt.Errorf("unable to substitute environment variables: %v", err) + return nil, fmt.Errorf("unable to substitute environment variables: %w", err) } // unmarshal step configuration err = yaml.Unmarshal([]byte(subStep), step) if err != nil { - return nil, fmt.Errorf("unable to unmarshal configuration: %v", err) + return nil, fmt.Errorf("unable to unmarshal configuration: %w", err) } } diff --git a/compiler/native/validate.go b/compiler/native/validate.go index 482f3e09b..c63e65974 100644 --- a/compiler/native/validate.go +++ b/compiler/native/validate.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Target Brands, Inc. All rights reserved. +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -84,7 +84,6 @@ func validateStages(s yaml.StageSlice) error { return fmt.Errorf("no name provided for step for stage %s", stage.Name) } - // nolint: lll // ignore simplification here if len(step.Image) == 0 && len(step.Template.Name) == 0 { return fmt.Errorf("no image or template provided for step %s for stage %s", step.Name, stage.Name) } @@ -93,7 +92,6 @@ func validateStages(s yaml.StageSlice) error { continue } - // nolint: lll // ignore simplification here if len(step.Commands) == 0 && len(step.Environment) == 0 && len(step.Parameters) == 0 && len(step.Secrets) == 0 && len(step.Template.Name) == 0 && !step.Detach { @@ -121,7 +119,6 @@ func validateSteps(s yaml.StepSlice) error { continue } - // nolint: lll // ignore simplification here if len(step.Commands) == 0 && len(step.Environment) == 0 && len(step.Parameters) == 0 && len(step.Secrets) == 0 && len(step.Template.Name) == 0 && !step.Detach { diff --git a/compiler/native/validate_test.go b/compiler/native/validate_test.go index 6380a2df2..772494aa7 100644 --- a/compiler/native/validate_test.go +++ b/compiler/native/validate_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Target Brands, Inc. All rights reserved. +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index 22815b75a..08c85cff3 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -84,5 +84,6 @@ func (c *client) newClientToken(token string) *github.Client { // ensure the proper URL is set github.BaseURL, _ = url.Parse(c.API) + return github } diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index 11d40700f..6318226af 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -125,6 +125,7 @@ func TestGithub_NewURL(t *testing.T) { if got.URL != test.want.URL { t.Errorf("New URL is %v, want %v", got.URL, test.want.URL) } + if got.API != test.want.API { t.Errorf("New API is %v, want %v", got.API, test.want.API) } diff --git a/compiler/registry/github/parse.go b/compiler/registry/github/parse.go index 7e7a824c2..9c40cf1c8 100644 --- a/compiler/registry/github/parse.go +++ b/compiler/registry/github/parse.go @@ -34,13 +34,10 @@ func (c *client) Parse(path string) (*registry.Source, error) { // this will handle multiple cases for the path: // * // // * //// - // nolint: gomnd // ignore magic number parts := strings.SplitN(u.Path, "/", 3) // ensure org, repo and filename parts exist - // nolint: gomnd // ignore magic number if len(parts) < 3 { - // nolint: lll // ignore long line length due to error message return ®istry.Source{}, fmt.Errorf("invalid template source %s, must contain org/repo/path_to_template", path) } diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index a712ef4c5..3ce99f0b0 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -38,16 +38,18 @@ func (c *client) Template(u *library.User, s *registry.Source) ([]byte, error) { // send API call to capture the templated pipeline configuration // - // nolint: lll // ignore long line length due to variable names + data, _, resp, err := cli.Repositories.GetContents(context.Background(), s.Org, s.Repo, s.Name, opts) if err != nil { if resp != nil && resp.StatusCode != http.StatusNotFound { // return different error message depending on if a branch was provided if len(s.Ref) == 0 { - errString := "unexpected error fetching template %s/%s/%s: %v" + errString := "unexpected error fetching template %s/%s/%s: %w" return nil, fmt.Errorf(errString, s.Org, s.Repo, s.Name, err) } - errString := "unexpected error fetching template %s/%s/%s@%s: %v" + + errString := "unexpected error fetching template %s/%s/%s@%s: %w" + return nil, fmt.Errorf(errString, s.Org, s.Repo, s.Name, s.Ref, err) } @@ -55,6 +57,7 @@ func (c *client) Template(u *library.User, s *registry.Source) ([]byte, error) { if len(s.Ref) == 0 { return nil, fmt.Errorf("no Vela template found at %s/%s/%s", s.Org, s.Repo, s.Name) } + return nil, fmt.Errorf("no Vela template found at %s/%s/%s@%s", s.Org, s.Repo, s.Name, s.Ref) } @@ -72,5 +75,6 @@ func (c *client) Template(u *library.User, s *registry.Source) ([]byte, error) { if len(s.Ref) == 0 { return nil, fmt.Errorf("no Vela template found at %s/%s/%s", s.Org, s.Repo, s.Name) } + return nil, fmt.Errorf("no Vela template found at %s/%s/%s@%s", s.Org, s.Repo, s.Name, s.Ref) } diff --git a/compiler/registry/github/template_test.go b/compiler/registry/github/template_test.go index bffa1d47c..16e9ee696 100644 --- a/compiler/registry/github/template_test.go +++ b/compiler/registry/github/template_test.go @@ -21,6 +21,7 @@ import ( func TestGithub_Template(t *testing.T) { // setup context gin.SetMode(gin.TestMode) + resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) @@ -30,7 +31,9 @@ func TestGithub_Template(t *testing.T) { c.Status(http.StatusOK) c.File("testdata/template.json") }) + s := httptest.NewServer(engine) + defer s.Close() // setup types @@ -75,6 +78,7 @@ func TestGithub_Template(t *testing.T) { func TestGithub_TemplateSourceRef(t *testing.T) { // setup context gin.SetMode(gin.TestMode) + resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) @@ -88,7 +92,9 @@ func TestGithub_TemplateSourceRef(t *testing.T) { c.Status(http.StatusOK) c.File("testdata/template.json") }) + s := httptest.NewServer(engine) + defer s.Close() // setup types @@ -138,6 +144,7 @@ func TestGithub_TemplateSourceRef(t *testing.T) { func TestGithub_TemplateEmptySourceRef(t *testing.T) { // setup context gin.SetMode(gin.TestMode) + resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) @@ -151,7 +158,9 @@ func TestGithub_TemplateEmptySourceRef(t *testing.T) { c.Status(http.StatusOK) c.File("testdata/template.json") }) + s := httptest.NewServer(engine) + defer s.Close() // setup types @@ -200,6 +209,7 @@ func TestGithub_TemplateEmptySourceRef(t *testing.T) { func TestGithub_Template_BadRequest(t *testing.T) { // setup context gin.SetMode(gin.TestMode) + resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) @@ -207,7 +217,9 @@ func TestGithub_Template_BadRequest(t *testing.T) { engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { c.Status(http.StatusBadRequest) }) + s := httptest.NewServer(engine) + defer s.Close() // setup types @@ -247,6 +259,7 @@ func TestGithub_Template_BadRequest(t *testing.T) { func TestGithub_Template_NotFound(t *testing.T) { // setup context gin.SetMode(gin.TestMode) + resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) @@ -254,7 +267,9 @@ func TestGithub_Template_NotFound(t *testing.T) { engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { c.Status(http.StatusNotFound) }) + s := httptest.NewServer(engine) + defer s.Close() // setup types diff --git a/compiler/template/native/convert.go b/compiler/template/native/convert.go index ed83f9ff3..7a773b83b 100644 --- a/compiler/template/native/convert.go +++ b/compiler/template/native/convert.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package native import ( @@ -13,6 +17,7 @@ import ( // within the template. func convertPlatformVars(slice raw.StringSliceMap, name string) raw.StringSliceMap { envs := make(map[string]string) + for key, value := range slice { key = strings.ToLower(key) if strings.HasPrefix(key, "vela_") { @@ -29,7 +34,7 @@ func convertPlatformVars(slice raw.StringSliceMap, name string) raw.StringSliceM // always return a string, even on marshal error (empty string). // // This code is under copyright (full attribution in NOTICE) and is from: -// nolint: lll // ignore long line length due to url + // https://github.com/helm/helm/blob/a499b4b179307c267bdf3ec49b880e3dbd2a5591/pkg/engine/funcs.go#L83 // // This is designed to be called from a template. @@ -39,6 +44,7 @@ func toYAML(v interface{}) string { // Swallow errors inside of a template. return "" } + return strings.TrimSuffix(string(data), "\n") } diff --git a/compiler/template/native/convert_test.go b/compiler/template/native/convert_test.go index 525e6a027..9e350a2fe 100644 --- a/compiler/template/native/convert_test.go +++ b/compiler/template/native/convert_test.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package native import ( @@ -37,6 +41,7 @@ func Test_convertPlatformVars(t *testing.T) { want: raw.StringSliceMap{"build_author": "octocat", "repo_full_name": "go-vela/hello-world", "template_name": "foo"}, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := convertPlatformVars(tt.slice, tt.templateName); !reflect.DeepEqual(got, tt.want) { @@ -50,9 +55,11 @@ func Test_funcHandler_returnPlatformVar(t *testing.T) { type fields struct { envs raw.StringSliceMap } + type args struct { input string } + tests := []struct { name string fields fields @@ -110,6 +117,7 @@ func Test_funcHandler_returnPlatformVar(t *testing.T) { want: "", }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := funcHandler{ diff --git a/compiler/template/native/render.go b/compiler/template/native/render.go index b71cf7afc..265550f02 100644 --- a/compiler/template/native/render.go +++ b/compiler/template/native/render.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package native import ( @@ -15,7 +19,7 @@ import ( ) // RenderStep combines the template with the step in the yaml pipeline. -// nolint: lll // ignore long line length due to return args + func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, types.ServiceSlice, raw.StringSliceMap, error) { buffer := new(bytes.Buffer) config := new(types.Build) @@ -38,22 +42,19 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // https://pkg.go.dev/github.com/Masterminds/sprig?tab=doc#TxtFuncMap t, err := template.New(s.Name).Funcs(sf).Funcs(templateFuncMap).Parse(tmpl) if err != nil { - // nolint: lll // ignore long line length due to return arguments - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to parse template %s: %v", s.Template.Name, err) + return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to parse template %s: %w", s.Template.Name, err) } // apply the variables to the parsed template err = t.Execute(buffer, s.Template.Variables) if err != nil { - // nolint: lll // ignore long line length due to return arguments - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to execute template %s: %v", s.Template.Name, err) + return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to execute template %s: %w", s.Template.Name, err) } // unmarshal the template to the pipeline err = yaml.Unmarshal(buffer.Bytes(), config) if err != nil { - // nolint: lll // ignore long line length due to return args - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %v", err) + return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %w", err) } // ensure all templated steps have template prefix diff --git a/compiler/template/native/render_test.go b/compiler/template/native/render_test.go index 04dd9fef4..3a215d8da 100644 --- a/compiler/template/native/render_test.go +++ b/compiler/template/native/render_test.go @@ -20,6 +20,7 @@ func TestNative_RenderStep(t *testing.T) { velaFile string templateFile string } + tests := []struct { name string args args @@ -39,6 +40,7 @@ func TestNative_RenderStep(t *testing.T) { {"disallowed env func", args{velaFile: "testdata/step/basic/step.yml", templateFile: "testdata/step/disallowed/tmpl_env.yml"}, "", true}, {"disallowed expandenv func", args{velaFile: "testdata/step/basic/step.yml", templateFile: "testdata/step/disallowed/tmpl_expandenv.yml"}, "", true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sFile, err := ioutil.ReadFile(tt.args.velaFile) @@ -101,6 +103,7 @@ func TestNative_RenderBuild(t *testing.T) { type args struct { velaFile string } + tests := []struct { name string args args @@ -111,6 +114,7 @@ func TestNative_RenderBuild(t *testing.T) { {"stages", args{velaFile: "testdata/build/basic_stages/build.yml"}, "testdata/build/basic_stages/want.yml", false}, {"conditional match", args{velaFile: "testdata/build/conditional/build.yml"}, "testdata/build/conditional/want.yml", false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sFile, err := ioutil.ReadFile(tt.args.velaFile) diff --git a/compiler/template/starlark/convert.go b/compiler/template/starlark/convert.go index 9112bf7d5..9ec0d4ee5 100644 --- a/compiler/template/starlark/convert.go +++ b/compiler/template/starlark/convert.go @@ -56,14 +56,17 @@ func convertPlatformVars(slice raw.StringSliceMap, name string) (*starlark.Dict, if err != nil { return nil, err } + err = dict.SetKey(starlark.String("repo"), repo) if err != nil { return nil, err } + err = dict.SetKey(starlark.String("user"), user) if err != nil { return nil, err } + err = dict.SetKey(starlark.String("system"), system) if err != nil { return nil, err diff --git a/compiler/template/starlark/convert_test.go b/compiler/template/starlark/convert_test.go index 77cd577ce..cfaae4acb 100644 --- a/compiler/template/starlark/convert_test.go +++ b/compiler/template/starlark/convert_test.go @@ -20,24 +20,28 @@ func TestStarlark_Render_convertTemplateVars(t *testing.T) { tags = append(tags, starlark.String("1.15")) commands := starlark.NewDict(16) + err := commands.SetKey(starlark.String("test"), starlark.String("go test ./...")) if err != nil { t.Error(err) } strWant := starlark.NewDict(0) + err = strWant.SetKey(starlark.String("pull"), starlark.String("always")) if err != nil { t.Error(err) } arrayWant := starlark.NewDict(0) + err = arrayWant.SetKey(starlark.String("tags"), tags) if err != nil { t.Error(err) } mapWant := starlark.NewDict(0) + err = mapWant.SetKey(starlark.String("commands"), commands) if err != nil { t.Error(err) @@ -81,46 +85,55 @@ func TestStarlark_Render_convertTemplateVars(t *testing.T) { func TestStarlark_Render_velaEnvironmentData(t *testing.T) { // setup types build := starlark.NewDict(1) + err := build.SetKey(starlark.String("author"), starlark.String("octocat")) if err != nil { t.Error(err) } repo := starlark.NewDict(1) + err = repo.SetKey(starlark.String("full_name"), starlark.String("go-vela/hello-world")) if err != nil { t.Error(err) } user := starlark.NewDict(1) + err = user.SetKey(starlark.String("admin"), starlark.String("true")) if err != nil { t.Error(err) } system := starlark.NewDict(2) + err = system.SetKey(starlark.String("template_name"), starlark.String("foo")) if err != nil { t.Error(err) } + err = system.SetKey(starlark.String("workspace"), starlark.String("/vela/src/github.com/go-vela/hello-world")) if err != nil { t.Error(err) } withAllPre := starlark.NewDict(0) + err = withAllPre.SetKey(starlark.String("build"), build) if err != nil { t.Error(err) } + err = withAllPre.SetKey(starlark.String("repo"), repo) if err != nil { t.Error(err) } + err = withAllPre.SetKey(starlark.String("user"), user) if err != nil { t.Error(err) } + err = withAllPre.SetKey(starlark.String("system"), system) if err != nil { t.Error(err) @@ -145,6 +158,7 @@ func TestStarlark_Render_velaEnvironmentData(t *testing.T) { want: withAllPre, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := convertPlatformVars(tt.slice, tt.templateName) diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index 1d4cf1296..0c1b3242c 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -31,8 +31,6 @@ var ( ) // RenderStep combines the template with the step in the yaml pipeline. -// -// nolint: funlen,lll // ignore function length due to comments func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, types.ServiceSlice, raw.StringSliceMap, error) { config := new(types.Build) @@ -40,9 +38,8 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // arbitrarily limiting the steps of the thread to 5000 to help prevent infinite loops // may need to further investigate spawning a separate POSIX process if user input is problematic // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details - // - // nolint: gomnd // ignore magic number thread.SetMaxExecutionSteps(5000) + globals, err := starlark.ExecFile(thread, s.Template.Name, tmpl, nil) if err != nil { return nil, nil, nil, nil, err @@ -51,13 +48,13 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // check the provided template has a main function mainVal, ok := globals["main"] if !ok { - return nil, nil, nil, nil, fmt.Errorf("%s: %s", ErrMissingMainFunc, s.Template.Name) + return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrMissingMainFunc, s.Template.Name) } // check the provided main is a function main, ok := mainVal.(starlark.Callable) if !ok { - return nil, nil, nil, nil, fmt.Errorf("%s: %s", ErrInvalidMainFunc, s.Template.Name) + return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrInvalidMainFunc, s.Template.Name) } // load the user provided vars into a starlark type @@ -75,10 +72,12 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // add the user and platform vars to a context to be used // within the template caller i.e. ctx["vela"] or ctx["vars"] context := starlark.NewDict(0) + err = context.SetKey(starlark.String("vela"), velaVars) if err != nil { return nil, nil, nil, nil, err } + err = context.SetKey(starlark.String("vars"), userVars) if err != nil { return nil, nil, nil, nil, err @@ -99,28 +98,31 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, case *starlark.List: for i := 0; i < v.Len(); i++ { item := v.Index(i) + buf.WriteString("---\n") + err = writeJSON(buf, item) if err != nil { return nil, nil, nil, nil, err } + buf.WriteString("\n") } case *starlark.Dict: buf.WriteString("---\n") + err = writeJSON(buf, v) if err != nil { return nil, nil, nil, nil, err } default: - return nil, nil, nil, nil, fmt.Errorf("%s: %s", ErrInvalidPipelineReturn, mainVal.Type()) + return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrInvalidPipelineReturn, mainVal.Type()) } // unmarshal the template to the pipeline err = yaml.Unmarshal(buf.Bytes(), config) if err != nil { - // nolint: lll // ignore long line length due to return args - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %v", err) + return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %w", err) } // ensure all templated steps have template prefix @@ -139,9 +141,8 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { // arbitrarily limiting the steps of the thread to 5000 to help prevent infinite loops // may need to further investigate spawning a separate POSIX process if user input is problematic // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details - // - // nolint: gomnd // ignore magic number thread.SetMaxExecutionSteps(5000) + globals, err := starlark.ExecFile(thread, "templated-base", b, nil) if err != nil { return nil, err @@ -150,13 +151,13 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { // check the provided template has a main function mainVal, ok := globals["main"] if !ok { - return nil, fmt.Errorf("%s: %s", ErrMissingMainFunc, "templated-base") + return nil, fmt.Errorf("%w: %s", ErrMissingMainFunc, "templated-base") } // check the provided main is a function main, ok := mainVal.(starlark.Callable) if !ok { - return nil, fmt.Errorf("%s: %s", ErrInvalidMainFunc, "templated-base") + return nil, fmt.Errorf("%w: %s", ErrInvalidMainFunc, "templated-base") } // load the platform provided vars into a starlark type @@ -168,6 +169,7 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { // add the user and platform vars to a context to be used // within the template caller i.e. ctx["vela"] or ctx["vars"] context := starlark.NewDict(0) + err = context.SetKey(starlark.String("vela"), velaVars) if err != nil { return nil, err @@ -188,27 +190,31 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { case *starlark.List: for i := 0; i < v.Len(); i++ { item := v.Index(i) + buf.WriteString("---\n") + err = writeJSON(buf, item) if err != nil { return nil, err } + buf.WriteString("\n") } case *starlark.Dict: buf.WriteString("---\n") + err = writeJSON(buf, v) if err != nil { return nil, err } default: - return nil, fmt.Errorf("%s: %s", ErrInvalidPipelineReturn, mainVal.Type()) + return nil, fmt.Errorf("%w: %s", ErrInvalidPipelineReturn, mainVal.Type()) } // unmarshal the template to the pipeline err = yaml.Unmarshal(buf.Bytes(), config) if err != nil { - return nil, fmt.Errorf("unable to unmarshal yaml: %v", err) + return nil, fmt.Errorf("unable to unmarshal yaml: %w", err) } return config, nil diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index aa14caae9..89dedd041 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -19,6 +19,7 @@ func TestStarlark_RenderStep(t *testing.T) { velaFile string starlarkFile string } + tests := []struct { name string args args @@ -31,6 +32,7 @@ func TestStarlark_RenderStep(t *testing.T) { {"platform vars", args{velaFile: "testdata/step/with_vars_plat/step.yml", starlarkFile: "testdata/step/with_vars_plat/template.star"}, "testdata/step/with_vars_plat/want.yml", false}, {"cancel due to complexity", args{velaFile: "testdata/step/cancel/step.yml", starlarkFile: "testdata/step/cancel/template.star"}, "", true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sFile, err := ioutil.ReadFile(tt.args.velaFile) @@ -93,6 +95,7 @@ func TestNative_RenderBuild(t *testing.T) { type args struct { velaFile string } + tests := []struct { name string args args @@ -103,6 +106,7 @@ func TestNative_RenderBuild(t *testing.T) { {"stages", args{velaFile: "testdata/build/basic_stages/build.star"}, "testdata/build/basic_stages/want.yml", false}, {"conditional match", args{velaFile: "testdata/build/conditional/build.star"}, "testdata/build/conditional/want.yml", false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sFile, err := ioutil.ReadFile(tt.args.velaFile) diff --git a/compiler/template/starlark/starlark.go b/compiler/template/starlark/starlark.go index fd987f6dc..7df72e250 100644 --- a/compiler/template/starlark/starlark.go +++ b/compiler/template/starlark/starlark.go @@ -33,7 +33,7 @@ var ( // // https://github.com/wonderix/shalm/blob/899b8f7787883d40619eefcc39bd12f42a09b5e7/pkg/shalm/convert.go#L14-L85 // -// nolint: gocyclo,funlen,lll // ignore above line length and function length due to comments +// nolint: gocyclo // ignore complexity func toStarlark(value interface{}) (starlark.Value, error) { logrus.Tracef("converting %v to starlark type", value) @@ -78,6 +78,7 @@ func toStarlark(value interface{}) (starlark.Value, error) { if err != nil { return nil, err } + a = append(a, val) } @@ -90,11 +91,11 @@ func toStarlark(value interface{}) (starlark.Value, error) { return val, nil case reflect.Map: - // nolint: gomnd // ignore magic number d := starlark.NewDict(16) for _, key := range v.MapKeys() { strct := v.MapIndex(key) + keyValue, err := toStarlark(key.Interface()) if err != nil { return nil, err @@ -137,7 +138,7 @@ func toStarlark(value interface{}) (starlark.Value, error) { } } - return nil, fmt.Errorf("%s: %v", ErrUnableToConvertStarlark, value) + return nil, fmt.Errorf("%w: %v", ErrUnableToConvertStarlark, value) } // writeJSON takes an starlark input and return the valid JSON @@ -151,7 +152,7 @@ func toStarlark(value interface{}) (starlark.Value, error) { // if/when we try to return values it breaks the recursion. Panics were swapped to error // returns from implementation. // -// nolint: gocyclo,funlen // ignore cyclomatic complexity and function length +// nolint: gocyclo // ignore cyclomatic complexity func writeJSON(out *bytes.Buffer, v starlark.Value) error { logrus.Tracef("converting %v to JSON", v) @@ -268,7 +269,7 @@ func writeJSON(out *bytes.Buffer, v starlark.Value) error { logrus.Error(err) } default: - return fmt.Errorf("%s: %v", ErrUnableToConvertJSON, v) + return fmt.Errorf("%w: %v", ErrUnableToConvertJSON, v) } return nil @@ -286,5 +287,6 @@ func goQuoteIsSafe(s string) bool { return false } } + return true } diff --git a/compiler/template/starlark/starlark_test.go b/compiler/template/starlark/starlark_test.go index 378da6a2f..e3aa65626 100644 --- a/compiler/template/starlark/starlark_test.go +++ b/compiler/template/starlark/starlark_test.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package starlark import ( @@ -9,16 +13,20 @@ import ( func TestStarlark_toStarlark(t *testing.T) { dict := starlark.NewDict(16) + err := dict.SetKey(starlark.String("foo"), starlark.String("bar")) if err != nil { t.Error(err) } + a := make([]starlark.Value, 0) a = append(a, starlark.Value(starlark.String("foo"))) a = append(a, starlark.Value(starlark.String("bar"))) + type args struct { value interface{} } + tests := []struct { name string args args @@ -42,6 +50,7 @@ func TestStarlark_toStarlark(t *testing.T) { {"nil", args{value: nil}, starlark.None, false}, {"map", args{value: map[string]string{"foo": "bar"}}, dict, false}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := toStarlark(tt.args.value) diff --git a/database/context_test.go b/database/context_test.go index 4c997ef04..382567a43 100644 --- a/database/context_test.go +++ b/database/context_test.go @@ -14,6 +14,7 @@ import ( func TestDatabase_FromContext(t *testing.T) { // setup types want, _ := sqlite.NewTest() + defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() // setup context @@ -73,6 +74,7 @@ func TestDatabase_FromContext_Empty(t *testing.T) { func TestDatabase_ToContext(t *testing.T) { // setup types want, _ := sqlite.NewTest() + defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/database/postgres/build_count_test.go b/database/postgres/build_count_test.go index ba5a795ca..0c4522798 100644 --- a/database/postgres/build_count_test.go +++ b/database/postgres/build_count_test.go @@ -34,6 +34,7 @@ func TestPostgres_Client_GetBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -99,6 +100,7 @@ func TestPostgres_Client_GetBuildCountByStatus(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -164,6 +166,7 @@ func TestPostgres_Client_GetOrgBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -224,6 +227,7 @@ func TestPostgres_Client_GetOrgBuildCountByEvent(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -296,6 +300,7 @@ func TestPostgres_Client_GetRepoBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock diff --git a/database/postgres/build_list.go b/database/postgres/build_list.go index 670c6b7b4..76fe1dce4 100644 --- a/database/postgres/build_list.go +++ b/database/postgres/build_list.go @@ -53,8 +53,6 @@ func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, er filters["source"] = deployment } // send query to the database and store result in variable - // - // nolint: gomnd // ignore magic number err := c.Postgres. Table(constants.TableBuild). Select("*"). @@ -78,8 +76,6 @@ func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, er } // GetOrgBuildList gets a list of all builds by org name and allows filters from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": org, @@ -129,8 +125,6 @@ func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, pag } // GetRepoBuildList gets a list of all builds by repo ID from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/postgres/build_list_test.go b/database/postgres/build_list_test.go index 031c9a110..c0db1066d 100644 --- a/database/postgres/build_list_test.go +++ b/database/postgres/build_list_test.go @@ -36,6 +36,7 @@ func TestPostgres_Client_GetBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -106,6 +107,7 @@ func TestPostgres_Client_GetDeploymentBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -169,6 +171,7 @@ func TestPostgres_Client_GetOrgBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -240,6 +243,7 @@ func TestPostgres_Client_GetOrgBuildList_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -312,6 +316,7 @@ func TestPostgres_Client_GetOrgBuildListByEvent(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -396,6 +401,7 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock diff --git a/database/postgres/build_test.go b/database/postgres/build_test.go index ea15b41d8..2b6a53c60 100644 --- a/database/postgres/build_test.go +++ b/database/postgres/build_test.go @@ -38,6 +38,7 @@ func TestPostgres_Client_GetBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -114,6 +115,7 @@ func TestPostgres_Client_GetLastBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -190,6 +192,7 @@ func TestPostgres_Client_GetLastBuildByBranch(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -263,6 +266,7 @@ func TestPostgres_Client_GetPendingAndRunningBuilds(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -337,6 +341,7 @@ func TestPostgres_Client_CreateBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -395,6 +400,7 @@ func TestPostgres_Client_UpdateBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -431,12 +437,12 @@ func TestPostgres_Client_UpdateBuild(t *testing.T) { func TestPostgres_Client_DeleteBuild(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/driver_test.go b/database/postgres/driver_test.go index de49bc671..e54d0b0f5 100644 --- a/database/postgres/driver_test.go +++ b/database/postgres/driver_test.go @@ -20,6 +20,7 @@ func TestPostgres_Client_Driver(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // run test diff --git a/database/postgres/hook_count_test.go b/database/postgres/hook_count_test.go index c86f29446..77943483e 100644 --- a/database/postgres/hook_count_test.go +++ b/database/postgres/hook_count_test.go @@ -43,6 +43,7 @@ func TestPostgres_Client_GetRepoHookCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/hook_list_test.go b/database/postgres/hook_list_test.go index dbc1524fe..c8f4129dc 100644 --- a/database/postgres/hook_list_test.go +++ b/database/postgres/hook_list_test.go @@ -37,6 +37,7 @@ func TestPostgres_Client_GetHookList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -114,6 +115,7 @@ func TestPostgres_Client_GetRepoHookList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/hook_test.go b/database/postgres/hook_test.go index 8d94bd0a2..113cbb468 100644 --- a/database/postgres/hook_test.go +++ b/database/postgres/hook_test.go @@ -37,6 +37,7 @@ func TestPostgres_Client_GetHook(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -112,6 +113,7 @@ func TestPostgres_Client_GetLastHook(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -180,6 +182,7 @@ func TestPostgres_Client_CreateHook(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -231,6 +234,7 @@ func TestPostgres_Client_UpdateHook(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -267,12 +271,12 @@ func TestPostgres_Client_UpdateHook(t *testing.T) { func TestPostgres_Client_DeleteHook(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/log.go b/database/postgres/log.go index 7ab708ced..840f5f154 100644 --- a/database/postgres/log.go +++ b/database/postgres/log.go @@ -158,7 +158,7 @@ func (c *client) CreateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress err = log.Compress(c.config.CompressionLevel) if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %v", l.GetStepID(), err) + return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) } // send query to the database @@ -192,7 +192,7 @@ func (c *client) UpdateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress err = log.Compress(c.config.CompressionLevel) if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %v", l.GetStepID(), err) + return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) } // send query to the database diff --git a/database/postgres/log_test.go b/database/postgres/log_test.go index 1f4551378..7173cecbf 100644 --- a/database/postgres/log_test.go +++ b/database/postgres/log_test.go @@ -37,6 +37,7 @@ func TestPostgres_Client_GetBuildLogs(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -99,6 +100,7 @@ func TestPostgres_Client_GetStepLog(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -167,6 +169,7 @@ func TestPostgres_Client_GetServiceLog(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -235,6 +238,7 @@ func TestPostgres_Client_CreateLog(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -286,6 +290,7 @@ func TestPostgres_Client_UpdateLog(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -322,12 +327,12 @@ func TestPostgres_Client_UpdateLog(t *testing.T) { func TestPostgres_Client_DeleteLog(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/ping_test.go b/database/postgres/ping_test.go index 9853ecd90..563f41016 100644 --- a/database/postgres/ping_test.go +++ b/database/postgres/ping_test.go @@ -10,12 +10,12 @@ import ( func TestPostgres_Client_Ping(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the ping diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index c0efe59b4..afa221c58 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -206,55 +206,55 @@ func createTables(c *client) error { // create the builds table err := c.Postgres.Exec(ddl.CreateBuildTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } // create the hooks table err = c.Postgres.Exec(ddl.CreateHookTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableHook, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableHook, err) } // create the logs table err = c.Postgres.Exec(ddl.CreateLogTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableLog, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) } // create the repos table err = c.Postgres.Exec(ddl.CreateRepoTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableRepo, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) } // create the secrets table err = c.Postgres.Exec(ddl.CreateSecretTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableSecret, err) } // create the services table err = c.Postgres.Exec(ddl.CreateServiceTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableService, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) } // create the steps table err = c.Postgres.Exec(ddl.CreateStepTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableStep, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } // create the users table err = c.Postgres.Exec(ddl.CreateUserTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableUser, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableUser, err) } // create the workers table err = c.Postgres.Exec(ddl.CreateWorkerTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableWorker, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableWorker, err) } return nil @@ -262,75 +262,73 @@ func createTables(c *client) error { // createIndexes is a helper function to setup // the database with the necessary indexes. -// -// nolint: lll // ignore long line length due to error messages func createIndexes(c *client) error { c.Logger.Trace("creating data indexes in the postgres database") // create the builds_repo_id index for the builds table err := c.Postgres.Exec(ddl.CreateBuildRepoIDIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_repo_id index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_repo_id index for the %s table: %w", constants.TableBuild, err) } // create the builds_status index for the builds table err = c.Postgres.Exec(ddl.CreateBuildStatusIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_status index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_status index for the %s table: %w", constants.TableBuild, err) } // create the builds_created index for the builds table err = c.Postgres.Exec(ddl.CreateBuildCreatedIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_created index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) } // create the hooks_repo_id index for the hooks table err = c.Postgres.Exec(ddl.CreateHookRepoIDIndex).Error if err != nil { - return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %v", constants.TableHook, err) + return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %w", constants.TableHook, err) } // create the logs_build_id index for the logs table err = c.Postgres.Exec(ddl.CreateLogBuildIDIndex).Error if err != nil { - return fmt.Errorf("unable to create logs_build_id index for the %s table: %v", constants.TableLog, err) + return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) } // create the repos_org_name index for the repos table err = c.Postgres.Exec(ddl.CreateRepoOrgNameIndex).Error if err != nil { - return fmt.Errorf("unable to create repos_org_name index for the %s table: %v", constants.TableRepo, err) + return fmt.Errorf("unable to create repos_org_name index for the %s table: %w", constants.TableRepo, err) } // create the secrets_type_org_repo index for the secrets table err = c.Postgres.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %w", constants.TableSecret, err) } // create the secrets_type_org_team index for the secrets table err = c.Postgres.Exec(ddl.CreateSecretTypeOrgTeam).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %w", constants.TableSecret, err) } // create the secrets_type_org index for the secrets table err = c.Postgres.Exec(ddl.CreateSecretTypeOrg).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } // create the users_refresh index for the users table err = c.Postgres.Exec(ddl.CreateUserRefreshIndex).Error if err != nil { - return fmt.Errorf("unable to create users_refresh index for the %s table: %v", constants.TableUser, err) + return fmt.Errorf("unable to create users_refresh index for the %s table: %w", constants.TableUser, err) } // create the workers_hostname_address index for the workers table err = c.Postgres.Exec(ddl.CreateWorkerHostnameAddressIndex).Error if err != nil { - return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %v", constants.TableWorker, err) + return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %w", constants.TableWorker, err) } return nil diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 15859fd3a..2c0fbc9e5 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -60,12 +60,12 @@ func TestPostgres_New(t *testing.T) { func TestPostgres_setupDatabase(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the ping @@ -100,6 +100,7 @@ func TestPostgres_setupDatabase(t *testing.T) { if err != nil { t.Errorf("unable to create new skip postgres test database: %v", err) } + defer func() { _sql, _ := _skipDatabase.Postgres.DB(); _sql.Close() }() err = WithSkipCreation(true)(_skipDatabase) @@ -144,12 +145,12 @@ func TestPostgres_setupDatabase(t *testing.T) { func TestPostgres_createTables(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the table queries @@ -191,12 +192,12 @@ func TestPostgres_createTables(t *testing.T) { func TestPostgres_createIndexes(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the index queries diff --git a/database/postgres/repo.go b/database/postgres/repo.go index 8085c5a45..409a2b7ef 100644 --- a/database/postgres/repo.go +++ b/database/postgres/repo.go @@ -80,7 +80,7 @@ func (c *client) CreateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %v", r.GetFullName(), err) + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database @@ -112,7 +112,7 @@ func (c *client) UpdateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %v", r.GetFullName(), err) + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database diff --git a/database/postgres/repo_count_test.go b/database/postgres/repo_count_test.go index f5a03f7f1..4213f36e1 100644 --- a/database/postgres/repo_count_test.go +++ b/database/postgres/repo_count_test.go @@ -41,6 +41,7 @@ func TestPostgres_Client_GetRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -117,6 +118,7 @@ func TestPostgres_Client_GetUserRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -188,6 +190,7 @@ func TestPostgres_Client_GetOrgRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -254,6 +257,7 @@ func TestPostgres_Client_GetOrgRepoCount_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock diff --git a/database/postgres/repo_list.go b/database/postgres/repo_list.go index 773d62666..52887d2e0 100644 --- a/database/postgres/repo_list.go +++ b/database/postgres/repo_list.go @@ -56,8 +56,6 @@ func (c *client) GetRepoList() ([]*library.Repo, error) { } // GetOrgRepoList gets a list of all repos by org from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int) ([]*library.Repo, error) { c.Logger.WithFields(logrus.Fields{ "org": org, diff --git a/database/postgres/repo_list_test.go b/database/postgres/repo_list_test.go index 78caad661..af1a74fd3 100644 --- a/database/postgres/repo_list_test.go +++ b/database/postgres/repo_list_test.go @@ -45,6 +45,7 @@ func TestPostgres_Client_GetRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -123,6 +124,7 @@ func TestPostgres_Client_GetOrgRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -196,6 +198,7 @@ func TestPostgres_Client_GetOrgRepoList_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -274,6 +277,7 @@ func TestPostgres_Client_GetUserRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/repo_test.go b/database/postgres/repo_test.go index 17f4cd63e..b95d3ecc3 100644 --- a/database/postgres/repo_test.go +++ b/database/postgres/repo_test.go @@ -34,6 +34,7 @@ func TestPostgres_Client_GetRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -106,6 +107,7 @@ func TestPostgres_Client_CreateRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -161,6 +163,7 @@ func TestPostgres_Client_UpdateRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -197,12 +200,12 @@ func TestPostgres_Client_UpdateRepo(t *testing.T) { func TestPostgres_Client_DeleteRepo(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/secret.go b/database/postgres/secret.go index 9c5b2a577..0d7433c8f 100644 --- a/database/postgres/secret.go +++ b/database/postgres/secret.go @@ -40,7 +40,6 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("getting %s secret %s for %s/%s from the database", t, secretName, o, n) var err error @@ -87,6 +86,7 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) err = result.Error } + if err != nil { return nil, err } @@ -132,7 +132,6 @@ func (c *client) CreateSecret(s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("creating %s secret %s in the database", s.GetType(), s.GetName()) // cast to database type @@ -149,7 +148,7 @@ func (c *client) CreateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt err = secret.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %v", s.GetName(), err) + return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) } // send query to the database @@ -181,7 +180,6 @@ func (c *client) UpdateSecret(s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("updating %s secret %s in the database", s.GetType(), s.GetName()) // cast to database type @@ -198,7 +196,7 @@ func (c *client) UpdateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt err = secret.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %v", s.GetName(), err) + return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) } // send query to the database diff --git a/database/postgres/secret_count.go b/database/postgres/secret_count.go index 162ee17a5..3a5008d85 100644 --- a/database/postgres/secret_count.go +++ b/database/postgres/secret_count.go @@ -33,7 +33,6 @@ func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, erro } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("getting count of %s secrets for %s/%s from the database", t, o, n) var err error @@ -60,6 +59,7 @@ func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, erro for _, t := range teams { lowerTeams = append(lowerTeams, strings.ToLower(t)) } + err = c.Postgres. Table(constants.TableSecret). Select("count(*)"). diff --git a/database/postgres/secret_count_test.go b/database/postgres/secret_count_test.go index f5f465d5a..d75a4f5e1 100644 --- a/database/postgres/secret_count_test.go +++ b/database/postgres/secret_count_test.go @@ -38,6 +38,7 @@ func TestPostgres_Client_GetTypeSecretCount_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -107,6 +108,7 @@ func TestPostgres_Client_GetTypeSecretCount_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -176,6 +178,7 @@ func TestPostgres_Client_GetTypeSecretCount_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -245,6 +248,7 @@ func TestPostgres_Client_GetTypeSecretCount_Shared_Wildcard(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/secret_list.go b/database/postgres/secret_list.go index bdc26c041..6ae3dfb2b 100644 --- a/database/postgres/secret_list.go +++ b/database/postgres/secret_list.go @@ -60,8 +60,6 @@ func (c *client) GetSecretList() ([]*library.Secret, error) { // GetTypeSecretList gets a list of secrets by type, // owner, and name (repo or team) from the database. -// -// nolint: lll // ignore long line length func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []string) ([]*library.Secret, error) { // create log fields from secret metadata fields := logrus.Fields{ @@ -80,7 +78,6 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("listing %s secrets for %s/%s from the database", t, o, n) var err error @@ -108,6 +105,7 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st for _, t := range teams { lowerTeams = append(lowerTeams, strings.ToLower(t)) } + err = c.Postgres. Table(constants.TableSecret). Where("type = 'shared' AND org = ?", o). @@ -123,6 +121,7 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st Scan(s).Error } } + if err != nil { return nil, err } diff --git a/database/postgres/secret_list_test.go b/database/postgres/secret_list_test.go index 12b4b4c34..bbaf3dc5f 100644 --- a/database/postgres/secret_list_test.go +++ b/database/postgres/secret_list_test.go @@ -47,6 +47,7 @@ func TestPostgres_Client_GetSecretList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -127,6 +128,7 @@ func TestPostgres_Client_GetTypeSecretList_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -207,6 +209,7 @@ func TestPostgres_Client_GetTypeSecretList_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -287,6 +290,7 @@ func TestPostgres_Client_GetTypeSecretList_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -367,6 +371,7 @@ func TestPostgres_Client_GetTypeSecretList_Shared_Wildcard(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock diff --git a/database/postgres/secret_test.go b/database/postgres/secret_test.go index 9ea9c7c19..6b513af45 100644 --- a/database/postgres/secret_test.go +++ b/database/postgres/secret_test.go @@ -36,6 +36,7 @@ func TestPostgres_Client_GetSecret_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -109,6 +110,7 @@ func TestPostgres_Client_GetSecret_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -182,6 +184,7 @@ func TestPostgres_Client_GetSecret_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -255,6 +258,7 @@ func TestPostgres_Client_CreateSecret(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -311,6 +315,7 @@ func TestPostgres_Client_UpdateSecret(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -347,12 +352,12 @@ func TestPostgres_Client_UpdateSecret(t *testing.T) { func TestPostgres_Client_DeleteSecret(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/service_count_test.go b/database/postgres/service_count_test.go index 513b1ac8d..52226e296 100644 --- a/database/postgres/service_count_test.go +++ b/database/postgres/service_count_test.go @@ -27,6 +27,7 @@ func TestPostgres_Client_GetBuildServiceCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -75,12 +76,12 @@ func TestPostgres_Client_GetBuildServiceCount(t *testing.T) { func TestPostgres_Client_GetServiceImageCount(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -129,12 +130,12 @@ func TestPostgres_Client_GetServiceImageCount(t *testing.T) { func TestPostgres_Client_GetServiceStatusCount(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/service_list.go b/database/postgres/service_list.go index 04b3fc949..b26536d56 100644 --- a/database/postgres/service_list.go +++ b/database/postgres/service_list.go @@ -40,8 +40,6 @@ func (c *client) GetServiceList() ([]*library.Service, error) { } // GetBuildServiceList gets a list of services by build ID from the database. -// -// nolint: lll // ignore long line length due to parameters func (c *client) GetBuildServiceList(b *library.Build, page, perPage int) ([]*library.Service, error) { c.Logger.WithFields(logrus.Fields{ "build": b.GetNumber(), diff --git a/database/postgres/service_list_test.go b/database/postgres/service_list_test.go index 8787831f9..40c267d27 100644 --- a/database/postgres/service_list_test.go +++ b/database/postgres/service_list_test.go @@ -39,6 +39,7 @@ func TestPostgres_Client_GetServiceList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -116,6 +117,7 @@ func TestPostgres_Client_GetBuildServiceList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/service_test.go b/database/postgres/service_test.go index 7689f7ead..5c88561e5 100644 --- a/database/postgres/service_test.go +++ b/database/postgres/service_test.go @@ -36,6 +36,7 @@ func TestPostgres_Client_GetService(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -105,6 +106,7 @@ func TestPostgres_Client_CreateService(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -157,6 +159,7 @@ func TestPostgres_Client_UpdateService(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -193,12 +196,12 @@ func TestPostgres_Client_UpdateService(t *testing.T) { func TestPostgres_Client_DeleteService(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/step_count_test.go b/database/postgres/step_count_test.go index 227ba5021..e065ade38 100644 --- a/database/postgres/step_count_test.go +++ b/database/postgres/step_count_test.go @@ -27,6 +27,7 @@ func TestPostgres_Client_GetBuildStepCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -75,12 +76,12 @@ func TestPostgres_Client_GetBuildStepCount(t *testing.T) { func TestPostgres_Client_GetStepImageCount(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -129,12 +130,12 @@ func TestPostgres_Client_GetStepImageCount(t *testing.T) { func TestPostgres_Client_GetStepStatusCount(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/step_list_test.go b/database/postgres/step_list_test.go index 2c8ce586f..f5985690f 100644 --- a/database/postgres/step_list_test.go +++ b/database/postgres/step_list_test.go @@ -39,6 +39,7 @@ func TestPostgres_Client_GetStepList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -116,6 +117,7 @@ func TestPostgres_Client_GetBuildStepList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/step_test.go b/database/postgres/step_test.go index 31f8dc26a..1b0e79388 100644 --- a/database/postgres/step_test.go +++ b/database/postgres/step_test.go @@ -36,6 +36,7 @@ func TestPostgres_Client_GetStep(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -105,6 +106,7 @@ func TestPostgres_Client_CreateStep(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -157,6 +159,7 @@ func TestPostgres_Client_UpdateStep(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -193,12 +196,12 @@ func TestPostgres_Client_UpdateStep(t *testing.T) { func TestPostgres_Client_DeleteStep(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/user.go b/database/postgres/user.go index d7b8c5f87..ca36ae49c 100644 --- a/database/postgres/user.go +++ b/database/postgres/user.go @@ -118,7 +118,7 @@ func (c *client) CreateUser(u *library.User) error { // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt err = user.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt user %s: %v", u.GetName(), err) + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) } // send query to the database @@ -153,7 +153,7 @@ func (c *client) UpdateUser(u *library.User) error { // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt err = user.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt user %s: %v", u.GetName(), err) + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) } // send query to the database diff --git a/database/postgres/user_count_test.go b/database/postgres/user_count_test.go index ccc22c873..55a0bbaf4 100644 --- a/database/postgres/user_count_test.go +++ b/database/postgres/user_count_test.go @@ -34,6 +34,7 @@ func TestPostgres_Client_GetUserCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/user_list_test.go b/database/postgres/user_list_test.go index eb69b6c90..d83b835b2 100644 --- a/database/postgres/user_list_test.go +++ b/database/postgres/user_list_test.go @@ -35,6 +35,7 @@ func TestPostgres_Client_GetUserList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -101,6 +102,7 @@ func TestPostgres_Client_GetUserLiteList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/user_test.go b/database/postgres/user_test.go index 3dd2f3ebf..f17aed522 100644 --- a/database/postgres/user_test.go +++ b/database/postgres/user_test.go @@ -29,6 +29,7 @@ func TestPostgres_Client_GetUser(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -96,6 +97,7 @@ func TestPostgres_Client_CreateUser(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -146,6 +148,7 @@ func TestPostgres_Client_UpdateUser(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -182,12 +185,12 @@ func TestPostgres_Client_UpdateUser(t *testing.T) { func TestPostgres_Client_DeleteUser(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/worker_count_test.go b/database/postgres/worker_count_test.go index 0c099c2e2..61645f5ee 100644 --- a/database/postgres/worker_count_test.go +++ b/database/postgres/worker_count_test.go @@ -34,6 +34,7 @@ func TestPostgres_Client_GetWorkerCount(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/worker_list_test.go b/database/postgres/worker_list_test.go index c6250062a..b6b3684cc 100644 --- a/database/postgres/worker_list_test.go +++ b/database/postgres/worker_list_test.go @@ -35,6 +35,7 @@ func TestPostgres_Client_GetWorkerList(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/postgres/worker_test.go b/database/postgres/worker_test.go index 5167c5cc3..dcc983203 100644 --- a/database/postgres/worker_test.go +++ b/database/postgres/worker_test.go @@ -28,6 +28,7 @@ func TestPostgres_Client_GetWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -95,6 +96,7 @@ func TestPostgres_Client_GetWorkerByAddress(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query @@ -162,6 +164,7 @@ func TestPostgres_Client_CreateWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // create expected return in mock @@ -212,6 +215,7 @@ func TestPostgres_Client_UpdateWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query @@ -248,12 +252,12 @@ func TestPostgres_Client_UpdateWorker(t *testing.T) { func TestPostgres_Client_DeleteWorker(t *testing.T) { // setup types - // setup the test database client _database, _mock, err := NewTest() if err != nil { t.Errorf("unable to create new postgres test database: %v", err) } + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // capture the current expected SQL query diff --git a/database/service.go b/database/service.go index 071437d29..7419cc11e 100644 --- a/database/service.go +++ b/database/service.go @@ -42,7 +42,6 @@ type Service interface { GetDeploymentBuildList(string) ([]*library.Build, error) // GetRepoBuildList defines a function that // gets a list of builds by repo ID. - // nolint: lll // ignore long line length GetRepoBuildList(*library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) // GetOrgBuildList defines a function that // gets a list of builds by org. diff --git a/database/setup.go b/database/setup.go index e8f3b0516..fa13ecdff 100644 --- a/database/setup.go +++ b/database/setup.go @@ -127,15 +127,11 @@ func (s *Setup) Validate() error { case constants.CompressionNine: break default: - // nolint:lll // ignoring line length due to error message return fmt.Errorf("database compression level must be between %d and %d - provided level: %d", constants.CompressionNegOne, constants.CompressionNine, s.CompressionLevel) } // enforce AES-256 for the encryption key - explicitly check for 32 characters in the key - // - // nolint: gomnd // ignore magic number if len(s.EncryptionKey) != 32 { - // nolint: lll // ignore long line length due to long error message return fmt.Errorf("database encryption key must have 32 characters - provided length: %d", len(s.EncryptionKey)) } diff --git a/database/sqlite/build_count_test.go b/database/sqlite/build_count_test.go index 9740aa59d..ec4c2120d 100644 --- a/database/sqlite/build_count_test.go +++ b/database/sqlite/build_count_test.go @@ -46,6 +46,7 @@ func TestSqlite_Client_GetBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -116,6 +117,7 @@ func TestSqlite_Client_GetBuildCountByStatus(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -193,6 +195,7 @@ func TestSqlite_Client_GetOrgBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -283,6 +286,7 @@ func TestSqlite_Client_GetOrgBuildCountByEvent(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -373,6 +377,7 @@ func TestSqlite_Client_GetRepoBuildCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/build_list.go b/database/sqlite/build_list.go index a10c29d93..300a7c9a8 100644 --- a/database/sqlite/build_list.go +++ b/database/sqlite/build_list.go @@ -48,12 +48,11 @@ func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, er // variable to store query results b := new([]database.Build) filters := map[string]string{} + if len(deployment) > 0 { filters["source"] = deployment } // send query to the database and store result in variable - // - // nolint: gomnd // ignore magic number err := c.Sqlite. Table(constants.TableBuild). Select("*"). @@ -77,8 +76,6 @@ func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, er } // GetOrgBuildList gets a list of all builds by org name from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, page int, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": org, @@ -129,8 +126,6 @@ func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, pag } // GetRepoBuildList gets a list of all builds by repo ID from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/sqlite/build_list_test.go b/database/sqlite/build_list_test.go index 28f646fb5..908c501bc 100644 --- a/database/sqlite/build_list_test.go +++ b/database/sqlite/build_list_test.go @@ -48,6 +48,7 @@ func TestSqlite_Client_GetBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -117,6 +118,7 @@ func TestSqlite_Client_GetDeploymentBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -195,6 +197,7 @@ func TestSqlite_Client_GetOrgBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -289,6 +292,7 @@ func TestSqlite_Client_GetOrgBuildList_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -379,6 +383,7 @@ func TestSqlite_Client_GetOrgBuildListByEvent(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -468,6 +473,7 @@ func TestSqlite_Client_GetRepoBuildList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/build_test.go b/database/sqlite/build_test.go index 4cb95fccb..d35cf6952 100644 --- a/database/sqlite/build_test.go +++ b/database/sqlite/build_test.go @@ -33,6 +33,7 @@ func TestSqlite_Client_GetBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -105,6 +106,7 @@ func TestSqlite_Client_GetLastBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -178,6 +180,7 @@ func TestSqlite_Client_GetLastBuildByBranch(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -272,6 +275,7 @@ func TestSqlite_Client_GetPendingAndRunningBuilds(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -356,6 +360,7 @@ func TestSqlite_Client_CreateBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -409,6 +414,7 @@ func TestSqlite_Client_UpdateBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -459,6 +465,7 @@ func TestSqlite_Client_DeleteBuild(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/driver_test.go b/database/sqlite/driver_test.go index 92a80c129..83a2aae29 100644 --- a/database/sqlite/driver_test.go +++ b/database/sqlite/driver_test.go @@ -20,6 +20,7 @@ func TestSqlite_Client_Driver(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // run test diff --git a/database/sqlite/hook_count_test.go b/database/sqlite/hook_count_test.go index 8eea9515d..3d5d334cf 100644 --- a/database/sqlite/hook_count_test.go +++ b/database/sqlite/hook_count_test.go @@ -55,6 +55,7 @@ func TestSqlite_Client_GetRepoHookCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/hook_list_test.go b/database/sqlite/hook_list_test.go index ed44e5945..a9d8394ac 100644 --- a/database/sqlite/hook_list_test.go +++ b/database/sqlite/hook_list_test.go @@ -49,6 +49,7 @@ func TestSqlite_Client_GetHookList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -123,6 +124,7 @@ func TestSqlite_Client_GetRepoHookList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/hook_test.go b/database/sqlite/hook_test.go index 371c787e8..91a8c0fb5 100644 --- a/database/sqlite/hook_test.go +++ b/database/sqlite/hook_test.go @@ -32,6 +32,7 @@ func TestSqlite_Client_GetHook(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -103,6 +104,7 @@ func TestSqlite_Client_GetLastHook(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -167,6 +169,7 @@ func TestSqlite_Client_CreateHook(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -213,6 +216,7 @@ func TestSqlite_Client_UpdateHook(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -265,6 +269,7 @@ func TestSqlite_Client_DeleteHook(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/log.go b/database/sqlite/log.go index 605d50064..aed36ca20 100644 --- a/database/sqlite/log.go +++ b/database/sqlite/log.go @@ -158,7 +158,7 @@ func (c *client) CreateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress err = log.Compress(c.config.CompressionLevel) if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %v", l.GetStepID(), err) + return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) } // send query to the database @@ -192,7 +192,7 @@ func (c *client) UpdateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress err = log.Compress(c.config.CompressionLevel) if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %v", l.GetStepID(), err) + return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) } // send query to the database diff --git a/database/sqlite/log_test.go b/database/sqlite/log_test.go index 280f06bce..a1a52a502 100644 --- a/database/sqlite/log_test.go +++ b/database/sqlite/log_test.go @@ -32,6 +32,7 @@ func TestSqlite_Client_GetBuildLogs(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -92,6 +93,7 @@ func TestSqlite_Client_GetStepLog(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -156,6 +158,7 @@ func TestSqlite_Client_GetServiceLog(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -220,6 +223,7 @@ func TestSqlite_Client_CreateLog(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -266,6 +270,7 @@ func TestSqlite_Client_UpdateLog(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -318,6 +323,7 @@ func TestSqlite_Client_DeleteLog(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/ping_test.go b/database/sqlite/ping_test.go index aee71b003..04c207bcd 100644 --- a/database/sqlite/ping_test.go +++ b/database/sqlite/ping_test.go @@ -14,6 +14,7 @@ func TestSqlite_Client_Ping(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB() _sql.Close() diff --git a/database/sqlite/repo.go b/database/sqlite/repo.go index 81bb01f8d..76767c277 100644 --- a/database/sqlite/repo.go +++ b/database/sqlite/repo.go @@ -80,7 +80,7 @@ func (c *client) CreateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %v", r.GetFullName(), err) + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database @@ -112,7 +112,7 @@ func (c *client) UpdateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %v", r.GetFullName(), err) + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database diff --git a/database/sqlite/repo_count_test.go b/database/sqlite/repo_count_test.go index ed2e77de4..dbb4ac10e 100644 --- a/database/sqlite/repo_count_test.go +++ b/database/sqlite/repo_count_test.go @@ -53,6 +53,7 @@ func TestSqlite_Client_GetRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -132,6 +133,7 @@ func TestSqlite_Client_GetUserRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -206,6 +208,7 @@ func TestSqlite_Client_GetOrgRepoCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -289,6 +292,7 @@ func TestSqlite_Client_GetOrgRepoCount_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/repo_list.go b/database/sqlite/repo_list.go index 72afbe125..0db0f6fdb 100644 --- a/database/sqlite/repo_list.go +++ b/database/sqlite/repo_list.go @@ -56,8 +56,6 @@ func (c *client) GetRepoList() ([]*library.Repo, error) { } // GetOrgRepoList gets a list of all repos by org from the database. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int) ([]*library.Repo, error) { c.Logger.WithFields(logrus.Fields{ "org": org, diff --git a/database/sqlite/repo_list_test.go b/database/sqlite/repo_list_test.go index 1d9567cdf..9d20602f2 100644 --- a/database/sqlite/repo_list_test.go +++ b/database/sqlite/repo_list_test.go @@ -57,6 +57,7 @@ func TestSqlite_Client_GetRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -132,6 +133,7 @@ func TestSqlite_Client_GetOrgRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -207,6 +209,7 @@ func TestSqlite_Client_GetOrgRepoList_NonAdmin(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -288,6 +291,7 @@ func TestSqlite_Client_GetUserRepoList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/repo_test.go b/database/sqlite/repo_test.go index a5fc9a925..2c0cb3081 100644 --- a/database/sqlite/repo_test.go +++ b/database/sqlite/repo_test.go @@ -29,6 +29,7 @@ func TestSqlite_Client_GetRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -96,6 +97,7 @@ func TestSqlite_Client_CreateRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -145,6 +147,7 @@ func TestSqlite_Client_UpdateRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -200,6 +203,7 @@ func TestSqlite_Client_DeleteRepo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/secret.go b/database/sqlite/secret.go index 98076763a..b0c84d4a3 100644 --- a/database/sqlite/secret.go +++ b/database/sqlite/secret.go @@ -40,7 +40,6 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("getting %s secret %s for %s/%s from the database", t, secretName, o, n) var err error @@ -87,6 +86,7 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) err = result.Error } + if err != nil { return nil, err } @@ -132,7 +132,6 @@ func (c *client) CreateSecret(s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("creating %s secret %s in the database", s.GetType(), s.GetName()) // cast to database type @@ -149,7 +148,7 @@ func (c *client) CreateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt err = secret.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %v", s.GetName(), err) + return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) } // send query to the database @@ -181,7 +180,6 @@ func (c *client) UpdateSecret(s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("updating %s secret %s in the database", s.GetType(), s.GetName()) // cast to database type @@ -198,7 +196,7 @@ func (c *client) UpdateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt err = secret.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %v", s.GetName(), err) + return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) } // send query to the database diff --git a/database/sqlite/secret_count.go b/database/sqlite/secret_count.go index 0cc6c4815..cca5fb6b8 100644 --- a/database/sqlite/secret_count.go +++ b/database/sqlite/secret_count.go @@ -33,7 +33,6 @@ func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, erro } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("getting count of %s secrets for %s/%s from the database", t, o, n) var err error @@ -60,6 +59,7 @@ func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, erro for _, t := range teams { lowerTeams = append(lowerTeams, strings.ToLower(t)) } + err = c.Sqlite. Table(constants.TableSecret). Select("count(*)"). diff --git a/database/sqlite/secret_count_test.go b/database/sqlite/secret_count_test.go index 4e5f20ee2..56039d5d8 100644 --- a/database/sqlite/secret_count_test.go +++ b/database/sqlite/secret_count_test.go @@ -58,6 +58,7 @@ func TestSqlite_Client_GetTypeSecretCount_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -138,6 +139,7 @@ func TestSqlite_Client_GetTypeSecretCount_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -218,6 +220,7 @@ func TestSqlite_Client_GetTypeSecretCount_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -298,6 +301,7 @@ func TestSqlite_Client_GetTypeSecretCount_Shared_Wildcard(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/secret_list.go b/database/sqlite/secret_list.go index 41650b985..d4edc5304 100644 --- a/database/sqlite/secret_list.go +++ b/database/sqlite/secret_list.go @@ -60,8 +60,6 @@ func (c *client) GetSecretList() ([]*library.Secret, error) { // GetTypeSecretList gets a list of secrets by type, // owner, and name (repo or team) from the database. -// -// nolint: lll // ignore long line length func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []string) ([]*library.Secret, error) { // create log fields from secret metadata fields := logrus.Fields{ @@ -80,7 +78,6 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("listing %s secrets for %s/%s from the database", t, o, n) var err error @@ -109,6 +106,7 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st for _, t := range teams { lowerTeams = append(lowerTeams, strings.ToLower(t)) } + err = c.Sqlite. Table(constants.TableSecret). Where("type = 'shared' AND org = ?", o). @@ -124,6 +122,7 @@ func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []st Scan(s).Error } } + if err != nil { return nil, err } diff --git a/database/sqlite/secret_list_test.go b/database/sqlite/secret_list_test.go index f9a48a183..027f01a94 100644 --- a/database/sqlite/secret_list_test.go +++ b/database/sqlite/secret_list_test.go @@ -51,6 +51,7 @@ func TestSqlite_Client_GetSecretList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -120,6 +121,7 @@ func TestSqlite_Client_GetTypeSecretList_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -189,6 +191,7 @@ func TestSqlite_Client_GetTypeSecretList_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -258,6 +261,7 @@ func TestSqlite_Client_GetTypeSecretList_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -327,6 +331,7 @@ func TestSqlite_Client_GetTypeSecretList_Shared_wildcard(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/secret_test.go b/database/sqlite/secret_test.go index 2d92fa710..74dacd850 100644 --- a/database/sqlite/secret_test.go +++ b/database/sqlite/secret_test.go @@ -29,6 +29,7 @@ func TestSqlite_Client_GetSecret_Org(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -98,6 +99,7 @@ func TestSqlite_Client_GetSecret_Repo(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -167,6 +169,7 @@ func TestSqlite_Client_GetSecret_Shared(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -236,6 +239,7 @@ func TestSqlite_Client_CreateSecret(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -287,6 +291,7 @@ func TestSqlite_Client_UpdateSecret(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -344,6 +349,7 @@ func TestSqlite_Client_DeleteSecret(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -389,6 +395,7 @@ func testSecret() *library.Secret { i64 := int64(0) str := "" booL := false + var arr []string return &library.Secret{ diff --git a/database/sqlite/service_count_test.go b/database/sqlite/service_count_test.go index 7b0d5eaba..13d533a82 100644 --- a/database/sqlite/service_count_test.go +++ b/database/sqlite/service_count_test.go @@ -55,6 +55,7 @@ func TestSqlite_Client_GetBuildServiceCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -106,12 +107,12 @@ func TestSqlite_Client_GetBuildServiceCount(t *testing.T) { func TestSqlite_Client_GetServiceImageCount(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -149,12 +150,12 @@ func TestSqlite_Client_GetServiceImageCount(t *testing.T) { func TestSqlite_Client_GetServiceStatusCount(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/service_list.go b/database/sqlite/service_list.go index 390fbdf76..eb16406af 100644 --- a/database/sqlite/service_list.go +++ b/database/sqlite/service_list.go @@ -40,8 +40,6 @@ func (c *client) GetServiceList() ([]*library.Service, error) { } // GetBuildServiceList gets a list of services by build ID from the database. -// -// nolint: lll // ignore long line length due to parameters func (c *client) GetBuildServiceList(b *library.Build, page, perPage int) ([]*library.Service, error) { c.Logger.WithFields(logrus.Fields{ "build": b.GetNumber(), diff --git a/database/sqlite/service_list_test.go b/database/sqlite/service_list_test.go index 200316325..a9c556d97 100644 --- a/database/sqlite/service_list_test.go +++ b/database/sqlite/service_list_test.go @@ -51,6 +51,7 @@ func TestSqlite_Client_GetServiceList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -125,6 +126,7 @@ func TestSqlite_Client_GetBuildServiceList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/service_test.go b/database/sqlite/service_test.go index 006a3ece6..3982ddf36 100644 --- a/database/sqlite/service_test.go +++ b/database/sqlite/service_test.go @@ -31,6 +31,7 @@ func TestSqlite_Client_GetService(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -96,6 +97,7 @@ func TestSqlite_Client_CreateService(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -143,6 +145,7 @@ func TestSqlite_Client_UpdateService(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -196,6 +199,7 @@ func TestSqlite_Client_DeleteService(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 6750540bd..291235644 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -205,55 +205,55 @@ func createTables(c *client) error { // create the builds table err := c.Sqlite.Exec(ddl.CreateBuildTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } // create the hooks table err = c.Sqlite.Exec(ddl.CreateHookTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableHook, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableHook, err) } // create the logs table err = c.Sqlite.Exec(ddl.CreateLogTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableLog, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) } // create the repos table err = c.Sqlite.Exec(ddl.CreateRepoTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableRepo, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) } // create the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableSecret, err) } // create the services table err = c.Sqlite.Exec(ddl.CreateServiceTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableService, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) } // create the steps table err = c.Sqlite.Exec(ddl.CreateStepTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableStep, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } // create the users table err = c.Sqlite.Exec(ddl.CreateUserTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableUser, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableUser, err) } // create the workers table err = c.Sqlite.Exec(ddl.CreateWorkerTable).Error if err != nil { - return fmt.Errorf("unable to create %s table: %v", constants.TableWorker, err) + return fmt.Errorf("unable to create %s table: %w", constants.TableWorker, err) } return nil @@ -261,75 +261,73 @@ func createTables(c *client) error { // createIndexes is a helper function to setup // the database with the necessary indexes. -// -// nolint: lll // ignore long line length due to error messages func createIndexes(c *client) error { c.Logger.Trace("creating data indexes in the sqlite database") // create the builds_repo_id index for the builds table err := c.Sqlite.Exec(ddl.CreateBuildRepoIDIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_repo_id index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_repo_id index for the %s table: %w", constants.TableBuild, err) } // create the builds_status index for the builds table err = c.Sqlite.Exec(ddl.CreateBuildStatusIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_status index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_status index for the %s table: %w", constants.TableBuild, err) } // create the builds_created index for the builds table err = c.Sqlite.Exec(ddl.CreateBuildCreatedIndex).Error if err != nil { - return fmt.Errorf("unable to create builds_created index for the %s table: %v", constants.TableBuild, err) + return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) } // create the hooks_repo_id index for the hooks table err = c.Sqlite.Exec(ddl.CreateHookRepoIDIndex).Error if err != nil { - return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %v", constants.TableHook, err) + return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %w", constants.TableHook, err) } // create the logs_build_id index for the logs table err = c.Sqlite.Exec(ddl.CreateLogBuildIDIndex).Error if err != nil { - return fmt.Errorf("unable to create logs_build_id index for the %s table: %v", constants.TableLog, err) + return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) } // create the repos_org_name index for the repos table err = c.Sqlite.Exec(ddl.CreateRepoOrgNameIndex).Error if err != nil { - return fmt.Errorf("unable to create repos_org_name index for the %s table: %v", constants.TableRepo, err) + return fmt.Errorf("unable to create repos_org_name index for the %s table: %w", constants.TableRepo, err) } // create the secrets_type_org_repo index for the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %w", constants.TableSecret, err) } // create the secrets_type_org_team index for the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgTeam).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %w", constants.TableSecret, err) } // create the secrets_type_org index for the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTypeOrg).Error if err != nil { - return fmt.Errorf("unable to create secrets_type_org index for the %s table: %v", constants.TableSecret, err) + return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } // create the users_refresh index for the users table err = c.Sqlite.Exec(ddl.CreateUserRefreshIndex).Error if err != nil { - return fmt.Errorf("unable to create users_refresh index for the %s table: %v", constants.TableUser, err) + return fmt.Errorf("unable to create users_refresh index for the %s table: %w", constants.TableUser, err) } // create the workers_hostname_address index for the workers table err = c.Sqlite.Exec(ddl.CreateWorkerHostnameAddressIndex).Error if err != nil { - return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %v", constants.TableWorker, err) + return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %w", constants.TableWorker, err) } return nil diff --git a/database/sqlite/sqlite_test.go b/database/sqlite/sqlite_test.go index 99831a70b..713ce897d 100644 --- a/database/sqlite/sqlite_test.go +++ b/database/sqlite/sqlite_test.go @@ -56,12 +56,12 @@ func TestSqlite_New(t *testing.T) { func TestSqlite_setupDatabase(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup the skip test database client @@ -69,6 +69,7 @@ func TestSqlite_setupDatabase(t *testing.T) { if err != nil { t.Errorf("unable to create new skip sqlite test database: %v", err) } + defer func() { _sql, _ := _skipDatabase.Sqlite.DB(); _sql.Close() }() err = WithSkipCreation(true)(_skipDatabase) @@ -110,12 +111,12 @@ func TestSqlite_setupDatabase(t *testing.T) { func TestSqlite_createTables(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() tests := []struct { @@ -146,12 +147,12 @@ func TestSqlite_createTables(t *testing.T) { func TestPostgres_createIndexes(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() tests := []struct { diff --git a/database/sqlite/step_count_test.go b/database/sqlite/step_count_test.go index 1ac7e5f39..83bf7138a 100644 --- a/database/sqlite/step_count_test.go +++ b/database/sqlite/step_count_test.go @@ -55,6 +55,7 @@ func TestSqlite_Client_GetBuildStepCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -106,12 +107,12 @@ func TestSqlite_Client_GetBuildStepCount(t *testing.T) { func TestSqlite_Client_GetStepImageCount(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -149,12 +150,12 @@ func TestSqlite_Client_GetStepImageCount(t *testing.T) { func TestSqlite_Client_GetStepStatusCount(t *testing.T) { // setup types - // setup the test database client _database, err := NewTest() if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/step_list_test.go b/database/sqlite/step_list_test.go index 23303adf5..75956b54f 100644 --- a/database/sqlite/step_list_test.go +++ b/database/sqlite/step_list_test.go @@ -51,6 +51,7 @@ func TestSqlite_Client_GetStepList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -125,6 +126,7 @@ func TestSqlite_Client_GetBuildStepList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/step_test.go b/database/sqlite/step_test.go index 52d73e47a..7c7b91500 100644 --- a/database/sqlite/step_test.go +++ b/database/sqlite/step_test.go @@ -31,6 +31,7 @@ func TestSqlite_Client_GetStep(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -96,6 +97,7 @@ func TestSqlite_Client_CreateStep(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -143,6 +145,7 @@ func TestSqlite_Client_UpdateStep(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -196,6 +199,7 @@ func TestSqlite_Client_DeleteStep(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/user.go b/database/sqlite/user.go index dae174edd..033291854 100644 --- a/database/sqlite/user.go +++ b/database/sqlite/user.go @@ -118,7 +118,7 @@ func (c *client) CreateUser(u *library.User) error { // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt err = user.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt user %s: %v", u.GetName(), err) + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) } // send query to the database @@ -153,7 +153,7 @@ func (c *client) UpdateUser(u *library.User) error { // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt err = user.Encrypt(c.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt user %s: %v", u.GetName(), err) + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) } // send query to the database diff --git a/database/sqlite/user_count_test.go b/database/sqlite/user_count_test.go index f866f0aa7..a991f7f8b 100644 --- a/database/sqlite/user_count_test.go +++ b/database/sqlite/user_count_test.go @@ -46,6 +46,7 @@ func TestSqlite_Client_GetUserCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/user_list_test.go b/database/sqlite/user_list_test.go index 0ee623f72..4a626f988 100644 --- a/database/sqlite/user_list_test.go +++ b/database/sqlite/user_list_test.go @@ -47,6 +47,7 @@ func TestSqlite_Client_GetUserList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -108,6 +109,7 @@ func TestSqlite_Client_GetUserLiteList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/user_test.go b/database/sqlite/user_test.go index ef97c6eda..21f6d9543 100644 --- a/database/sqlite/user_test.go +++ b/database/sqlite/user_test.go @@ -24,6 +24,7 @@ func TestSqlite_Client_GetUser(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -87,6 +88,7 @@ func TestSqlite_Client_CreateUser(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -132,6 +134,7 @@ func TestSqlite_Client_UpdateUser(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -183,6 +186,7 @@ func TestSqlite_Client_DeleteUser(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -228,6 +232,7 @@ func testUser() *library.User { i64 := int64(0) str := "" b := false + var arr []string return &library.User{ diff --git a/database/sqlite/worker_count_test.go b/database/sqlite/worker_count_test.go index fdd652852..dbbdcfc18 100644 --- a/database/sqlite/worker_count_test.go +++ b/database/sqlite/worker_count_test.go @@ -46,6 +46,7 @@ func TestSqlite_Client_GetWorkerCount(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/worker_list_test.go b/database/sqlite/worker_list_test.go index 8a6c0eba1..72916385e 100644 --- a/database/sqlite/worker_list_test.go +++ b/database/sqlite/worker_list_test.go @@ -47,6 +47,7 @@ func TestSqlite_Client_GetWorkerList(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/database/sqlite/worker_test.go b/database/sqlite/worker_test.go index 219351e6d..50c6087db 100644 --- a/database/sqlite/worker_test.go +++ b/database/sqlite/worker_test.go @@ -24,6 +24,7 @@ func TestSqlite_Client_GetWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -87,6 +88,7 @@ func TestSqlite_Client_GetWorkerByAddress(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -150,6 +152,7 @@ func TestSqlite_Client_CreateWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -195,6 +198,7 @@ func TestSqlite_Client_UpdateWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -246,6 +250,7 @@ func TestSqlite_Client_DeleteWorker(t *testing.T) { if err != nil { t.Errorf("unable to create new sqlite test database: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests @@ -291,6 +296,7 @@ func testWorker() *library.Worker { i64 := int64(0) str := "" b := false + var arr []string return &library.Worker{ diff --git a/mock/server/hook.go b/mock/server/hook.go index 0c356c3c5..3bca13258 100644 --- a/mock/server/hook.go +++ b/mock/server/hook.go @@ -2,6 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/secret.go b/mock/server/secret.go index 3ef924d67..eefbe9861 100644 --- a/mock/server/secret.go +++ b/mock/server/secret.go @@ -2,6 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/service.go b/mock/server/service.go index b461bde65..ba4136515 100644 --- a/mock/server/service.go +++ b/mock/server/service.go @@ -2,6 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/step.go b/mock/server/step.go index e0826d45a..c88ce6250 100644 --- a/mock/server/step.go +++ b/mock/server/step.go @@ -2,6 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/user.go b/mock/server/user.go index 3d883274d..7e69c809a 100644 --- a/mock/server/user.go +++ b/mock/server/user.go @@ -2,6 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: dupl // ignore duplicate with user code package server import ( diff --git a/queue/context.go b/queue/context.go index ea9c2d0fe..d6789e5bb 100644 --- a/queue/context.go +++ b/queue/context.go @@ -56,7 +56,7 @@ func WithContext(c context.Context, s Service) context.Context { // // https://pkg.go.dev/context?tab=doc#WithValue // - // nolint: golint,staticcheck // ignore using string with context value + // nolint: staticcheck,revive // ignore using string with context value return context.WithValue(c, key, s) } diff --git a/queue/context_test.go b/queue/context_test.go index 4a6ba4c90..b88b8f3d8 100644 --- a/queue/context_test.go +++ b/queue/context_test.go @@ -22,7 +22,7 @@ func TestExecutor_FromContext(t *testing.T) { want Service }{ { - // nolint: golint,staticcheck // ignore using string with context value + // nolint: staticcheck // ignore using string with context value context: context.WithValue(context.Background(), key, _service), want: _service, }, @@ -31,7 +31,7 @@ func TestExecutor_FromContext(t *testing.T) { want: nil, }, { - // nolint: golint,staticcheck // ignore using string with context value + // nolint: staticcheck // ignore using string with context value context: context.WithValue(context.Background(), key, "foo"), want: nil, }, @@ -92,7 +92,7 @@ func TestExecutor_WithContext(t *testing.T) { // setup types _service, _ := New(&Setup{}) - // nolint: golint,staticcheck // ignore using string with context value + // nolint: staticcheck // ignore using string with context value want := context.WithValue(context.Background(), key, _service) // run test diff --git a/queue/queue_test.go b/queue/queue_test.go index 8e690920c..61bcfd527 100644 --- a/queue/queue_test.go +++ b/queue/queue_test.go @@ -13,7 +13,6 @@ import ( func TestQueue_New(t *testing.T) { // setup types - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run diff --git a/queue/redis/driver_test.go b/queue/redis/driver_test.go index 85582775c..2e5d4bd96 100644 --- a/queue/redis/driver_test.go +++ b/queue/redis/driver_test.go @@ -16,7 +16,6 @@ import ( func TestRedis_Driver(t *testing.T) { // setup types - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run diff --git a/queue/redis/opts_test.go b/queue/redis/opts_test.go index 72c91c5eb..b44e79418 100644 --- a/queue/redis/opts_test.go +++ b/queue/redis/opts_test.go @@ -15,7 +15,6 @@ import ( func TestRedis_ClientOpt_WithAddress(t *testing.T) { // setup tests - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run @@ -68,7 +67,6 @@ func TestRedis_ClientOpt_WithAddress(t *testing.T) { func TestRedis_ClientOpt_WithChannels(t *testing.T) { // setup tests - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run @@ -122,7 +120,6 @@ func TestRedis_ClientOpt_WithChannels(t *testing.T) { func TestRedis_ClientOpt_WithCluster(t *testing.T) { // setup tests - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run diff --git a/queue/redis/pop.go b/queue/redis/pop.go index e55b3e253..3f698a5f0 100644 --- a/queue/redis/pop.go +++ b/queue/redis/pop.go @@ -7,6 +7,7 @@ package redis import ( "context" "encoding/json" + "errors" "github.com/go-redis/redis/v8" "github.com/go-vela/types" @@ -26,12 +27,12 @@ func (c *client) Pop(ctx context.Context) (*types.Item, error) { // https://pkg.go.dev/github.com/go-redis/redis?tab=doc#StringSliceCmd.Result result, err := popCmd.Result() if err != nil { - switch err { - case redis.Nil: // BLPOP timeout + // BLPOP timeout + if errors.Is(err, redis.Nil) { return nil, nil - default: - return nil, err } + + return nil, err } item := new(types.Item) diff --git a/queue/redis/pop_test.go b/queue/redis/pop_test.go index cacda6557..772d98830 100644 --- a/queue/redis/pop_test.go +++ b/queue/redis/pop_test.go @@ -16,7 +16,6 @@ import ( func TestRedis_Pop(t *testing.T) { // setup types - // use global variables in redis_test.go _item := &types.Item{ Build: _build, diff --git a/queue/redis/push_test.go b/queue/redis/push_test.go index 97ed47a7a..34980f0db 100644 --- a/queue/redis/push_test.go +++ b/queue/redis/push_test.go @@ -14,7 +14,6 @@ import ( func TestRedis_Push(t *testing.T) { // setup types - // use global variables in redis_test.go _item := &types.Item{ Build: _build, diff --git a/queue/redis/redis_test.go b/queue/redis/redis_test.go index d7faeedd3..8c37fd3fc 100644 --- a/queue/redis/redis_test.go +++ b/queue/redis/redis_test.go @@ -151,7 +151,6 @@ var ( func TestRedis_New(t *testing.T) { // setup types - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run diff --git a/queue/setup_test.go b/queue/setup_test.go index 317753b91..4b2e35ede 100644 --- a/queue/setup_test.go +++ b/queue/setup_test.go @@ -13,7 +13,6 @@ import ( func TestQueue_Setup_Redis(t *testing.T) { // setup types - // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run diff --git a/random/random.go b/random/random.go index 96f324cd3..0a5953ed0 100644 --- a/random/random.go +++ b/random/random.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package random import ( diff --git a/router/middleware/build/build.go b/router/middleware/build/build.go index ff4bcd4ca..5b521bf36 100644 --- a/router/middleware/build/build.go +++ b/router/middleware/build/build.go @@ -36,6 +36,7 @@ func Establish() gin.HandlerFunc { if r == nil { retErr := fmt.Errorf("repo %s/%s not found", c.Param("org"), c.Param("repo")) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -43,6 +44,7 @@ func Establish() gin.HandlerFunc { if len(bParam) == 0 { retErr := fmt.Errorf("no build parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -50,6 +52,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("invalid build parameter provided: %s", bParam) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -65,8 +68,9 @@ func Establish() gin.HandlerFunc { b, err := database.FromContext(c).GetBuild(number, r) if err != nil { - retErr := fmt.Errorf("unable to read build %s/%d: %v", r.GetFullName(), number, err) + retErr := fmt.Errorf("unable to read build %s/%d: %w", r.GetFullName(), number, err) util.HandleError(c, http.StatusNotFound, retErr) + return } diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 2940c17d7..9d311e4e8 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -128,6 +128,7 @@ func TestBuild_Establish(t *testing.T) { func TestBuild_Establish_NoRepo(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/database_test.go b/router/middleware/database_test.go index e8f6496bb..dd8b95a37 100644 --- a/router/middleware/database_test.go +++ b/router/middleware/database_test.go @@ -20,6 +20,7 @@ func TestMiddleware_Database(t *testing.T) { var got database.Service want, _ := sqlite.NewTest() + defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/default_build_limit_test.go b/router/middleware/default_build_limit_test.go index 8c0ec2923..a0ed48c2e 100644 --- a/router/middleware/default_build_limit_test.go +++ b/router/middleware/default_build_limit_test.go @@ -16,6 +16,7 @@ import ( func TestMiddleware_DefaultBuildLimit(t *testing.T) { // setup types var got int64 + want := int64(10) // setup context diff --git a/router/middleware/default_timeout_test.go b/router/middleware/default_timeout_test.go index 25be3bce8..2c80a9dc2 100644 --- a/router/middleware/default_timeout_test.go +++ b/router/middleware/default_timeout_test.go @@ -16,6 +16,7 @@ import ( func TestMiddleware_DefaultTimeout(t *testing.T) { // setup types var got int64 + want := int64(60) // setup context diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index 20061022b..87eeb248f 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -5,6 +5,7 @@ package executors import ( + "context" "encoding/json" "io/ioutil" "time" @@ -36,6 +37,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("unable to get worker: %w", err) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -43,10 +45,12 @@ func Establish() gin.HandlerFunc { client := http.DefaultClient client.Timeout = 30 * time.Second endpoint := fmt.Sprintf("%s/api/v1/executors", w.GetAddress()) - req, err := http.NewRequest("GET", endpoint, nil) + + req, err := http.NewRequestWithContext(context.Background(), "GET", endpoint, nil) if err != nil { retErr := fmt.Errorf("unable to form request to %s: %w", endpoint, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -68,6 +72,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("unable to read response from %s: %w", endpoint, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -76,6 +81,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("unable to parse response from %s: %w", endpoint, err) util.HandleError(c, http.StatusBadRequest, retErr) + return } diff --git a/router/middleware/header.go b/router/middleware/header.go index 9eea7c22a..ef3798b0c 100644 --- a/router/middleware/header.go +++ b/router/middleware/header.go @@ -52,12 +52,11 @@ func Secure(c *gin.Context) { c.Header("X-Content-Type-Options", "nosniff") c.Header("X-XSS-Protection", "1; mode=block") + // Also consider adding Content-Security-Policy headers + // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") if c.Request.TLS != nil { c.Header("Strict-Transport-Security", "max-age=31536000") } - - // Also consider adding Content-Security-Policy headers - // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") } // Cors is a middleware function that appends headers for @@ -67,10 +66,12 @@ func Cors(c *gin.Context) { m := c.MustGet("metadata").(*types.Metadata) c.Header("Access-Control-Allow-Origin", "*") + if len(m.Vela.WebAddress) > 0 { c.Header("Access-Control-Allow-Origin", m.Vela.WebAddress) c.Header("Access-Control-Allow-Credentials", "true") } + c.Header("Access-Control-Expose-Headers", "link, x-total-count") } diff --git a/router/middleware/logger.go b/router/middleware/logger.go index 40f2e7d7b..6e8506059 100644 --- a/router/middleware/logger.go +++ b/router/middleware/logger.go @@ -37,6 +37,7 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc end := time.Now() latency := end.Sub(start) + if utc { end = end.UTC() } diff --git a/router/middleware/max_build_limit_test.go b/router/middleware/max_build_limit_test.go index f22df3846..00e3516c9 100644 --- a/router/middleware/max_build_limit_test.go +++ b/router/middleware/max_build_limit_test.go @@ -16,6 +16,7 @@ import ( func TestMiddleware_MaxBuildLimit(t *testing.T) { // setup types var got int64 + want := int64(30) // setup context diff --git a/router/middleware/org/org.go b/router/middleware/org/org.go index 6f5ab5b84..17b384234 100644 --- a/router/middleware/org/org.go +++ b/router/middleware/org/org.go @@ -25,6 +25,7 @@ func Establish() gin.HandlerFunc { if len(oParam) == 0 { retErr := fmt.Errorf("no org parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } diff --git a/router/middleware/org/org_test.go b/router/middleware/org/org_test.go index bfecf125b..f52e2aea3 100644 --- a/router/middleware/org/org_test.go +++ b/router/middleware/org/org_test.go @@ -35,7 +35,6 @@ func TestOrg_Retrieve(t *testing.T) { func TestOrg_Establish(t *testing.T) { // setup types - r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -102,6 +101,7 @@ func TestOrg_Establish(t *testing.T) { func TestOrg_Establish_NoOrgParameter(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index c5a80502a..60056df9e 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -49,8 +49,6 @@ func MustPlatformAdmin() gin.HandlerFunc { } // MustSecretAdmin ensures the user has admin access to the org, repo or team. -// -// nolint: funlen // ignore function length due to comments func MustSecretAdmin() gin.HandlerFunc { return func(c *gin.Context) { u := user.Retrieve(c) @@ -115,7 +113,6 @@ func MustSecretAdmin() gin.HandlerFunc { } if !strings.EqualFold(perm, "admin") { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("user %s does not have 'admin' permissions for the repo %s/%s", u.GetName(), o, n) util.HandleError(c, http.StatusUnauthorized, retErr) @@ -147,7 +144,6 @@ func MustSecretAdmin() gin.HandlerFunc { } if !strings.EqualFold(perm, "admin") { - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("user %s does not have 'admin' permissions for the team %s/%s", u.GetName(), o, n) util.HandleError(c, http.StatusUnauthorized, retErr) @@ -182,7 +178,6 @@ func MustAdmin() gin.HandlerFunc { "user": u.GetName(), }) - // nolint: lll // ignore long line length due to parameters logger.Debugf("verifying user %s has 'admin' permissions for repo %s", u.GetName(), r.GetFullName()) if globalPerms(u) { @@ -216,7 +211,6 @@ func MustAdmin() gin.HandlerFunc { case "admin": return default: - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("user %s does not have 'admin' permissions for the repo %s", u.GetName(), r.GetFullName()) util.HandleError(c, http.StatusUnauthorized, retErr) @@ -242,7 +236,6 @@ func MustWrite() gin.HandlerFunc { "user": u.GetName(), }) - // nolint: lll // ignore long line length due to log message logger.Debugf("verifying user %s has 'write' permissions for repo %s", u.GetName(), r.GetFullName()) if globalPerms(u) { @@ -277,7 +270,6 @@ func MustWrite() gin.HandlerFunc { case "write": return default: - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("user %s does not have 'write' permissions for the repo %s", u.GetName(), r.GetFullName()) util.HandleError(c, http.StatusUnauthorized, retErr) @@ -305,13 +297,11 @@ func MustRead() gin.HandlerFunc { // check if the repo visibility field is set to public if strings.EqualFold(r.GetVisibility(), constants.VisibilityPublic) { - // nolint: lll // ignore long line length due to log message logger.Debugf("skipping 'read' check for repo %s with %s visibility for user %s", r.GetFullName(), r.GetVisibility(), u.GetName()) return } - // nolint: lll // ignore long line length due to log message logger.Debugf("verifying user %s has 'read' permissions for repo %s", u.GetName(), r.GetFullName()) if globalPerms(u) { @@ -348,7 +338,6 @@ func MustRead() gin.HandlerFunc { case "read": return default: - // nolint: lll // ignore long line length due to error message retErr := fmt.Errorf("user %s does not have 'read' permissions for repo %s", u.GetName(), r.GetFullName()) util.HandleError(c, http.StatusUnauthorized, retErr) diff --git a/router/middleware/repo/repo.go b/router/middleware/repo/repo.go index 8afa16813..68b0cc24c 100644 --- a/router/middleware/repo/repo.go +++ b/router/middleware/repo/repo.go @@ -34,6 +34,7 @@ func Establish() gin.HandlerFunc { if len(rParam) == 0 { retErr := fmt.Errorf("no repo parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -48,8 +49,9 @@ func Establish() gin.HandlerFunc { r, err := database.FromContext(c).GetRepo(o, rParam) if err != nil { - retErr := fmt.Errorf("unable to read repo %s/%s: %v", o, rParam, err) + retErr := fmt.Errorf("unable to read repo %s/%s: %w", o, rParam, err) util.HandleError(c, http.StatusNotFound, retErr) + return } diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index 63411640c..eac2daeee 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -108,6 +108,7 @@ func TestRepo_Establish(t *testing.T) { func TestRepo_Establish_NoOrgParameter(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context @@ -135,6 +136,7 @@ func TestRepo_Establish_NoOrgParameter(t *testing.T) { func TestRepo_Establish_NoRepoParameter(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context @@ -162,6 +164,7 @@ func TestRepo_Establish_NoRepoParameter(t *testing.T) { func TestRepo_Establish_NoRepo(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/secret.go b/router/middleware/secret.go index 90f497492..66f28af78 100644 --- a/router/middleware/secret.go +++ b/router/middleware/secret.go @@ -26,6 +26,7 @@ func Secrets(secrets map[string]secret.Service) gin.HandlerFunc { for k, v := range secrets { secret.ToContext(c, k, v) } + c.Next() } } diff --git a/router/middleware/secret_test.go b/router/middleware/secret_test.go index ae6cb623b..55ee9edcf 100644 --- a/router/middleware/secret_test.go +++ b/router/middleware/secret_test.go @@ -52,6 +52,7 @@ func TestMiddleware_Secret(t *testing.T) { func TestMiddleware_Secrets(t *testing.T) { // setup types d, _ := sqlite.NewTest() + defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() var got secret.Service diff --git a/router/middleware/secure_cookie_test.go b/router/middleware/secure_cookie_test.go index 4681cb3ca..60fa73eb4 100644 --- a/router/middleware/secure_cookie_test.go +++ b/router/middleware/secure_cookie_test.go @@ -18,6 +18,7 @@ func TestCookie_SecureCookie(t *testing.T) { type args struct { secure bool } + tests := []struct { name string args args @@ -38,6 +39,7 @@ func TestCookie_SecureCookie(t *testing.T) { want: true, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // setup context diff --git a/router/middleware/service/service.go b/router/middleware/service/service.go index 4e557345f..66adaa082 100644 --- a/router/middleware/service/service.go +++ b/router/middleware/service/service.go @@ -39,12 +39,14 @@ func Establish() gin.HandlerFunc { if r == nil { retErr := fmt.Errorf("repo %s/%s not found", o, c.Param("repo")) util.HandleError(c, http.StatusNotFound, retErr) + return } if b == nil { retErr := fmt.Errorf("build %s not found for repo %s", c.Param("build"), r.GetFullName()) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -52,6 +54,7 @@ func Establish() gin.HandlerFunc { if len(sParam) == 0 { retErr := fmt.Errorf("no service parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -59,6 +62,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("malformed service parameter provided: %s", sParam) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -75,9 +79,9 @@ func Establish() gin.HandlerFunc { s, err := database.FromContext(c).GetService(number, b) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to read service %s/%d/%d: %v", r.GetFullName(), b.GetNumber(), number, err) + retErr := fmt.Errorf("unable to read service %s/%d/%d: %w", r.GetFullName(), b.GetNumber(), number, err) util.HandleError(c, http.StatusNotFound, retErr) + return } diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index 3b324d9c4..bf38fc5ad 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -122,6 +122,7 @@ func TestService_Establish(t *testing.T) { func TestService_Establish_NoRepo(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/step/step.go b/router/middleware/step/step.go index 3ae6409ee..1413cbf35 100644 --- a/router/middleware/step/step.go +++ b/router/middleware/step/step.go @@ -39,12 +39,14 @@ func Establish() gin.HandlerFunc { if r == nil { retErr := fmt.Errorf("repo %s/%s not found", o, c.Param("repo")) util.HandleError(c, http.StatusNotFound, retErr) + return } if b == nil { retErr := fmt.Errorf("build %s not found for repo %s", c.Param("build"), r.GetFullName()) util.HandleError(c, http.StatusNotFound, retErr) + return } @@ -52,6 +54,7 @@ func Establish() gin.HandlerFunc { if len(sParam) == 0 { retErr := fmt.Errorf("no step parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -59,6 +62,7 @@ func Establish() gin.HandlerFunc { if err != nil { retErr := fmt.Errorf("malformed step parameter provided: %s", sParam) util.HandleError(c, http.StatusBadRequest, retErr) + return } @@ -75,9 +79,9 @@ func Establish() gin.HandlerFunc { s, err := database.FromContext(c).GetStep(number, b) if err != nil { - // nolint: lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to read step %s/%d/%d: %v", r.GetFullName(), b.GetNumber(), number, err) + retErr := fmt.Errorf("unable to read step %s/%d/%d: %w", r.GetFullName(), b.GetNumber(), number, err) util.HandleError(c, http.StatusNotFound, retErr) + return } diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index e0367c887..b9a0d8e9f 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -124,6 +124,7 @@ func TestStep_Establish(t *testing.T) { func TestStep_Establish_NoRepo(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/token/token.go b/router/middleware/token/token.go index 51e9a2e07..cf40b882a 100644 --- a/router/middleware/token/token.go +++ b/router/middleware/token/token.go @@ -22,6 +22,7 @@ import ( "github.com/sirupsen/logrus" ) +//lint:ignore SA1019 ignore deprecated type Claims struct { IsAdmin bool `json:"is_admin"` IsActive bool `json:"is_active"` @@ -34,7 +35,6 @@ type Claims struct { // The hash signs the token to guarantee the signature is unique // per token. The refresh token is returned to store with the user // in the database. -// nolint:lll // reference links cause long lines func Compose(c *gin.Context, u *library.User) (string, string, error) { // grab the metadata from the context to pull in provided // cookie duration information @@ -146,6 +146,7 @@ func RetrieveRefreshToken(r *http.Request) (string, error) { } // CreateAccessToken creates a new access token for the given user and duration. +// nolint:staticcheck // ignore deprecated func CreateAccessToken(u *library.User, d time.Duration) (string, error) { now := time.Now() exp := now.Add(d) @@ -171,6 +172,7 @@ func CreateAccessToken(u *library.User, d time.Duration) (string, error) { } // CreateCreateRefreshToken creates a new refresh token for the given user and duration. +// nolint:staticcheck // ignore deprecated func CreateRefreshToken(u *library.User, d time.Duration) (string, int, error) { exp := time.Now().Add(d) diff --git a/router/middleware/token/token_test.go b/router/middleware/token/token_test.go index 6e22c8111..82293ab12 100644 --- a/router/middleware/token/token_test.go +++ b/router/middleware/token/token_test.go @@ -2,9 +2,11 @@ // // Use of this source code is governed by the LICENSE file in this repository. +// nolint: staticcheck // ignore deprecated package token import ( + "context" "fmt" "net/http" "net/http/httptest" @@ -472,7 +474,7 @@ func TestToken_Retrieve_Refresh(t *testing.T) { // setup types want := "fresh" - request, _ := http.NewRequest(http.MethodGet, "/test", nil) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) request.AddCookie(&http.Cookie{ Name: constants.RefreshTokenName, Value: want, @@ -494,7 +496,7 @@ func TestToken_Retrieve_Access(t *testing.T) { want := "foobar" header := fmt.Sprintf("Bearer %s", want) - request, _ := http.NewRequest(http.MethodGet, "/test", nil) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) request.Header.Set("Authorization", header) // run test @@ -510,7 +512,7 @@ func TestToken_Retrieve_Access(t *testing.T) { func TestToken_Retrieve_Access_Error(t *testing.T) { // setup types - request, _ := http.NewRequest(http.MethodGet, "/test", nil) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) // run test got, err := RetrieveAccessToken(request) @@ -525,7 +527,7 @@ func TestToken_Retrieve_Access_Error(t *testing.T) { func TestToken_Retrieve_Refresh_Error(t *testing.T) { // setup types - request, _ := http.NewRequest(http.MethodGet, "/test", nil) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) // run test got, err := RetrieveRefreshToken(request) diff --git a/router/middleware/user/user_test.go b/router/middleware/user/user_test.go index 6aefc9e8a..724ac1cdb 100644 --- a/router/middleware/user/user_test.go +++ b/router/middleware/user/user_test.go @@ -127,6 +127,7 @@ func TestUser_Establish(t *testing.T) { func TestUser_Establish_NoToken(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context @@ -197,6 +198,7 @@ func TestUser_Establish_NoAuthorizeUser(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context @@ -230,6 +232,7 @@ func TestUser_Establish_NoUser(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/webhook_validation_test.go b/router/middleware/webhook_validation_test.go index e7596ba9f..cb0f432fe 100644 --- a/router/middleware/webhook_validation_test.go +++ b/router/middleware/webhook_validation_test.go @@ -18,6 +18,7 @@ func TestWebhook_WebhookValidation(t *testing.T) { type args struct { validate bool } + tests := []struct { name string args args @@ -38,6 +39,7 @@ func TestWebhook_WebhookValidation(t *testing.T) { want: true, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // setup context diff --git a/router/middleware/worker/worker.go b/router/middleware/worker/worker.go index c2eed2880..f4fc5e524 100644 --- a/router/middleware/worker/worker.go +++ b/router/middleware/worker/worker.go @@ -29,14 +29,17 @@ func Establish() gin.HandlerFunc { if len(wParam) == 0 { retErr := fmt.Errorf("no worker parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) + return } logrus.Debugf("Reading worker %s", wParam) + w, err := database.FromContext(c).GetWorker(wParam) if err != nil { - retErr := fmt.Errorf("unable to read worker %s: %v", wParam, err) + retErr := fmt.Errorf("unable to read worker %s: %w", wParam, err) util.HandleError(c, http.StatusNotFound, retErr) + return } diff --git a/router/middleware/worker/worker_test.go b/router/middleware/worker/worker_test.go index dd0b92ffa..cad19f15e 100644 --- a/router/middleware/worker/worker_test.go +++ b/router/middleware/worker/worker_test.go @@ -89,6 +89,7 @@ func TestWorker_Establish(t *testing.T) { func TestWorker_Establish_NoWorkerParameter(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup context diff --git a/router/middleware/worker_test.go b/router/middleware/worker_test.go index 2e1a941e4..5c141bdbb 100644 --- a/router/middleware/worker_test.go +++ b/router/middleware/worker_test.go @@ -17,6 +17,7 @@ import ( func TestMiddleware_Worker(t *testing.T) { // setup types var got time.Duration + want := 5 * time.Minute // setup context diff --git a/scm/flags.go b/scm/flags.go index 9de700f67..3dc36d139 100644 --- a/scm/flags.go +++ b/scm/flags.go @@ -15,7 +15,6 @@ import ( // https://pkg.go.dev/github.com/urfave/cli?tab=doc#Flag // // TODO: in a future release remove the "source" vars in favor of the "scm" ones. -// nolint:lll // these errors will go away when the TODO is completed var Flags = []cli.Flag{ // SCM Flags diff --git a/scm/github/authentication.go b/scm/github/authentication.go index c2d27b14c..0d3bf4b26 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -38,8 +38,6 @@ func (c *client) Login(w http.ResponseWriter, r *http.Request) (string, error) { c.Logger.Trace("processing login request") // generate a random string for creating the OAuth state - // - // nolint: gomnd // ignore magic number oAuthState, err := random.GenerateRandomString(32) if err != nil { return "", err @@ -59,8 +57,6 @@ func (c *client) Login(w http.ResponseWriter, r *http.Request) (string, error) { // Authenticate completes the authentication workflow for the session // and returns the remote user details. -// -// nolint: lll // ignore long line length due to variable names func (c *client) Authenticate(w http.ResponseWriter, r *http.Request, oAuthState string) (*library.User, error) { c.Logger.Trace("authenticating user") @@ -136,7 +132,8 @@ func (c *client) AuthenticateToken(r *http.Request) (*library.User, error) { // check if the provided token was created by Vela _, resp, err := client.Authorizations.Check(context.Background(), c.config.ClientID, token) // check if the error is of type ErrorResponse - if gerr, ok := err.(*github.ErrorResponse); ok { + var gerr *github.ErrorResponse + if errors.As(err, &gerr) { // check the status code switch gerr.Response.StatusCode { // 404 is expected when non vela token is used diff --git a/scm/github/authentication_test.go b/scm/github/authentication_test.go index 3e1c50942..d1b369a1f 100644 --- a/scm/github/authentication_test.go +++ b/scm/github/authentication_test.go @@ -411,6 +411,7 @@ func TestGithub_AuthenticateToken_Vela_OAuth(t *testing.T) { // run test _, err := client.AuthenticateToken(context.Request) + if resp.Code != http.StatusOK { t.Errorf("AuthenticateToken returned %v, want %v", resp.Code, http.StatusOK) } diff --git a/scm/github/changeset.go b/scm/github/changeset.go index 6a47edce0..72ffee69c 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -31,7 +31,7 @@ func (c *client) Changeset(u *library.User, r *library.Repo, sha string) ([]stri // send API call to capture the commit commit, _, err := client.Repositories.GetCommit(ctx, r.GetOrg(), r.GetName(), sha, &opts) if err != nil { - return nil, fmt.Errorf("Repositories.GetCommit returned error: %v", err) + return nil, fmt.Errorf("Repositories.GetCommit returned error: %w", err) } // iterate through each file in the commit @@ -62,7 +62,7 @@ func (c *client) ChangesetPR(u *library.User, r *library.Repo, number int) ([]st // send API call to capture the files from the pull request files, resp, err := client.PullRequests.ListFiles(ctx, r.GetOrg(), r.GetName(), number, &opts) if err != nil { - return nil, fmt.Errorf("PullRequests.ListFiles returned error: %v", err) + return nil, fmt.Errorf("PullRequests.ListFiles returned error: %w", err) } f = append(f, files...) diff --git a/scm/github/deployment.go b/scm/github/deployment.go index 799948a74..68b127450 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -15,8 +15,6 @@ import ( ) // GetDeployment gets a deployment from the GitHub repo. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetDeployment(u *library.User, r *library.Repo, id int64) (*library.Deployment, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), @@ -34,6 +32,7 @@ func (c *client) GetDeployment(u *library.User, r *library.Repo, id int64) (*lib } var payload *raw.StringSliceMap + err = json.Unmarshal(deployment.Payload, &payload) if err != nil { c.Logger.Tracef("Unable to unmarshal payload for deployment id %v", deployment.ID) @@ -96,8 +95,6 @@ func (c *client) GetDeploymentCount(u *library.User, r *library.Repo) (int64, er } // GetDeploymentList gets a list of deployments from the GitHub repo. -// -// nolint: lll // ignore long line length due to variable names func (c *client) GetDeploymentList(u *library.User, r *library.Repo, page, perPage int) ([]*library.Deployment, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), @@ -128,6 +125,7 @@ func (c *client) GetDeploymentList(u *library.User, r *library.Repo, page, perPa // iterate through all API results for _, deployment := range d { var payload *raw.StringSliceMap + err := json.Unmarshal(deployment.Payload, &payload) if err != nil { c.Logger.Tracef("Unable to unmarshal payload for deployment id %v", deployment.ID) diff --git a/scm/github/repo.go b/scm/github/repo.go index 9f45bfc7f..96afc608b 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -20,7 +20,6 @@ import ( // ConfigBackoff is a wrapper for Config that will retry five times if the function // fails to retrieve the yaml/yml file. -// nolint: lll // ignore long line length due to input arguments func (c *client) ConfigBackoff(u *library.User, r *library.Repo, ref string) (data []byte, err error) { // number of times to retry retryLimit := 5 @@ -332,7 +331,7 @@ func (c *client) ListUserRepos(u *library.User) ([]*library.Repo, error) { // send API call to capture the user's repos repos, resp, err := client.Repositories.List(ctx, "", opts) if err != nil { - return nil, fmt.Errorf("unable to list user repos: %v", err) + return nil, fmt.Errorf("unable to list user repos: %w", err) } r = append(r, repos...) @@ -373,7 +372,6 @@ func toLibraryRepo(gr github.Repository) *library.Repo { // GetPullRequest defines a function that retrieves // a pull request for a repo. -// nolint:lll // function signature is lengthy func (c *client) GetPullRequest(u *library.User, r *library.Repo, number int) (string, string, string, string, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), @@ -422,6 +420,7 @@ func (c *client) GetHTMLURL(u *library.User, org, repo, name, ref string) (strin // data is not nil if the file exists if data != nil { URL := data.GetHTMLURL() + if err != nil { return "", err } diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 55c143fa6..b7b524a24 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -155,6 +155,7 @@ func TestGithub_Config_YML_BadRequest(t *testing.T) { // run test got, err := client.Config(u, r, "") + if resp.Code != http.StatusOK { t.Errorf("Config returned %v, want %v", resp.Code, http.StatusOK) } diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 7db25edf2..38c9bca28 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -19,6 +19,7 @@ import ( "github.com/google/go-github/v42/github" ) +// nolint: nilerr // ignore webhook returning nil // ProcessWebhook parses the webhook from a repo. func (c *client) ProcessWebhook(request *http.Request) (*types.Webhook, error) { c.Logger.Tracef("processing GitHub webhook") @@ -80,8 +81,6 @@ func (c *client) VerifyWebhook(request *http.Request, r *library.Repo) error { } // processPushEvent is a helper function to process the push event. -// -// nolint: lll // ignore long line length due to variable names func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (*types.Webhook, error) { c.Logger.WithFields(logrus.Fields{ "org": payload.GetRepo().GetOwner().GetLogin(), @@ -159,8 +158,6 @@ func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (* } // processPREvent is a helper function to process the pull_request event. -// -// nolint: lll // ignore long line length due to variable names func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEvent) (*types.Webhook, error) { c.Logger.WithFields(logrus.Fields{ "org": payload.GetRepo().GetOwner().GetLogin(), @@ -244,8 +241,6 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven } // processDeploymentEvent is a helper function to process the deployment event. -// -// nolint: lll // ignore long line length due to variable names func (c *client) processDeploymentEvent(h *library.Hook, payload *github.DeploymentEvent) (*types.Webhook, error) { c.Logger.WithFields(logrus.Fields{ "org": payload.GetRepo().GetOwner().GetLogin(), @@ -287,8 +282,6 @@ func (c *client) processDeploymentEvent(h *library.Hook, payload *github.Deploym // // sending an API request to GitHub with no // payload provided yields a default of `{}`. - // - // nolint: gomnd // ignore magic number if len(payload.GetDeployment().Payload) > 2 { deployPayload := make(map[string]string) // unmarshal the payload into the expected map[string]string format @@ -334,8 +327,6 @@ func (c *client) processDeploymentEvent(h *library.Hook, payload *github.Deploym } // processIssueCommentEvent is a helper function to process the issue comment event. -// -// nolint: lll // ignore long line length due to variable names func (c *client) processIssueCommentEvent(h *library.Hook, payload *github.IssueCommentEvent) (*types.Webhook, error) { c.Logger.WithFields(logrus.Fields{ "org": payload.GetRepo().GetOwner().GetLogin(), @@ -402,7 +393,7 @@ func (c *client) processIssueCommentEvent(h *library.Hook, payload *github.Issue } // processRepositoryEvent is a helper function to process the repository event. -// nolint: lll // ignore long line length due to error message + func (c *client) processRepositoryEvent(h *library.Hook, payload *github.RepositoryEvent) (*types.Webhook, error) { logrus.Tracef("processing repository event GitHub webhook for %s", payload.GetRepo().GetFullName()) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index fff122e79..3ae551d33 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -5,6 +5,7 @@ package github import ( + "context" "fmt" "net/http" "net/http/httptest" @@ -34,7 +35,7 @@ func TestGithub_ProcessWebhook_Push(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -108,7 +109,7 @@ func TestGithub_ProcessWebhook_Push_NoSender(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -184,7 +185,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -262,7 +263,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedAction(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -315,7 +316,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedState(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -400,6 +401,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { build *library.Build deploymentPayload raw.StringSliceMap } + tests := []struct { name string args args @@ -409,6 +411,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { {"unexpected json payload", args{file: "deployment_unexpected_json_payload.json", deploymentPayload: raw.StringSliceMap{}}, true}, {"unexpected text payload", args{file: "deployment_unexpected_text_payload.json", deploymentPayload: raw.StringSliceMap{}}, true}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { body, err := os.Open(fmt.Sprintf("testdata/hooks/%s", tt.args.file)) @@ -418,7 +421,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -462,7 +465,7 @@ func TestGithub_ProcessWebhook_Deployment_Commit(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -538,7 +541,7 @@ func TestGithub_ProcessWebhook_BadGithubEvent(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -589,7 +592,7 @@ func TestGithub_ProcessWebhook_BadContentType(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "foobar") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -640,7 +643,7 @@ func TestGithub_VerifyWebhook_EmptyRepo(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -680,7 +683,7 @@ func TestGithub_VerifyWebhook_NoSecret(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -711,7 +714,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -784,7 +787,7 @@ func TestGithub_ProcessWebhook_IssueComment_Created(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -857,7 +860,7 @@ func TestGithub_ProcessWebhook_IssueComment_Deleted(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -910,7 +913,7 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") @@ -970,7 +973,7 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { defer body.Close() - request, _ := http.NewRequest(http.MethodGet, "/test", body) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") diff --git a/secret/context_test.go b/secret/context_test.go index 803980664..e9f2de71c 100644 --- a/secret/context_test.go +++ b/secret/context_test.go @@ -16,6 +16,7 @@ import ( func TestSecret_FromContext(t *testing.T) { // setup types d, _ := sqlite.NewTest() + defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() want, err := native.New( @@ -82,6 +83,7 @@ func TestSecret_FromContext_Empty(t *testing.T) { func TestSecret_ToContext(t *testing.T) { // setup types d, _ := sqlite.NewTest() + defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() want, err := native.New( diff --git a/secret/native/create.go b/secret/native/create.go index b4bad22b1..5c2cdfe7d 100644 --- a/secret/native/create.go +++ b/secret/native/create.go @@ -35,7 +35,6 @@ func (c *client) Create(sType, org, name string, s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("creating native %s secret %s for %s/%s", sType, s.GetName(), org, name) // create the secret for the native service diff --git a/secret/native/delete.go b/secret/native/delete.go index 76cf3ef15..380e4bf65 100644 --- a/secret/native/delete.go +++ b/secret/native/delete.go @@ -32,7 +32,6 @@ func (c *client) Delete(sType, org, name, path string) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("deleting native %s secret %s for %s/%s", sType, path, org, name) // capture the secret from the native service diff --git a/secret/native/delete_test.go b/secret/native/delete_test.go index 34f9e4229..556046ea4 100644 --- a/secret/native/delete_test.go +++ b/secret/native/delete_test.go @@ -53,6 +53,7 @@ func TestNative_Delete(t *testing.T) { func TestNative_Delete_Invalid(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // run test diff --git a/secret/native/driver_test.go b/secret/native/driver_test.go index 89e152f27..81cddaeb4 100644 --- a/secret/native/driver_test.go +++ b/secret/native/driver_test.go @@ -18,6 +18,7 @@ func TestNative_Driver(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() want := constants.DriverNative diff --git a/secret/native/get_test.go b/secret/native/get_test.go index 44db6acaf..33dc174ce 100644 --- a/secret/native/get_test.go +++ b/secret/native/get_test.go @@ -62,6 +62,7 @@ func TestNative_Get(t *testing.T) { func TestNative_Get_Invalid(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // run test diff --git a/secret/native/list.go b/secret/native/list.go index a2dc14a6e..3b92f9462 100644 --- a/secret/native/list.go +++ b/secret/native/list.go @@ -13,8 +13,6 @@ import ( ) // List captures a list of secrets. -// -// nolint: lll // ignore long line length func (c *client) List(sType, org, name string, page, perPage int, teams []string) ([]*library.Secret, error) { // create log fields from secret metadata fields := logrus.Fields{ diff --git a/secret/native/native_test.go b/secret/native/native_test.go index bc1ec1aa1..070dba97b 100644 --- a/secret/native/native_test.go +++ b/secret/native/native_test.go @@ -17,6 +17,7 @@ func TestNative_New(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/secret/native/opts_test.go b/secret/native/opts_test.go index 2199a9f4d..dea0ef22e 100644 --- a/secret/native/opts_test.go +++ b/secret/native/opts_test.go @@ -18,6 +18,7 @@ func TestNative_ClientOpt_WithDatabase(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/secret/native/update.go b/secret/native/update.go index 7edbbf995..04f136800 100644 --- a/secret/native/update.go +++ b/secret/native/update.go @@ -33,7 +33,6 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("updating native %s secret %s for %s/%s", sType, s.GetName(), org, name) // capture the secret from the native service diff --git a/secret/native/update_test.go b/secret/native/update_test.go index 419aead61..f8dcf9bec 100644 --- a/secret/native/update_test.go +++ b/secret/native/update_test.go @@ -86,6 +86,7 @@ func TestNative_Update_Invalid(t *testing.T) { // setup database db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() // run test diff --git a/secret/secret_test.go b/secret/secret_test.go index c6f806871..03cc6a432 100644 --- a/secret/secret_test.go +++ b/secret/secret_test.go @@ -16,6 +16,7 @@ func TestSecret_New(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/secret/setup_test.go b/secret/setup_test.go index 904e19059..da5c535c9 100644 --- a/secret/setup_test.go +++ b/secret/setup_test.go @@ -17,6 +17,7 @@ func TestSecret_Setup_Native(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() _setup := &Setup{ @@ -129,6 +130,7 @@ func TestSecret_Setup_Validate(t *testing.T) { if err != nil { t.Errorf("unable to create database service: %v", err) } + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() // setup tests diff --git a/secret/vault/count_test.go b/secret/vault/count_test.go index b57d4ea1a..f5219b3e0 100644 --- a/secret/vault/count_test.go +++ b/secret/vault/count_test.go @@ -63,6 +63,7 @@ func TestVault_Count_Org(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -71,6 +72,7 @@ func TestVault_Count_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -154,6 +156,7 @@ func TestVault_Count_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -162,6 +165,7 @@ func TestVault_Count_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -245,6 +249,7 @@ func TestVault_Count_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -253,6 +258,7 @@ func TestVault_Count_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -294,6 +300,7 @@ func TestVault_Count_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -302,6 +309,7 @@ func TestVault_Count_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -338,6 +346,7 @@ func TestVault_Count_ClosedServer(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -346,6 +355,7 @@ func TestVault_Count_ClosedServer(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -406,6 +416,7 @@ func TestVault_Count_EmptyList(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -414,6 +425,7 @@ func TestVault_Count_EmptyList(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -479,6 +491,7 @@ func TestVault_Count_InvalidList(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -487,6 +500,7 @@ func TestVault_Count_InvalidList(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/create.go b/secret/vault/create.go index 552a6fa55..bdcde401d 100644 --- a/secret/vault/create.go +++ b/secret/vault/create.go @@ -36,7 +36,6 @@ func (c *client) Create(sType, org, name string, s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("creating vault %s secret %s for %s/%s", sType, s.GetName(), org, name) // validate the secret diff --git a/secret/vault/create_test.go b/secret/vault/create_test.go index 8ed0471b0..d6e03d920 100644 --- a/secret/vault/create_test.go +++ b/secret/vault/create_test.go @@ -53,6 +53,7 @@ func TestVault_Create_Org(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -61,6 +62,7 @@ func TestVault_Create_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -127,6 +129,7 @@ func TestVault_Create_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -135,6 +138,7 @@ func TestVault_Create_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -199,6 +203,7 @@ func TestVault_Create_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -207,6 +212,7 @@ func TestVault_Create_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -273,6 +279,7 @@ func TestVault_Create_InvalidSecret(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -281,6 +288,7 @@ func TestVault_Create_InvalidSecret(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -329,6 +337,7 @@ func TestVault_Create_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -337,6 +346,7 @@ func TestVault_Create_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -381,6 +391,7 @@ func TestVault_Create_ClosedServer(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -389,6 +400,7 @@ func TestVault_Create_ClosedServer(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/delete_test.go b/secret/vault/delete_test.go index bdccaf416..57338820c 100644 --- a/secret/vault/delete_test.go +++ b/secret/vault/delete_test.go @@ -33,12 +33,14 @@ func TestVault_Delete_Org(t *testing.T) { }) fake := httptest.NewServer(engine) + defer fake.Close() type args struct { version string prefix string } + tests := []struct { name string args args @@ -47,6 +49,7 @@ func TestVault_Delete_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -102,6 +105,7 @@ func TestVault_Delete_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -110,6 +114,7 @@ func TestVault_Delete_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -165,6 +170,7 @@ func TestVault_Delete_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -173,6 +179,7 @@ func TestVault_Delete_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -210,6 +217,7 @@ func TestVault_Delete_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -218,6 +226,7 @@ func TestVault_Delete_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -250,6 +259,7 @@ func TestVault_Delete_ClosedServer(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -258,6 +268,7 @@ func TestVault_Delete_ClosedServer(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/driver_test.go b/secret/vault/driver_test.go index 43e83e321..9e4589fe8 100644 --- a/secret/vault/driver_test.go +++ b/secret/vault/driver_test.go @@ -25,6 +25,7 @@ func TestVault_Driver(t *testing.T) { version string prefix string } + tests := []struct { name string args args diff --git a/secret/vault/get.go b/secret/vault/get.go index 486dec6fc..625b036ff 100644 --- a/secret/vault/get.go +++ b/secret/vault/get.go @@ -75,7 +75,6 @@ func (c *client) getRepo(org, repo, path string) (*api.Secret, error) { // getShared is a helper function to capture // the shared secret for the provided path. func (c *client) getShared(org, team, path string) (*api.Secret, error) { - // nolint: lll // ignore long line length due to parameters return c.get(fmt.Sprintf("%s/%s/%s/%s/%s", c.config.Prefix, constants.SecretShared, org, team, path)) } diff --git a/secret/vault/get_test.go b/secret/vault/get_test.go index 024644990..624cbb07a 100644 --- a/secret/vault/get_test.go +++ b/secret/vault/get_test.go @@ -58,6 +58,7 @@ func TestVault_Get_Org(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -66,6 +67,7 @@ func TestVault_Get_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -140,6 +142,7 @@ func TestVault_Get_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -148,6 +151,7 @@ func TestVault_Get_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -222,6 +226,7 @@ func TestVault_Get_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -230,6 +235,7 @@ func TestVault_Get_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -270,6 +276,7 @@ func TestVault_Get_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -278,6 +285,7 @@ func TestVault_Get_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -313,6 +321,7 @@ func TestVault_Get_ClosedServer(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -321,6 +330,7 @@ func TestVault_Get_ClosedServer(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/list_test.go b/secret/vault/list_test.go index 3323948f8..bb7f538a4 100644 --- a/secret/vault/list_test.go +++ b/secret/vault/list_test.go @@ -75,6 +75,7 @@ func TestVault_List_Org(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -83,6 +84,7 @@ func TestVault_List_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -204,6 +206,7 @@ func TestVault_List_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -212,6 +215,7 @@ func TestVault_List_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -318,6 +322,7 @@ func TestVault_List_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -326,6 +331,7 @@ func TestVault_List_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -366,6 +372,7 @@ func TestVault_List_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -374,6 +381,7 @@ func TestVault_List_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -463,6 +471,7 @@ func TestVault_List_EmptyList(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -471,6 +480,7 @@ func TestVault_List_EmptyList(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -536,6 +546,7 @@ func TestVault_List_InvalidList(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -544,6 +555,7 @@ func TestVault_List_InvalidList(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -618,6 +630,7 @@ func TestVault_List_NoRead(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -626,6 +639,7 @@ func TestVault_List_NoRead(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/refresh.go b/secret/vault/refresh.go index 330255a78..83bf76a76 100644 --- a/secret/vault/refresh.go +++ b/secret/vault/refresh.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package vault import ( @@ -64,6 +68,7 @@ func (c *client) getAwsToken() (string, time.Duration, error) { } c.Logger.Trace("getting AWS token from vault") + secret, err := c.Vault.Logical().Write("auth/aws/login", headers) if err != nil { return "", 0, err @@ -104,7 +109,7 @@ func (c *client) generateAwsAuthHeader() (map[string]interface{}, error) { // construct the vault STS auth header // - // nolint: lll // ignore long line length due to variable names + loginData := map[string]interface{}{ "role": c.AWS.Role, "iam_http_request_method": req.HTTPRequest.Method, diff --git a/secret/vault/refresh_test.go b/secret/vault/refresh_test.go index 60b5b4dca..0bdb16233 100644 --- a/secret/vault/refresh_test.go +++ b/secret/vault/refresh_test.go @@ -1,3 +1,7 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + package vault import ( diff --git a/secret/vault/update.go b/secret/vault/update.go index ce2d53b57..ef0f1e131 100644 --- a/secret/vault/update.go +++ b/secret/vault/update.go @@ -36,7 +36,6 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { } } - // nolint: lll // ignore long line length due to parameters c.Logger.WithFields(fields).Tracef("updating vault %s secret %s for %s/%s", sType, s.GetName(), org, name) // capture the secret from the Vault service @@ -91,14 +90,12 @@ func (c *client) updateOrg(org, path string, data map[string]interface{}) error // updateRepo is a helper function to update // the repo secret for the provided path. func (c *client) updateRepo(org, repo, path string, data map[string]interface{}) error { - // nolint: lll // ignore long line length due to variable names return c.update(fmt.Sprintf("%s/%s/%s/%s/%s", c.config.Prefix, constants.SecretRepo, org, repo, path), data) } // updateShared is a helper function to update // the shared secret for the provided path. func (c *client) updateShared(org, team, path string, data map[string]interface{}) error { - // nolint: lll // ignore long line length due to variable names return c.update(fmt.Sprintf("%s/%s/%s/%s/%s", c.config.Prefix, constants.SecretShared, org, team, path), data) } diff --git a/secret/vault/update_test.go b/secret/vault/update_test.go index 785c87dd2..a0f54de42 100644 --- a/secret/vault/update_test.go +++ b/secret/vault/update_test.go @@ -68,6 +68,7 @@ func TestVault_Update_Org(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -76,6 +77,7 @@ func TestVault_Update_Org(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -157,6 +159,7 @@ func TestVault_Update_Repo(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -165,6 +168,7 @@ func TestVault_Update_Repo(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -246,6 +250,7 @@ func TestVault_Update_Shared(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -254,6 +259,7 @@ func TestVault_Update_Shared(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -335,6 +341,7 @@ func TestVault_Update_InvalidSecret(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -343,6 +350,7 @@ func TestVault_Update_InvalidSecret(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -390,6 +398,7 @@ func TestVault_Update_InvalidType(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -398,6 +407,7 @@ func TestVault_Update_InvalidType(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -440,6 +450,7 @@ func TestVault_Update_ClosedServer(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -448,6 +459,7 @@ func TestVault_Update_ClosedServer(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -523,6 +535,7 @@ func TestVault_Update_NoWrite(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -531,6 +544,7 @@ func TestVault_Update_NoWrite(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( diff --git a/secret/vault/vault_test.go b/secret/vault/vault_test.go index d7d62e6ac..7ba0ac254 100644 --- a/secret/vault/vault_test.go +++ b/secret/vault/vault_test.go @@ -23,6 +23,7 @@ func TestVault_New(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -31,6 +32,7 @@ func TestVault_New(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -58,6 +60,7 @@ func TestVault_New_Error(t *testing.T) { version string prefix string } + tests := []struct { name string args args @@ -66,6 +69,7 @@ func TestVault_New_Error(t *testing.T) { {"v2", args{version: "2", prefix: ""}}, {"v2 with prefix", args{version: "2", prefix: "prefix"}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s, err := New( @@ -146,6 +150,7 @@ func TestVault_secretFromVault(t *testing.T) { type args struct { secret *api.Secret } + tests := []struct { name string args args @@ -153,6 +158,7 @@ func TestVault_secretFromVault(t *testing.T) { {"v1", args{secret: inputV1}}, {"v2", args{secret: inputV2}}, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := secretFromVault(tt.args.secret) diff --git a/version/version.go b/version/version.go index 3368f7a64..30312ee24 100644 --- a/version/version.go +++ b/version/version.go @@ -34,7 +34,7 @@ var ( func New() *version.Version { // check if a semantic tag was provided if len(Tag) == 0 { - logrus.Warningf("no semantic tag provided - defaulting to v0.0.0") + logrus.Warning("no semantic tag provided - defaulting to v0.0.0") // set a fallback default for the tag Tag = "v0.0.0" @@ -42,7 +42,7 @@ func New() *version.Version { v, err := semver.NewVersion(Tag) if err != nil { - fmt.Println(fmt.Errorf("unable to parse semantic version for %s: %v", Tag, err)) + fmt.Println(fmt.Errorf("unable to parse semantic version for %s: %w", Tag, err)) } return &version.Version{ From 1087bb0e9d85ab2cdb8d154326a85dd2745b5df5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Mar 2022 14:31:55 -0600 Subject: [PATCH 024/298] fix(deps): update module github.com/hashicorp/vault/api to v1.4.1 (#596) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 7d3acd8fb..ceb28ff2b 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/goware/urlx v0.3.1 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.7.0 - github.com/hashicorp/vault/api v1.3.1 + github.com/hashicorp/vault/api v1.4.1 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 @@ -80,7 +80,7 @@ require ( github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.3.0 // indirect + github.com/hashicorp/vault/sdk v0.4.1 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect diff --git a/go.sum b/go.sum index bff408ec9..2e0ddb8c2 100644 --- a/go.sum +++ b/go.sum @@ -326,10 +326,10 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.3.1 h1:pkDkcgTh47PRjY1NEFeofqR4W/HkNUi9qIakESO2aRM= -github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFywzhptMsTIUw= -github.com/hashicorp/vault/sdk v0.3.0 h1:kR3dpxNkhh/wr6ycaJYqp6AFT/i2xaftbfnwZduTKEY= -github.com/hashicorp/vault/sdk v0.3.0/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= +github.com/hashicorp/vault/api v1.4.1 h1:mWLfPT0RhxBitjKr6swieCEP2v5pp/M//t70S3kMLRo= +github.com/hashicorp/vault/api v1.4.1/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM= +github.com/hashicorp/vault/sdk v0.4.1 h1:3SaHOJY687jY1fnB61PtL0cOkKItphrbLmux7T92HBo= +github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= From a1f558c2e8ad350624a0f824cc42d7a4674f2ec4 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 11 Mar 2022 15:03:25 -0600 Subject: [PATCH 025/298] fix(types): update types and fix tests (#609) --- compiler/native/compile_test.go | 15 +++++++++------ compiler/native/parse_test.go | 14 +++++++++++++- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 5fbfc07a2..a9a742250 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -1441,8 +1441,9 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { Version: "1", ID: "__0", Metadata: pipeline.Metadata{ - Clone: true, - Template: false, + Clone: true, + Template: false, + Environment: []string{"steps", "services", "secrets"}, }, Steps: pipeline.ContainerSlice{ &pipeline.Container{ @@ -1485,8 +1486,9 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { Version: "1", ID: "__0", Metadata: pipeline.Metadata{ - Clone: true, - Template: false, + Clone: true, + Template: false, + Environment: []string{"steps", "services", "secrets"}, }, Steps: pipeline.ContainerSlice{ &pipeline.Container{ @@ -1529,8 +1531,9 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { Version: "1", ID: "__0", Metadata: pipeline.Metadata{ - Clone: true, - Template: false, + Clone: true, + Template: false, + Environment: []string{"steps", "services", "secrets"}, }, Steps: pipeline.ContainerSlice{ &pipeline.Container{ diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index 1a04b6e68..909e8d848 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -180,6 +180,9 @@ func TestNative_Parse_Parameters(t *testing.T) { // setup types client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) want := &yaml.Build{ + Metadata: yaml.Metadata{ + Environment: []string{"steps", "services", "secrets"}, + }, Steps: yaml.StepSlice{ &yaml.Step{ Image: "plugins/docker:18.09", @@ -447,6 +450,9 @@ func TestNative_Parse_Secrets(t *testing.T) { // setup types client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) want := &yaml.Build{ + Metadata: yaml.Metadata{ + Environment: []string{"steps", "services", "secrets"}, + }, Secrets: yaml.SecretSlice{ &yaml.Secret{ Name: "docker_username", @@ -508,6 +514,9 @@ func TestNative_Parse_Stages(t *testing.T) { // setup types client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) want := &yaml.Build{ + Metadata: yaml.Metadata{ + Environment: []string{"steps", "services", "secrets"}, + }, Stages: yaml.StageSlice{ &yaml.Stage{ Name: "install", @@ -581,6 +590,9 @@ func TestNative_Parse_Steps(t *testing.T) { // setup types client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) want := &yaml.Build{ + Metadata: yaml.Metadata{ + Environment: []string{"steps", "services", "secrets"}, + }, Steps: yaml.StepSlice{ &yaml.Step{ Commands: []string{"./gradlew downloadDependencies"}, @@ -846,7 +858,7 @@ func Test_client_Parse(t *testing.T) { Metadata: yaml.Metadata{ Template: false, Clone: nil, - Environment: nil, + Environment: []string{"steps", "services", "secrets"}, }, Steps: yaml.StepSlice{ { diff --git a/go.mod b/go.mod index ceb28ff2b..6b185e2f3 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.12.0 + github.com/go-vela/types v0.13.0-rc1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 @@ -103,7 +103,7 @@ require ( github.com/mattn/go-isatty v0.0.12 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/microcosm-cc/bluemonday v1.0.17 // indirect + github.com/microcosm-cc/bluemonday v1.0.18 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect diff --git a/go.sum b/go.sum index 2e0ddb8c2..a4b1be205 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.12.0 h1:RnliZ5sZ0ceDRNyjp8o5uPKMIgLF7Gd7JRJWgOLgOPw= -github.com/go-vela/types v0.12.0/go.mod h1:nMZJ/0tb0HO8/AVaJXHuR5slG9UPuP9or+CnkuyFcL4= +github.com/go-vela/types v0.13.0-rc1 h1:y4A5R/zbjlz/XXdwDE7iOdl+/6hgB0B/jVz9LFDfznw= +github.com/go-vela/types v0.13.0-rc1/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -460,8 +460,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.17 h1:Z1a//hgsQ4yjC+8zEkV8IWySkXnsxmdSY642CTFQb5Y= -github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= +github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= +github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= From e37e3c1b703d44eddcc0deea70464e346e33887b Mon Sep 17 00:00:00 2001 From: Kayla McKay <39921134+kaymckay@users.noreply.github.com> Date: Tue, 15 Mar 2022 09:35:44 -0500 Subject: [PATCH 026/298] chore: Update contributing.md to link guidelines (#606) --- .github/CONTRIBUTING.md | 61 ++++------------------------------------- 1 file changed, 5 insertions(+), 56 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d146c46af..65e1e66a9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,29 +1,14 @@ # Contributing -We'd love to accept your contributions to this project! - -There are just a few guidelines you need to follow. - -## Bugs - -Bug reports should be opened up as [issues](https://help.github.com/en/github/managing-your-work-on-github/about-issues) on the [go-vela/community](https://github.com/go-vela/community) repository! - -## Feature Requests - -Feature Requests should be opened up as [issues](https://help.github.com/en/github/managing-your-work-on-github/about-issues) on the [go-vela/community](https://github.com/go-vela/community) repository! - -## Pull Requests - -**NOTE: We recommend you start by opening a new issue describing the bug or feature you're intending to fix. Even if you think it's relatively minor, it's helpful to know what people are working on.** - -We are always open to new PRs! You can follow the below guide for learning how you can contribute to the project! - ## Getting Started +We'd love to accept your contributions to this project! If you are a first time contributor, please review our [Contributing Guidelines](https://go-vela.github.io/docs/community/contributing_guidelines/) before proceeding. + ### Prerequisites -* [Review the commit guide we follow](https://chris.beams.io/posts/git-commit/#seven-rules) - ensure your commits follow our standards * [Review the local development docs](../DOCS.md) - ensures you have the Vela application stack running locally +* [Review the commit guide we follow](https://chris.beams.io/posts/git-commit/#seven-rules) - ensure your commits follow our standards +* [Review our style guide](https://go-vela.github.io/docs/community/contributing_guidelines/#style-guide) to ensure your code is clean and consistent. ### Setup @@ -62,23 +47,6 @@ cd $HOME/go-vela/server ``` * Write your code and tests to implement the changes you desire. - * Please be sure to [follow our commit rules](https://chris.beams.io/posts/git-commit/#seven-rules) - * Please address linter warnings appropriately. If you are intentionally violating a rule that triggers a linter, please annotate the respective code with `nolint` declarations [[docs](https://golangci-lint.run/usage/false-positives/)]. we are using the following format for `nolint` declarations: - - ```go - // nolint: // - ``` - - Example: - - ```go - // nolint:gocyclo // legacy function is complex, needs simplification - func superComplexFunction() error { - // .. - } - ``` - - Check the [documentation for more examples](https://golangci-lint.run/usage/false-positives/). * Run the repository code (ensures your changes perform as you desire): @@ -108,25 +76,6 @@ make clean git push fork master ``` -* Open a pull request! - * For the title of the pull request, please use the following format for the title: - - ```text - feat(wobble): add hat wobble - ^--^^------^ ^------------^ - | | | - | | +---> Summary in present tense. - | +---> Scope: a noun describing a section of the codebase (optional) - +---> Type: chore, docs, feat, fix, refactor, or test. - ``` - - * feat: adds a new feature (equivalent to a MINOR in Semantic Versioning) - * fix: fixes a bug (equivalent to a PATCH in Semantic Versioning) - * docs: changes to the documentation - * refactor: refactors production code, eg. renaming a variable; doesn't change public API - * test: adds missing tests, refactors tests; no production code change - * chore: updates something without impacting the user (ex: bump a dependency in package.json or go.mod); no production code change - - If a code change introduces a breaking change, place ! suffix after type, ie. feat(change)!: adds breaking change. correlates with MAJOR in semantic versioning. +* Make sure to follow our [PR process](https://go-vela.github.io/docs/community/contributing_guidelines/#development-workflow) when opening a pull request Thank you for your contribution! From dc544660203175c5d0b4a34fc7b9c2586318d19b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Mar 2022 11:27:09 -0500 Subject: [PATCH 027/298] fix(deps): update module github.com/urfave/cli/v2 to v2.4.0 (#610) --- go.mod | 7 +++---- go.sum | 15 ++++++--------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 6b185e2f3..cc8bf8ffa 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.1 - github.com/urfave/cli/v2 v2.3.0 + github.com/urfave/cli/v2 v2.4.0 go.starlark.net v0.0.0-20220302181546-5411bad688d1 golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b gopkg.in/square/go-jose.v2 v2.6.0 @@ -50,7 +50,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect @@ -116,10 +116,9 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/ugorji/go/codec v1.1.11 // indirect github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect diff --git a/go.sum b/go.sum index a4b1be205..9833030bd 100644 --- a/go.sum +++ b/go.sum @@ -106,9 +106,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -552,8 +551,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= @@ -561,8 +560,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -593,8 +590,8 @@ github.com/ugorji/go v1.1.11/go.mod h1:kbRrdMyHY64ADdazOwkrQP9btxt35Z26OJueD3Tq0 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.11 h1:GaQDxjNe1J3vCZvlVaDjUIHIbFuUByFXY7rMqnhB5ck= github.com/ugorji/go/codec v1.1.11/go.mod h1:svMFxxx5FVQJPnJ9vbpAgscNufuiXDyldvzApI86qQo= -github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I= +github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From f043fdabc8f23ae45f70deebcdae789f340cfb85 Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Tue, 15 Mar 2022 16:05:18 -0500 Subject: [PATCH 028/298] feat(templates): add support for stages (#597) --- Makefile | 12 +- api/pipeline.go | 110 +- compiler/engine.go | 13 +- compiler/native/compile.go | 291 +++- compiler/native/compile_test.go | 1206 ++++++++++++++++- compiler/native/environment_test.go | 21 +- compiler/native/expand.go | 203 +-- compiler/native/expand_test.go | 40 +- compiler/native/parse.go | 10 +- compiler/native/parse_test.go | 28 +- compiler/native/testdata/environment.yml | 3 + .../native/testdata/golang_inline_stages.yml | 13 + .../native/testdata/golang_inline_steps.yml | 11 + .../testdata/inline_with_environment.yml | 19 + .../native/testdata/inline_with_golang.yml | 28 + .../native/testdata/inline_with_secrets.yml | 22 + .../native/testdata/inline_with_services.yml | 20 + .../native/testdata/inline_with_stages.yml | 24 + .../testdata/inline_with_stages_and_steps.yml | 22 + .../native/testdata/inline_with_steps.yml | 20 + compiler/native/testdata/services.yml | 6 + .../native/testdata/stage_inline_template.yml | 21 + .../testdata/starlark_inline_stages.star | 25 + .../testdata/starlark_inline_steps.star | 20 + .../native/testdata/step_inline_template.yml | 19 + compiler/native/validate.go | 37 +- compiler/template/native/render.go | 25 +- compiler/template/native/render_test.go | 24 +- compiler/template/starlark/render.go | 56 +- compiler/template/starlark/render_test.go | 24 +- compiler/template/template.go | 4 +- go.mod | 2 +- secret/native/update_test.go | 2 +- 33 files changed, 1961 insertions(+), 420 deletions(-) create mode 100644 compiler/native/testdata/environment.yml create mode 100644 compiler/native/testdata/golang_inline_stages.yml create mode 100644 compiler/native/testdata/golang_inline_steps.yml create mode 100644 compiler/native/testdata/inline_with_environment.yml create mode 100644 compiler/native/testdata/inline_with_golang.yml create mode 100644 compiler/native/testdata/inline_with_secrets.yml create mode 100644 compiler/native/testdata/inline_with_services.yml create mode 100644 compiler/native/testdata/inline_with_stages.yml create mode 100644 compiler/native/testdata/inline_with_stages_and_steps.yml create mode 100644 compiler/native/testdata/inline_with_steps.yml create mode 100644 compiler/native/testdata/services.yml create mode 100644 compiler/native/testdata/stage_inline_template.yml create mode 100644 compiler/native/testdata/starlark_inline_stages.star create mode 100644 compiler/native/testdata/starlark_inline_steps.star create mode 100644 compiler/native/testdata/step_inline_template.yml diff --git a/Makefile b/Makefile index ec24f2fd1..9bb50b910 100644 --- a/Makefile +++ b/Makefile @@ -310,4 +310,14 @@ spec-version-update: # # Usage: `make spec` .PHONY: spec -spec: spec-gen spec-version-update spec-validate \ No newline at end of file +spec: spec-gen spec-version-update spec-validate + +# The `lint` target is intended to lint the +# Go source code with golangci-lint. +# +# Usage: `make lint` +.PHONY: lint +lint: + @echo + @echo "### Linting Go Code" + @golangci-lint run ./... \ No newline at end of file diff --git a/api/pipeline.go b/api/pipeline.go index a6ae3f825..98b495ba9 100644 --- a/api/pipeline.go +++ b/api/pipeline.go @@ -90,13 +90,21 @@ func GetPipeline(ctx *gin.Context) { "user": u.GetName(), }).Infof("reading pipeline for repo %s", r.GetFullName()) - pipeline, _, err := getUnprocessedPipeline(ctx) + config, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) return } + pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{}) + if err != nil { + retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) + util.HandleError(ctx, http.StatusBadRequest, retErr) + + return + } + writeOutput(ctx, pipeline) } @@ -160,13 +168,21 @@ func GetTemplates(ctx *gin.Context) { "user": u.GetName(), }).Infof("reading templates from pipeline for repo %s", r.GetFullName()) - pipeline, _, err := getUnprocessedPipeline(ctx) + config, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) return } + pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{}) + if err != nil { + retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) + util.HandleError(ctx, http.StatusBadRequest, retErr) + + return + } + // create map of templates for response body templates, err := getTemplateLinks(ctx, pipeline.Templates) if err != nil { @@ -225,6 +241,8 @@ func GetTemplates(ctx *gin.Context) { // ExpandPipeline represents the API handler to capture and // expand a pipeline configuration. +// +// nolint: dupl // ignore false positive of duplicate code func ExpandPipeline(ctx *gin.Context) { // capture middleware values o := org.Retrieve(ctx) @@ -240,15 +258,17 @@ func ExpandPipeline(ctx *gin.Context) { "user": u.GetName(), }).Infof("expanding templates from pipeline for repo %s", r.GetFullName()) - pipeline, comp, err := getUnprocessedPipeline(ctx) + config, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) return } - if err := expandPipeline(ctx, pipeline, comp, false); err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) + pipeline, err := comp.CompileLite(config, true, false) + if err != nil { + retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) + util.HandleError(ctx, http.StatusBadRequest, retErr) return } @@ -315,24 +335,22 @@ func ValidatePipeline(ctx *gin.Context) { "user": u.GetName(), }).Infof("validating pipeline for repo %s", r.GetFullName()) - pipeline, comp, err := getUnprocessedPipeline(ctx) + config, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) return } + template := false + // check optional template query parameter if ok, _ := strconv.ParseBool(ctx.DefaultQuery("template", "true")); ok { - if err := expandPipeline(ctx, pipeline, comp, false); err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } + template = true } - // validate the yaml configuration - if err = comp.Validate(pipeline); err != nil { + pipeline, err := comp.CompileLite(config, template, false) + if err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) @@ -387,6 +405,7 @@ func ValidatePipeline(ctx *gin.Context) { // CompilePipeline represents the API handler to capture, // expand and compile a pipeline configuration. +// nolint: dupl // ignore false positive of duplicate code func CompilePipeline(ctx *gin.Context) { // capture middleware values o := org.Retrieve(ctx) @@ -402,21 +421,15 @@ func CompilePipeline(ctx *gin.Context) { "user": u.GetName(), }).Infof("compiling pipeline for repo %s", r.GetFullName()) - pipeline, comp, err := getUnprocessedPipeline(ctx) + config, comp, err := getUnprocessedPipeline(ctx) if err != nil { util.HandleError(ctx, http.StatusBadRequest, err) return } - if err := expandPipeline(ctx, pipeline, comp, true); err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - // validate the yaml configuration - if err = comp.Validate(pipeline); err != nil { + pipeline, err := comp.CompileLite(config, true, true) + if err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) @@ -426,8 +439,9 @@ func CompilePipeline(ctx *gin.Context) { writeOutput(ctx, pipeline) } -// getUnprocessedPipeline retrieves the unprocessed pipeline from a given context. -func getUnprocessedPipeline(ctx *gin.Context) (*yaml.Build, compiler.Engine, error) { +// getUnprocessedPipeline retrieves the unprocessed pipeline from a given context +// and creates an instance of the compiler with metadata. +func getUnprocessedPipeline(ctx *gin.Context) ([]byte, compiler.Engine, error) { // capture middleware values meta := ctx.MustGet("metadata").(*types.Metadata) repo := repo.Retrieve(ctx) @@ -453,12 +467,7 @@ func getUnprocessedPipeline(ctx *gin.Context) (*yaml.Build, compiler.Engine, err WithRepo(repo). WithUser(user) - pipeline, err := comp.Parse(config) - if err != nil { - return nil, nil, fmt.Errorf("unable to parse pipeline configuration for %s: %w", repoName(ctx), err) - } - - return pipeline, comp, nil + return config, comp, nil } // getTemplateLinks helper function that retrieves source provider links @@ -529,44 +538,3 @@ func writeOutput(ctx *gin.Context, pipeline interface{}) { ctx.YAML(http.StatusOK, pipeline) } } - -// expandPipeline uses a given pipeline and compiler to expand stages and steps -// in the pipeline along with optionally substituting the environmental variables. -func expandPipeline(ctx *gin.Context, pipeline *yaml.Build, comp compiler.Engine, substituteEnv bool) error { - // create map of templates for easy lookup - templates := pipeline.Templates.Map() - - var err error - - if len(pipeline.Stages) > 0 { - // inject the templates into the stages - pipeline.Stages, pipeline.Secrets, pipeline.Services, pipeline.Environment, err = comp.ExpandStages(pipeline, templates) - if err != nil { - return fmt.Errorf("unable to expand stages in pipeline configuration for %s: %w", repoName(ctx), err) - } - - if substituteEnv { - // inject the substituted environment variables into the stages - pipeline.Stages, err = comp.SubstituteStages(pipeline.Stages) - if err != nil { - return fmt.Errorf("unable to substitute stages in pipeline configuration for %s: %w", repoName(ctx), err) - } - } - } else { - // inject the templates into the steps - pipeline.Steps, pipeline.Secrets, pipeline.Services, pipeline.Environment, err = comp.ExpandSteps(pipeline, templates) - if err != nil { - return fmt.Errorf("unable to expand steps in pipeline configuration for %s: %w", repoName(ctx), err) - } - - if substituteEnv { - // inject the substituted environment variables into the steps - pipeline.Steps, err = comp.SubstituteSteps(pipeline.Steps) - if err != nil { - return fmt.Errorf("unable to substitute steps in pipeline configuration for %s: %w", repoName(ctx), err) - } - } - } - - return nil -} diff --git a/compiler/engine.go b/compiler/engine.go index 96b29696e..f8795dd50 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -22,13 +22,18 @@ type Engine interface { // Parse internally to convert the object to a yaml configuration. Compile(interface{}) (*pipeline.Build, error) + // CompileLite defines a function that produces an light executable + // representation of a pipeline from an object. This calls + // Parse internally to convert the object to a yaml configuration. + CompileLite(interface{}, bool, bool) (*yaml.Build, error) + // Duplicate defines a function that // creates a clone of the Engine. Duplicate() Engine // Parse defines a function that converts // an object to a yaml configuration. - Parse(interface{}) (*yaml.Build, error) + Parse(interface{}, string, map[string]interface{}) (*yaml.Build, error) // ParseRaw defines a function that converts // an object to a string. @@ -66,12 +71,10 @@ type Engine interface { // ExpandStages defines a function that injects the template // for each templated step in every stage in a yaml configuration. - - ExpandStages(*yaml.Build, map[string]*yaml.Template) (yaml.StageSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) + ExpandStages(*yaml.Build, map[string]*yaml.Template) (*yaml.Build, error) // ExpandSteps defines a function that injects the template // for each templated step in a yaml configuration. - - ExpandSteps(*yaml.Build, map[string]*yaml.Template) (yaml.StepSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) + ExpandSteps(*yaml.Build, map[string]*yaml.Template) (*yaml.Build, error) // Init Compiler Interface Functions diff --git a/compiler/native/compile.go b/compiler/native/compile.go index c58146315..7d8e41d51 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -14,6 +14,8 @@ import ( "strings" "time" + "github.com/go-vela/types/constants" + yml "github.com/buildkite/yaml" "github.com/go-vela/types/library" @@ -39,10 +41,8 @@ type ModifyResponse struct { } // Compile produces an executable pipeline from a yaml configuration. -// -// nolint: gocyclo,funlen // ignore function length due to comments func (c *client) Compile(v interface{}) (*pipeline.Build, error) { - p, err := c.Parse(v) + p, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) if err != nil { return nil, err } @@ -54,7 +54,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { } // create map of templates for easy lookup - tmpls := mapFromTemplates(p.Templates) + templates := mapFromTemplates(p.Templates) // create the ruledata to purge steps r := &pipeline.RuleData{ @@ -67,93 +67,178 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { Target: c.build.GetDeploy(), } - if len(p.Stages) > 0 { - // check if the pipeline disabled the clone - if p.Metadata.Clone == nil || *p.Metadata.Clone { - // inject the clone stage - p, err = c.CloneStage(p) - if err != nil { - return nil, err - } - } - - // inject the init stage - p, err = c.InitStage(p) + switch { + case p.Metadata.RenderInline: + newPipeline, err := c.compileInline(p) if err != nil { return nil, err } - - // inject the templates into the stages - p.Stages, p.Secrets, p.Services, p.Environment, err = c.ExpandStages(p, tmpls) + // validate the yaml configuration + err = c.Validate(newPipeline) if err != nil { return nil, err } - if c.ModificationService.Endpoint != "" { - // send config to external endpoint for modification - p, err = c.modifyConfig(p, c.build, c.repo) - if err != nil { - return nil, err - } + if len(newPipeline.Stages) > 0 { + return c.compileStages(newPipeline, map[string]*yaml.Template{}, r) } + return c.compileSteps(newPipeline, map[string]*yaml.Template{}, r) + case len(p.Stages) > 0: + return c.compileStages(p, templates, r) + default: + return c.compileSteps(p, templates, r) + } +} + +// CompileLite produces a partial of an executable pipeline from a yaml configuration. +func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Build, error) { + p, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) + if err != nil { + return nil, err + } + + if p.Metadata.RenderInline { + newPipeline, err := c.compileInline(p) + if err != nil { + return nil, err + } // validate the yaml configuration - err = c.Validate(p) + err = c.Validate(newPipeline) if err != nil { return nil, err } - // Create some default global environment inject vars - // these are used below to overwrite to an empty - // map if they should not be injected into a container - envGlobalServices, envGlobalSecrets, envGlobalSteps := p.Environment, p.Environment, p.Environment + p = newPipeline + } - if !p.Metadata.HasEnvironment("services") { - envGlobalServices = make(raw.StringSliceMap) - } + if template { + // create map of templates for easy lookup + templates := mapFromTemplates(p.Templates) - if !p.Metadata.HasEnvironment("secrets") { - envGlobalSecrets = make(raw.StringSliceMap) - } + switch { + case len(p.Stages) > 0: + // inject the templates into the steps + p, err = c.ExpandStages(p, templates) + if err != nil { + return nil, err + } - if !p.Metadata.HasEnvironment("steps") { - envGlobalSteps = make(raw.StringSliceMap) + if substitute { + // inject the substituted environment variables into the steps + p.Stages, err = c.SubstituteStages(p.Stages) + if err != nil { + return nil, err + } + } + case len(p.Steps) > 0: + // inject the templates into the steps + p, err = c.ExpandSteps(p, templates) + if err != nil { + return nil, err + } + + if substitute { + // inject the substituted environment variables into the steps + p.Steps, err = c.SubstituteSteps(p.Steps) + if err != nil { + return nil, err + } + } } + } - // inject the environment variables into the services - p.Services, err = c.EnvironmentServices(p.Services, envGlobalServices) + // validate the yaml configuration + err = c.Validate(p) + if err != nil { + return nil, err + } + + return p, nil +} + +// compileInline parses and expands out inline pipelines. +func (c *client) compileInline(p *yaml.Build) (*yaml.Build, error) { + newPipeline := *p + newPipeline.Templates = yaml.TemplateSlice{} + + for _, template := range p.Templates { + bytes, err := c.getTemplate(template, template.Name) if err != nil { return nil, err } - // inject the environment variables into the secrets - p.Secrets, err = c.EnvironmentSecrets(p.Secrets, envGlobalSecrets) - if err != nil { - return nil, err + format := template.Format + // set the default format to golang if the user did not define anything + if template.Format == "" { + format = constants.PipelineTypeGo } - // inject the environment variables into the stages - p.Stages, err = c.EnvironmentStages(p.Stages, envGlobalSteps) + parsed, err := c.Parse(bytes, format, template.Variables) if err != nil { return nil, err } - // inject the substituted environment variables into the stages - p.Stages, err = c.SubstituteStages(p.Stages) - if err != nil { - return nil, err + switch { + case len(parsed.Environment) > 0: + for key, value := range parsed.Environment { + newPipeline.Environment[key] = value + } + + fallthrough + case len(parsed.Stages) > 0: + // ensure all templated steps inside stages have template prefix + for stgIndex, newStage := range parsed.Stages { + parsed.Stages[stgIndex].Name = fmt.Sprintf("%s_%s", template.Name, newStage.Name) + + for index, newStep := range newStage.Steps { + parsed.Stages[stgIndex].Steps[index].Name = fmt.Sprintf("%s_%s", template.Name, newStep.Name) + } + } + + newPipeline.Stages = append(newPipeline.Stages, parsed.Stages...) + + fallthrough + case len(parsed.Steps) > 0: + // ensure all templated steps have template prefix + for index, newStep := range parsed.Steps { + parsed.Steps[index].Name = fmt.Sprintf("%s_%s", template.Name, newStep.Name) + } + + newPipeline.Steps = append(newPipeline.Steps, parsed.Steps...) + + fallthrough + case len(parsed.Services) > 0: + newPipeline.Services = append(newPipeline.Services, parsed.Services...) + fallthrough + case len(parsed.Secrets) > 0: + newPipeline.Secrets = append(newPipeline.Secrets, parsed.Secrets...) + default: + // nolint: lll // ignore long line length due to error message + return nil, fmt.Errorf("empty template %s provided: template must contain secrets, services, stages or steps", template.Name) } - // inject the scripts into the stages - p.Stages, err = c.ScriptStages(p.Stages) - if err != nil { - return nil, err + if len(newPipeline.Stages) > 0 && len(newPipeline.Steps) > 0 { + // nolint: lll // ignore long line length due to error message + return nil, fmt.Errorf("invalid template %s provided: templates cannot mix stages and steps", template.Name) } + } - // return executable representation - return c.TransformStages(r, p) + // validate the yaml configuration + err := c.Validate(&newPipeline) + if err != nil { + return nil, err } + return &newPipeline, nil +} + +// compileSteps executes the workflow for converting a YAML pipeline into an executable struct. +// +// nolint:dupl,lll // linter thinks the steps and stages workflows are identical +func (c *client) compileSteps(p *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, error) { + var err error + // check if the pipeline disabled the clone if p.Metadata.Clone == nil || *p.Metadata.Clone { // inject the clone step @@ -170,7 +255,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { } // inject the templates into the steps - p.Steps, p.Secrets, p.Services, p.Environment, err = c.ExpandSteps(p, tmpls) + p, err = c.ExpandSteps(p, tmpls) if err != nil { return nil, err } @@ -240,6 +325,98 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { return c.TransformSteps(r, p) } +// compileStages executes the workflow for converting a YAML pipeline into an executable struct. +// +// nolint:dupl,lll // linter thinks the steps and stages workflows are identical +func (c *client) compileStages(p *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, error) { + var err error + + // check if the pipeline disabled the clone + if p.Metadata.Clone == nil || *p.Metadata.Clone { + // inject the clone stage + p, err = c.CloneStage(p) + if err != nil { + return nil, err + } + } + + // inject the init stage + p, err = c.InitStage(p) + if err != nil { + return nil, err + } + + // inject the templates into the stages + p, err = c.ExpandStages(p, tmpls) + if err != nil { + return nil, err + } + + if c.ModificationService.Endpoint != "" { + // send config to external endpoint for modification + p, err = c.modifyConfig(p, c.build, c.repo) + if err != nil { + return nil, err + } + } + + // validate the yaml configuration + err = c.Validate(p) + if err != nil { + return nil, err + } + + // Create some default global environment inject vars + // these are used below to overwrite to an empty + // map if they should not be injected into a container + envGlobalServices, envGlobalSecrets, envGlobalSteps := p.Environment, p.Environment, p.Environment + + if !p.Metadata.HasEnvironment("services") { + envGlobalServices = make(raw.StringSliceMap) + } + + if !p.Metadata.HasEnvironment("secrets") { + envGlobalSecrets = make(raw.StringSliceMap) + } + + if !p.Metadata.HasEnvironment("steps") { + envGlobalSteps = make(raw.StringSliceMap) + } + + // inject the environment variables into the services + p.Services, err = c.EnvironmentServices(p.Services, envGlobalServices) + if err != nil { + return nil, err + } + + // inject the environment variables into the secrets + p.Secrets, err = c.EnvironmentSecrets(p.Secrets, envGlobalSecrets) + if err != nil { + return nil, err + } + + // inject the environment variables into the stages + p.Stages, err = c.EnvironmentStages(p.Stages, envGlobalSteps) + if err != nil { + return nil, err + } + + // inject the substituted environment variables into the stages + p.Stages, err = c.SubstituteStages(p.Stages) + if err != nil { + return nil, err + } + + // inject the scripts into the stages + p.Stages, err = c.ScriptStages(p.Stages) + if err != nil { + return nil, err + } + + // return executable representation + return c.TransformStages(r, p) +} + // errorHandler ensures the error contains the number of request attempts. func errorHandler(resp *http.Response, err error, attempts int) (*http.Response, error) { if err != nil { diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index a9a742250..b6befc253 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -10,7 +10,13 @@ import ( "io/ioutil" "net/http" "net/http/httptest" - "reflect" + "path/filepath" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/raw" + + "github.com/google/go-github/v42/github" + "testing" "time" @@ -1129,73 +1135,8 @@ func TestNative_Compile_InvalidType(t *testing.T) { dockerEnv["PARAMETER_REPO"] = "github/octocat" dockerEnv["PARAMETER_TAGS"] = "latest,dev" - want := &pipeline.Build{ - Version: "1", - ID: "__0", - Metadata: pipeline.Metadata{ - Clone: true, - Template: false, - Environment: []string{"steps", "services", "secrets"}, - }, - Steps: pipeline.ContainerSlice{ - &pipeline.Container{ - ID: "step___0_init", - Directory: "/vela/src/foo//", - Environment: environment(nil, m, nil, nil), - Image: "#init", - Name: "init", - Number: 1, - Pull: "not_present", - }, - &pipeline.Container{ - ID: "step___0_clone", - Directory: "/vela/src/foo//", - Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.5.1", - Name: "clone", - Number: 2, - Pull: "not_present", - }, - &pipeline.Container{ - ID: "step___0_docker", - Directory: "/vela/src/foo//", - Image: "plugins/docker:18.09", - Environment: dockerEnv, - Name: "docker", - Number: 3, - Pull: "always", - Secrets: pipeline.StepSecretSlice{ - &pipeline.StepSecret{ - Source: "docker_username", - Target: "registry_username", - }, - &pipeline.StepSecret{ - Source: "docker_password", - Target: "registry_password", - }, - }, - }, - }, - Secrets: pipeline.SecretSlice{ - &pipeline.Secret{ - Name: "docker_username", - Key: "org/repo/docker/username", - Engine: "native", - Type: "repo", - Origin: &pipeline.Container{}, - }, - &pipeline.Secret{ - Name: "docker_password", - Key: "org/repo/docker/password", - Engine: "vault", - Type: "repo", - Origin: &pipeline.Container{}, - }, - }, - } - // run test - yaml, err := ioutil.ReadFile("testdata/invalid_type.yml") + invalidYaml, err := ioutil.ReadFile("testdata/invalid_type.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1207,13 +1148,9 @@ func TestNative_Compile_InvalidType(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) - if err != nil { - t.Errorf("Compile returned err: %v", err) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Compile is %v, want %v", got, want) + _, err = compiler.Compile(invalidYaml) + if err == nil { + t.Error("Compile should have returned an err") } } @@ -1930,3 +1867,1124 @@ func Test_client_modifyConfig(t *testing.T) { }) } } + +func convertFileToGithubResponse(file string) (github.RepositoryContent, error) { + body, err := ioutil.ReadFile(filepath.Join("testdata", file)) + if err != nil { + return github.RepositoryContent{}, err + } + + content := github.RepositoryContent{ + Encoding: github.String(""), + Content: github.String(string(body)), + } + + return content, nil +} + +func generateTestEnv(command string, m *types.Metadata, pipelineType string) map[string]string { + output := environment(nil, m, nil, nil) + output["VELA_BUILD_SCRIPT"] = generateScriptPosix([]string{command}) + output["HOME"] = "/root" + output["SHELL"] = "/bin/sh" + output["VELA_REPO_PIPELINE_TYPE"] = pipelineType + + return output +} + +func Test_Compile_Inline(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + c := cli.NewContext(nil, set, nil) + + m := &types.Metadata{ + Database: &types.Database{ + Driver: "foo", + Host: "foo", + }, + Queue: &types.Queue{ + Channel: "foo", + Driver: "foo", + Host: "foo", + }, + Source: &types.Source{ + Driver: "foo", + Host: "foo", + }, + Vela: &types.Vela{ + Address: "foo", + WebAddress: "foo", + }, + } + + initEnv := environment(nil, m, nil, nil) + testEnv := environment(nil, m, nil, nil) + testEnv["FOO"] = "Hello, foo!" + testEnv["HELLO"] = "Hello, Vela!" + stepEnv := environment(nil, m, nil, nil) + stepEnv["FOO"] = "Hello, foo!" + stepEnv["HELLO"] = "Hello, Vela!" + stepEnv["PARAMETER_FIRST"] = "foo" + golangEnv := environment(nil, m, nil, nil) + golangEnv["VELA_REPO_PIPELINE_TYPE"] = "go" + + type args struct { + file string + pipelineType string + } + + tests := []struct { + name string + args args + want *pipeline.Build + wantErr bool + }{ + { + name: "root stages", + args: args{ + file: "testdata/inline_with_stages.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Stages: []*pipeline.Stage{ + { + Name: "init", + Environment: initEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_init_init", + Directory: "/vela/src/foo//", + Environment: initEnv, + Image: "#init", + Name: "init", + Number: 1, + Pull: "not_present", + }, + }, + }, + { + Name: "clone", + Environment: initEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_clone_clone", + Directory: "/vela/src/foo//", + Environment: initEnv, + Image: "target/vela-git:v0.5.1", + Name: "clone", + Number: 2, + Pull: "not_present", + }, + }, + }, + { + Name: "test", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_test_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline", m, ""), + Image: "alpine", + Name: "test", + Pull: "not_present", + Number: 3, + }, + }, + }, + { + Name: "golang_foo", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_foo_golang_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, ""), + Image: "golang:1.17", + Name: "golang_foo", + Pull: "not_present", + Number: 4, + }, + }, + }, + { + Name: "golang_bar", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_bar_golang_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, ""), + Image: "golang:1.17", + Name: "golang_bar", + Pull: "not_present", + Number: 5, + }, + }, + }, + { + Name: "golang_star", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_star_golang_star", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from star", m, ""), + Image: "golang:1.17", + Name: "golang_star", + Pull: "not_present", + Number: 6, + }, + }, + }, + { + Name: "starlark_foo", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_starlark_foo_starlark_build_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, ""), + Image: "alpine", + Name: "starlark_build_foo", + Pull: "not_present", + Number: 7, + }, + }, + }, + { + Name: "starlark_bar", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_starlark_bar_starlark_build_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, ""), + Image: "alpine", + Name: "starlark_build_bar", + Pull: "not_present", + Number: 8, + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "root steps", + args: args{ + file: "testdata/inline_with_steps.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: []*pipeline.Container{ + { + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "init", + Image: "#init", + Number: 1, + Pull: "not_present", + }, + { + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "clone", + Image: "target/vela-git:v0.5.1", + Number: 2, + Pull: "not_present", + }, + { + ID: "step___0_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo from inline", m, ""), + Name: "test", + Image: "alpine", + Number: 3, + Pull: "not_present", + }, + { + ID: "step___0_golang_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo hello from foo", m, ""), + Name: "golang_foo", + Image: "alpine", + Number: 4, + Pull: "not_present", + }, + { + ID: "step___0_golang_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo hello from bar", m, ""), + Name: "golang_bar", + Image: "alpine", + Number: 5, + Pull: "not_present", + }, + { + ID: "step___0_golang_star", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo hello from star", m, ""), + Name: "golang_star", + Image: "alpine", + Number: 6, + Pull: "not_present", + }, + { + ID: "step___0_starlark_build_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo hello from foo", m, ""), + Name: "starlark_build_foo", + Image: "alpine", + Number: 7, + Pull: "not_present", + }, + { + ID: "step___0_starlark_build_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo hello from bar", m, ""), + Name: "starlark_build_bar", + Image: "alpine", + Number: 8, + Pull: "not_present", + }, + }, + }, + }, + { + name: "stages and steps", + args: args{ + file: "testdata/inline_with_stages_and_steps.yml", + }, + want: nil, + wantErr: true, + }, + { + name: "secrets", + args: args{ + file: "testdata/inline_with_secrets.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: []*pipeline.Container{ + { + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "init", + Image: "#init", + Number: 1, + Pull: "not_present", + }, + { + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "clone", + Image: "target/vela-git:v0.5.1", + Number: 2, + Pull: "not_present", + }, + { + ID: "step___0_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo from inline", m, ""), + Name: "test", + Image: "alpine", + Number: 3, + Pull: "not_present", + }, + }, + Secrets: pipeline.SecretSlice{ + &pipeline.Secret{ + Name: "foo_username", + Key: "org/repo/foo/username", + Engine: "native", + Type: "repo", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_username", + Key: "org/repo/docker/username", + Engine: "native", + Type: "repo", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_password", + Key: "org/repo/docker/password", + Engine: "vault", + Type: "repo", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_username", + Key: "org/docker/username", + Engine: "native", + Type: "org", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_password", + Key: "org/docker/password", + Engine: "vault", + Type: "org", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_username", + Key: "org/team/docker/username", + Engine: "native", + Type: "shared", + Origin: &pipeline.Container{}, + }, + &pipeline.Secret{ + Name: "docker_password", + Key: "org/team/docker/password", + Engine: "vault", + Type: "shared", + Origin: &pipeline.Container{}, + }, + }, + }, + wantErr: false, + }, + { + name: "services", + args: args{ + file: "testdata/inline_with_services.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: []*pipeline.Container{ + { + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "init", + Image: "#init", + Number: 1, + Pull: "not_present", + }, + { + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: initEnv, + Name: "clone", + Image: "target/vela-git:v0.5.1", + Number: 2, + Pull: "not_present", + }, + { + ID: "step___0_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Directory: "/vela/src/foo//", + Environment: generateTestEnv("echo from inline", m, ""), + Name: "test", + Image: "alpine", + Number: 3, + Pull: "not_present", + }, + }, + Services: []*pipeline.Container{ + { + ID: "service___0_postgres", + Detach: true, + Environment: initEnv, + Image: "postgres:latest", + Name: "postgres", + Number: 1, + Pull: "not_present", + }, + { + ID: "service___0_cache", + Detach: true, + Environment: initEnv, + Image: "redis", + Name: "cache", + Number: 2, + Pull: "not_present", + }, + { + ID: "service___0_database", + Detach: true, + Environment: initEnv, + Image: "mongo", + Name: "database", + Number: 3, + Pull: "not_present", + }, + }, + }, + wantErr: false, + }, + { + name: "environment", + args: args{ + file: "testdata/inline_with_environment.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: []*pipeline.Container{ + { + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: testEnv, + Name: "init", + Image: "#init", + Number: 1, + Pull: "not_present", + }, + { + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: testEnv, + Name: "clone", + Image: "target/vela-git:v0.5.1", + Number: 2, + Pull: "not_present", + }, + { + ID: "step___0_test", + Directory: "/vela/src/foo//", + Environment: stepEnv, + Name: "test", + Image: "alpine", + Number: 3, + Pull: "not_present", + }, + }, + }, + }, + { + name: "golang base", + args: args{ + file: "testdata/inline_with_golang.yml", + pipelineType: constants.PipelineTypeGo, + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Stages: []*pipeline.Stage{ + { + Name: "init", + Environment: golangEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_init_init", + Directory: "/vela/src/foo//", + Environment: golangEnv, + Image: "#init", + Name: "init", + Number: 1, + Pull: "not_present", + }, + }, + }, + { + Name: "clone", + Environment: golangEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_clone_clone", + Directory: "/vela/src/foo//", + Environment: golangEnv, + Image: "target/vela-git:v0.5.1", + Name: "clone", + Number: 2, + Pull: "not_present", + }, + }, + }, + { + Name: "foo", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_foo_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline foo", m, constants.PipelineTypeGo), + Image: "alpine", + Name: "foo", + Pull: "not_present", + Number: 3, + }, + }, + }, + { + Name: "bar", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_bar_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline bar", m, constants.PipelineTypeGo), + Image: "alpine", + Name: "bar", + Pull: "not_present", + Number: 4, + }, + }, + }, + { + Name: "star", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_star_star", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline star", m, constants.PipelineTypeGo), + Image: "alpine", + Name: "star", + Pull: "not_present", + Number: 5, + }, + }, + }, + { + Name: "golang_foo", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_foo_golang_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, constants.PipelineTypeGo), + Image: "golang:1.17", + Name: "golang_foo", + Pull: "not_present", + Number: 6, + }, + }, + }, + { + Name: "golang_bar", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_bar_golang_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, constants.PipelineTypeGo), + Image: "golang:1.17", + Name: "golang_bar", + Pull: "not_present", + Number: 7, + }, + }, + }, + { + Name: "golang_star", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_golang_star_golang_star", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from star", m, constants.PipelineTypeGo), + Image: "golang:1.17", + Name: "golang_star", + Pull: "not_present", + Number: 8, + }, + }, + }, + { + Name: "starlark_foo", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_starlark_foo_starlark_build_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, constants.PipelineTypeGo), + Image: "alpine", + Name: "starlark_build_foo", + Pull: "not_present", + Number: 9, + }, + }, + }, + { + Name: "starlark_bar", + Needs: []string{"clone"}, + Environment: golangEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_starlark_bar_starlark_build_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, constants.PipelineTypeGo), + Image: "alpine", + Name: "starlark_build_bar", + Pull: "not_present", + Number: 10, + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + yaml, err := ioutil.ReadFile(tt.args.file) + if err != nil { + t.Errorf("Reading yaml file return err: %v", err) + } + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } + + compiler.WithMetadata(m) + + if tt.args.pipelineType != "" { + compiler.WithRepo(&library.Repo{PipelineType: &tt.args.pipelineType}) + } + + got, err := compiler.Compile(yaml) + if (err != nil) != tt.wantErr { + t.Errorf("Compile() error = %v, wantErr %v", err, tt.wantErr) + return + } + + // WARNING: hack to compare stages + // + // Channel values can only be compared for equality. + // Two channel values are considered equal if they + // originated from the same make call meaning they + // refer to the same channel value in memory. + if got != nil { + for i, stage := range got.Stages { + tmp := tt.want.Stages + + tmp[i].Done = stage.Done + } + } + + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("Compile() mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func Test_CompileLite(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + c := cli.NewContext(nil, set, nil) + + m := &types.Metadata{ + Database: &types.Database{ + Driver: "foo", + Host: "foo", + }, + Queue: &types.Queue{ + Channel: "foo", + Driver: "foo", + Host: "foo", + }, + Source: &types.Source{ + Driver: "foo", + Host: "foo", + }, + Vela: &types.Vela{ + Address: "foo", + WebAddress: "foo", + }, + } + + type args struct { + file string + pipelineType string + template bool + substitute bool + } + + tests := []struct { + name string + args args + want *yaml.Build + wantErr bool + }{ + { + name: "render_inline with stages", + args: args{ + file: "testdata/inline_with_stages.yml", + pipelineType: "", + template: true, + substitute: true, + }, + want: &yaml.Build{ + Version: "1", + Metadata: yaml.Metadata{ + RenderInline: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Templates: []*yaml.Template{}, + Stages: []*yaml.Stage{ + { + Name: "test", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo from inline"}, + Image: "alpine", + Name: "test", + Pull: "not_present", + }, + }, + }, + { + Name: "golang_foo", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from foo"}, + Image: "golang:1.17", + Name: "golang_foo", + Pull: "not_present", + }, + }, + }, + { + Name: "golang_bar", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from bar"}, + Image: "golang:1.17", + Name: "golang_bar", + Pull: "not_present", + }, + }, + }, + { + Name: "golang_star", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from star"}, + Image: "golang:1.17", + Name: "golang_star", + Pull: "not_present", + }, + }, + }, + { + Name: "starlark_foo", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from foo"}, + Image: "alpine", + Name: "starlark_build_foo", + Pull: "not_present", + }, + }, + }, + { + Name: "starlark_bar", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from bar"}, + Image: "alpine", + Name: "starlark_build_bar", + Pull: "not_present", + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "render_inline with steps", + args: args{ + file: "testdata/inline_with_steps.yml", + pipelineType: "", + template: true, + substitute: true, + }, + want: &yaml.Build{ + Version: "1", + Metadata: yaml.Metadata{ + RenderInline: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: yaml.StepSlice{ + { + Commands: raw.StringSlice{"echo from inline"}, + Image: "alpine", + Name: "test", + Pull: "not_present", + }, + { + Commands: raw.StringSlice{"echo hello from foo"}, + Image: "alpine", + Name: "golang_foo", + Pull: "not_present", + }, + { + Commands: raw.StringSlice{"echo hello from bar"}, + Image: "alpine", + Name: "golang_bar", + Pull: "not_present", + }, + { + Commands: raw.StringSlice{"echo hello from star"}, + Image: "alpine", + Name: "golang_star", + Pull: "not_present", + }, + { + Commands: raw.StringSlice{"echo hello from foo"}, + Image: "alpine", + Name: "starlark_build_foo", + Pull: "not_present", + }, + { + Commands: raw.StringSlice{"echo hello from bar"}, + Image: "alpine", + Name: "starlark_build_bar", + Pull: "not_present", + }, + }, + Templates: yaml.TemplateSlice{}, + }, + wantErr: false, + }, + { + name: "golang", + args: args{ + file: "testdata/golang_inline_stages.yml", + pipelineType: "golang", + template: false, + substitute: false, + }, + want: &yaml.Build{ + Version: "1", + Metadata: yaml.Metadata{ + Environment: []string{"steps", "services", "secrets"}, + }, + Stages: []*yaml.Stage{ + { + Name: "foo", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from foo"}, + Image: "alpine", + Name: "foo", + Pull: "not_present", + }, + }, + }, + { + Name: "bar", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from bar"}, + Image: "alpine", + Name: "bar", + Pull: "not_present", + }, + }, + }, + { + Name: "star", + Needs: []string{"clone"}, + Steps: []*yaml.Step{ + { + Commands: raw.StringSlice{"echo hello from star"}, + Image: "alpine", + Name: "star", + Pull: "not_present", + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "step with template", + args: args{ + file: "testdata/step_inline_template.yml", + pipelineType: "", + template: false, + substitute: false, + }, + want: nil, + wantErr: true, + }, + { + name: "stage with template", + args: args{ + file: "testdata/stage_inline_template.yml", + pipelineType: "", + template: false, + substitute: false, + }, + want: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } + + compiler.WithMetadata(m) + if tt.args.pipelineType != "" { + compiler.WithRepo(&library.Repo{PipelineType: &tt.args.pipelineType}) + } + + yaml, err := ioutil.ReadFile(tt.args.file) + if err != nil { + t.Errorf("Reading yaml file return err: %v", err) + } + + got, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute) + if (err != nil) != tt.wantErr { + t.Errorf("CompileLite() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("CompileLite() mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index 151abaa8a..f638f41ea 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -219,8 +219,8 @@ func TestNative_EnvironmentSteps(t *testing.T) { t.Errorf("EnvironmentSteps returned err: %v", err) } - if !reflect.DeepEqual(got, want) { - t.Errorf("EnvironmentSteps is %v, want %v", got, want) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("EnvironmentSteps mismatch (-want +got):\n%s", diff) } } @@ -366,8 +366,8 @@ func TestNative_EnvironmentServices(t *testing.T) { t.Errorf("EnvironmentServices returned err: %v", err) } - if !reflect.DeepEqual(got, want) { - t.Errorf("EnvironmentServices is %v, want %v", got, want) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("EnvironmentServices mismatch (-want +got):\n%s", diff) } } @@ -526,8 +526,8 @@ func TestNative_EnvironmentSecrets(t *testing.T) { t.Errorf("EnvironmentSecrets returned err: %v", err) } - if !reflect.DeepEqual(got, want) { - t.Errorf("EnvironmentSecrets is %v, want %v", got, want) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("EnvironmentSecrets mismatch (-want +got):\n%s", diff) } } @@ -600,8 +600,8 @@ func TestNative_environment(t *testing.T) { for _, test := range tests { got := environment(test.b, test.m, test.r, test.u) - if !reflect.DeepEqual(got, test.want) { - t.Errorf("environment is %v, want %v", got, test.want) + if diff := cmp.Diff(got, test.want); diff != "" { + t.Errorf("environment mismatch (-want +got):\n%s", diff) } } } @@ -710,8 +710,9 @@ func Test_client_EnvironmentBuild(t *testing.T) { repo: tt.fields.repo, user: tt.fields.user, } - if got := c.EnvironmentBuild(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("EnvironmentBuild() = %v, want %v", got, tt.want) + got := c.EnvironmentBuild() + if diff := cmp.Diff(got, tt.want); diff != "" { + t.Errorf("EnvironmentBuild mismatch (-want +got):\n%s", diff) } }) } diff --git a/compiler/native/expand.go b/compiler/native/expand.go index 14d6aac35..e6a8bcdd8 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -8,6 +8,8 @@ import ( "fmt" "strings" + "github.com/go-vela/types/constants" + "github.com/go-vela/server/compiler/template/native" "github.com/go-vela/server/compiler/template/starlark" "github.com/spf13/afero" @@ -19,29 +21,35 @@ import ( // ExpandStages injects the template for each // templated step in every stage in a yaml configuration. -func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (yaml.StageSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) { +func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (*yaml.Build, error) { + if len(tmpls) == 0 { + return s, nil + } + // iterate through all stages for _, stage := range s.Stages { // inject the templates into the steps for the stage - steps, secrets, services, environment, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls) + p, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls) if err != nil { - return nil, nil, nil, nil, err + return nil, err } - stage.Steps = steps - s.Secrets = secrets - s.Services = services - s.Environment = environment + stage.Steps = p.Steps + s.Secrets = p.Secrets + s.Services = p.Services + s.Environment = p.Environment } - return s.Stages, s.Secrets, s.Services, s.Environment, nil + return s, nil } // ExpandSteps injects the template for each // templated step in a yaml configuration. -// -// nolint: funlen,gocyclo // ignore long line length due to variable names -func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (yaml.StepSlice, yaml.SecretSlice, yaml.ServiceSlice, raw.StringSliceMap, error) { +func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (*yaml.Build, error) { + if len(tmpls) == 0 { + return s, nil + } + steps := yaml.StepSlice{} secrets := s.Secrets services := s.Services @@ -53,9 +61,6 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // iterate through each step for _, step := range s.Steps { - // nolint: ineffassign,staticcheck // ignore ineffectual assignment - bytes := []byte{} - // skip if no template is provided for the step if len(step.Template.Name) == 0 { // add existing step if no template @@ -66,7 +71,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // lookup step template name tmpl, ok := tmpls[step.Template.Name] if !ok { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("missing template source for template %s in pipeline for step %s", step.Template.Name, step.Name) + return s, fmt.Errorf("missing template source for template %s in pipeline for step %s", step.Template.Name, step.Name) } // Create some default global environment inject vars @@ -81,86 +86,21 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya // inject environment information for template step, err := c.EnvironmentStep(step, envGlobalSteps) if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err + return s, err } - switch { - case c.local: - a := &afero.Afero{ - Fs: afero.NewOsFs(), - } - - bytes, err = a.ReadFile(tmpl.Source) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err - } - - case strings.EqualFold(tmpl.Type, "github"): - // parse source from template - src, err := c.Github.Parse(tmpl.Source) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("invalid template source provided for %s: %w", step.Template.Name, err) - } - - // pull from github without auth when the host isn't provided or is set to github.com - if !c.UsePrivateGithub && (len(src.Host) == 0 || strings.Contains(src.Host, "github.com")) { - logrus.WithFields(logrus.Fields{ - "org": src.Org, - "repo": src.Repo, - "path": src.Name, - "host": src.Host, - }).Tracef("Using GitHub client to pull template") - - bytes, err = c.Github.Template(nil, src) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err - } - } else { - logrus.WithFields(logrus.Fields{ - "org": src.Org, - "repo": src.Repo, - "path": src.Name, - "host": src.Host, - }).Tracef("Using authenticated GitHub client to pull template") - // use private (authenticated) github instance to pull from - bytes, err = c.PrivateGithub.Template(c.user, src) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err - } - } - - default: - logrus.Errorf("Unsupported template type: %v", tmpl.Type) - continue + bytes, err := c.getTemplate(tmpl, step.Template.Name) + if err != nil { + return s, err } - var ( - tmplSteps yaml.StepSlice - tmplSecrets yaml.SecretSlice - tmplServices yaml.ServiceSlice - tmplEnvironment raw.StringSliceMap - ) - - // TODO: provide friendlier error messages with file type mismatches - switch tmpl.Format { - case "go", "golang", "": - // render template for steps - tmplSteps, tmplSecrets, tmplServices, tmplEnvironment, err = native.RenderStep(string(bytes), step) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err - } - case "starlark": - // render template for steps - tmplSteps, tmplSecrets, tmplServices, tmplEnvironment, err = starlark.RenderStep(string(bytes), step) - if err != nil { - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, err - } - default: - return yaml.StepSlice{}, yaml.SecretSlice{}, yaml.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("format of %s is unsupported", tmpl.Format) + tmplBuild, err := c.mergeTemplate(bytes, tmpl, step) + if err != nil { + return s, err } // loop over secrets within template - for _, secret := range tmplSecrets { + for _, secret := range tmplBuild.Secrets { found := false // loop over secrets within base configuration for _, sec := range secrets { @@ -177,7 +117,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya } // loop over services within template - for _, service := range tmplServices { + for _, service := range tmplBuild.Services { found := false for _, serv := range services { @@ -193,7 +133,7 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya } // loop over environment within template - for key, value := range tmplEnvironment { + for key, value := range tmplBuild.Environment { found := false for env := range environment { @@ -209,10 +149,89 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (ya } // add templated steps - steps = append(steps, tmplSteps...) + steps = append(steps, tmplBuild.Steps...) } - return steps, secrets, services, environment, nil + s.Steps = steps + s.Secrets = secrets + s.Services = services + s.Environment = environment + + return s, nil +} + +func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) { + var ( + bytes []byte + err error + ) + + switch { + case c.local: + a := &afero.Afero{ + Fs: afero.NewOsFs(), + } + + bytes, err = a.ReadFile(tmpl.Source) + if err != nil { + return bytes, err + } + + case strings.EqualFold(tmpl.Type, "github"): + // parse source from template + src, err := c.Github.Parse(tmpl.Source) + if err != nil { + return bytes, fmt.Errorf("invalid template source provided for %s: %w", name, err) + } + + // pull from github without auth when the host isn't provided or is set to github.com + if !c.UsePrivateGithub && (len(src.Host) == 0 || strings.Contains(src.Host, "github.com")) { + logrus.WithFields(logrus.Fields{ + "org": src.Org, + "repo": src.Repo, + "path": src.Name, + "host": src.Host, + }).Tracef("Using GitHub client to pull template") + + bytes, err = c.Github.Template(nil, src) + if err != nil { + return bytes, err + } + } else { + logrus.WithFields(logrus.Fields{ + "org": src.Org, + "repo": src.Repo, + "path": src.Name, + "host": src.Host, + }).Tracef("Using authenticated GitHub client to pull template") + + // use private (authenticated) github instance to pull from + bytes, err = c.PrivateGithub.Template(c.user, src) + if err != nil { + return bytes, err + } + } + + default: + return bytes, fmt.Errorf("unsupported template type: %v", tmpl.Type) + } + + return bytes, nil +} + +// nolint: lll // ignore long line length due to input arguments +func (c *client) mergeTemplate(bytes []byte, tmpl *yaml.Template, step *yaml.Step) (*yaml.Build, error) { + switch tmpl.Format { + case constants.PipelineTypeGo, "golang", "": + // nolint: lll // ignore long line length due to return + return native.Render(string(bytes), step.Name, step.Template.Name, step.Environment, step.Template.Variables) + case constants.PipelineTypeStarlark: + // nolint: lll // ignore long line length due to return + return starlark.Render(string(bytes), step.Name, step.Template.Name, step.Environment, step.Template.Variables) + default: + // nolint: lll // ignore long line length due to return + return &yaml.Build{}, fmt.Errorf("format of %s is unsupported", tmpl.Format) + } } // helper function that creates a map of templates from a yaml configuration. diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index 714e9cd59..d4f9f8d7c 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -144,24 +144,24 @@ func TestNative_ExpandStages(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - stages, secrets, services, environment, err := compiler.ExpandStages(&yaml.Build{Stages: stages, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + build, err := compiler.ExpandStages(&yaml.Build{Stages: stages, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) if err != nil { t.Errorf("ExpandStages returned err: %v", err) } - if diff := cmp.Diff(stages, wantStages); diff != "" { + if diff := cmp.Diff(build.Stages, wantStages); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(secrets, wantSecrets); diff != "" { + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(services, wantServices); diff != "" { + if diff := cmp.Diff(build.Services, wantServices); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(environment, wantEnvironment); diff != "" { + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { t.Errorf("ExpandStages() mismatch (-want +got):\n%s", diff) } } @@ -287,24 +287,24 @@ func TestNative_ExpandSteps(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - steps, secrets, services, environment, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, tmpls) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, tmpls) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } - if diff := cmp.Diff(steps, wantSteps); diff != "" { + if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(secrets, wantSecrets); diff != "" { + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(services, wantServices); diff != "" { + if diff := cmp.Diff(build.Services, wantServices); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(environment, wantEnvironment); diff != "" { + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } } @@ -521,24 +521,24 @@ func TestNative_ExpandStepsMulti(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - steps, secrets, services, environment, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } - if diff := cmp.Diff(steps, wantSteps); diff != "" { + if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(secrets, wantSecrets); diff != "" { + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(services, wantServices); diff != "" { + if diff := cmp.Diff(build.Services, wantServices); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(environment, wantEnvironment); diff != "" { + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } } @@ -608,24 +608,24 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - steps, secrets, services, environment, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } - if diff := cmp.Diff(steps, wantSteps); diff != "" { + if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(secrets, wantSecrets); diff != "" { + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(services, wantServices); diff != "" { + if diff := cmp.Diff(build.Services, wantServices); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(environment, wantEnvironment); diff != "" { + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) } } diff --git a/compiler/native/parse.go b/compiler/native/parse.go index a84d6631c..8bca88c41 100644 --- a/compiler/native/parse.go +++ b/compiler/native/parse.go @@ -43,18 +43,18 @@ func (c *client) ParseRaw(v interface{}) (string, error) { } // Parse converts an object to a yaml configuration. -func (c *client) Parse(v interface{}) (*types.Build, error) { +func (c *client) Parse(v interface{}, pipelineType string, variables map[string]interface{}) (*types.Build, error) { var p *types.Build - switch c.repo.GetPipelineType() { - case constants.PipelineTypeGo: + switch pipelineType { + case constants.PipelineTypeGo, "golang": // expand the base configuration parsedRaw, err := c.ParseRaw(v) if err != nil { return nil, err } - p, err = native.RenderBuild(parsedRaw, c.EnvironmentBuild()) + p, err = native.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) if err != nil { return nil, err } @@ -65,7 +65,7 @@ func (c *client) Parse(v interface{}) (*types.Build, error) { return nil, err } - p, err = starlark.RenderBuild(parsedRaw, c.EnvironmentBuild()) + p, err = starlark.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) if err != nil { return nil, err } diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index 909e8d848..bf9b9a3d3 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -41,7 +41,7 @@ func TestNative_Parse_Metadata_Bytes(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -71,7 +71,7 @@ func TestNative_Parse_Metadata_File(t *testing.T) { defer f.Close() - got, err := client.Parse(f) + got, err := client.Parse(f, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -86,7 +86,7 @@ func TestNative_Parse_Metadata_Invalid(t *testing.T) { client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) // run test - got, err := client.Parse(nil) + got, err := client.Parse(nil, "", map[string]interface{}{}) if err == nil { t.Error("Parse should have returned err") @@ -110,7 +110,7 @@ func TestNative_Parse_Metadata_Path(t *testing.T) { } // run test - got, err := client.Parse("testdata/metadata.yml") + got, err := client.Parse("testdata/metadata.yml", "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -138,7 +138,7 @@ func TestNative_Parse_Metadata_Reader(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(bytes.NewReader(b)) + got, err := client.Parse(bytes.NewReader(b), "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -166,7 +166,7 @@ func TestNative_Parse_Metadata_String(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(string(b)) + got, err := client.Parse(string(b), "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -213,7 +213,7 @@ func TestNative_Parse_Parameters(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -339,7 +339,7 @@ func TestNative_Parse_StagesPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -436,7 +436,7 @@ func TestNative_Parse_StepsPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -499,7 +499,7 @@ func TestNative_Parse_Secrets(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -575,7 +575,7 @@ func TestNative_Parse_Stages(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -633,7 +633,7 @@ func TestNative_Parse_Steps(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b) + got, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -887,7 +887,7 @@ func Test_client_Parse(t *testing.T) { {"starlark", args{pipelineType: constants.PipelineTypeStarlark, file: "testdata/pipeline_type.star"}, want, false}, {"go", args{pipelineType: constants.PipelineTypeGo, file: "testdata/pipeline_type_go.yml"}, want, false}, {"empty", args{pipelineType: "", file: "testdata/pipeline_type_default.yml"}, want, false}, - {"nil", args{pipelineType: "nil", file: "testdata/pipeline_type_default.yml"}, want, false}, + {"nil", args{pipelineType: "nil", file: "testdata/pipeline_type_default.yml"}, nil, true}, {"invalid", args{pipelineType: "foo", file: "testdata/pipeline_type_default.yml"}, nil, true}, } @@ -907,7 +907,7 @@ func Test_client_Parse(t *testing.T) { } } - got, err := c.Parse(content) + got, err := c.Parse(content, tt.args.pipelineType, map[string]interface{}{}) if (err != nil) != tt.wantErr { t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/native/testdata/environment.yml b/compiler/native/testdata/environment.yml new file mode 100644 index 000000000..fe6e584e0 --- /dev/null +++ b/compiler/native/testdata/environment.yml @@ -0,0 +1,3 @@ +--- +environment: + FOO: "Hello, foo!" \ No newline at end of file diff --git a/compiler/native/testdata/golang_inline_stages.yml b/compiler/native/testdata/golang_inline_stages.yml new file mode 100644 index 000000000..59b390d47 --- /dev/null +++ b/compiler/native/testdata/golang_inline_stages.yml @@ -0,0 +1,13 @@ +version: "1" + +{{$stageList := list "foo" "bar" "star" -}} + +stages: + {{range $stage := $stageList -}} + {{ $stage }}: + steps: + - name: {{ $stage }} + image: {{ default "alpine" $.image }} + commands: + - echo hello from {{ $stage }} + {{ end }} \ No newline at end of file diff --git a/compiler/native/testdata/golang_inline_steps.yml b/compiler/native/testdata/golang_inline_steps.yml new file mode 100644 index 000000000..1a69da41b --- /dev/null +++ b/compiler/native/testdata/golang_inline_steps.yml @@ -0,0 +1,11 @@ +version: "1" + +{{$stepList := list "foo" "bar" "star" -}} + +steps: + {{range $step := $stepList -}} + - name: {{ $step }} + image: alpine + commands: + - echo hello from {{ $step }} + {{ end }} \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_environment.yml b/compiler/native/testdata/inline_with_environment.yml new file mode 100644 index 000000000..ffdb844fc --- /dev/null +++ b/compiler/native/testdata/inline_with_environment.yml @@ -0,0 +1,19 @@ +version: "1" + +environment: + HELLO: "Hello, Vela!" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/environment.yml + format: golang + type: github + +steps: + - name: test + image: alpine + parameters: + first: "foo" \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_golang.yml b/compiler/native/testdata/inline_with_golang.yml new file mode 100644 index 000000000..4ad50e3d9 --- /dev/null +++ b/compiler/native/testdata/inline_with_golang.yml @@ -0,0 +1,28 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + vars: + image: golang:1.17 + - name: starlark + source: github.example.com/github/octocat/starlark_inline_stages.star + format: starlark + type: github + +{{$stageList := list "foo" "bar" "star" -}} + +stages: + {{range $stage := $stageList -}} + {{ $stage }}: + steps: + - name: {{ $stage }} + image: alpine + commands: + - echo from inline {{ $stage }} + {{ end }} \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_secrets.yml b/compiler/native/testdata/inline_with_secrets.yml new file mode 100644 index 000000000..42ec50464 --- /dev/null +++ b/compiler/native/testdata/inline_with_secrets.yml @@ -0,0 +1,22 @@ +version: "1" + +secrets: + - name: foo_username + key: org/repo/foo/username + engine: native + type: repo + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/secrets.yml + format: golang + type: github + +steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_services.yml b/compiler/native/testdata/inline_with_services.yml new file mode 100644 index 000000000..5ecc71c2b --- /dev/null +++ b/compiler/native/testdata/inline_with_services.yml @@ -0,0 +1,20 @@ +version: "1" + +services: + - name: postgres + image: postgres:latest + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/services.yml + format: golang + type: github + +steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_stages.yml b/compiler/native/testdata/inline_with_stages.yml new file mode 100644 index 000000000..6d808e95d --- /dev/null +++ b/compiler/native/testdata/inline_with_stages.yml @@ -0,0 +1,24 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + vars: + image: golang:1.17 + - name: starlark + source: github.example.com/github/octocat/starlark_inline_stages.star + format: starlark + type: github + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_stages_and_steps.yml b/compiler/native/testdata/inline_with_stages_and_steps.yml new file mode 100644 index 000000000..8a70e12a7 --- /dev/null +++ b/compiler/native/testdata/inline_with_stages_and_steps.yml @@ -0,0 +1,22 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + - name: starlark + source: github.example.com/github/octocat/starlark_inline_steps.star + format: starlark + type: github + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_with_steps.yml b/compiler/native/testdata/inline_with_steps.yml new file mode 100644 index 000000000..28348cf8d --- /dev/null +++ b/compiler/native/testdata/inline_with_steps.yml @@ -0,0 +1,20 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_steps.yml + format: golang + type: github + - name: starlark + source: github.example.com/github/octocat/starlark_inline_steps.star + format: starlark + type: github + +steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/services.yml b/compiler/native/testdata/services.yml new file mode 100644 index 000000000..c4d0288a4 --- /dev/null +++ b/compiler/native/testdata/services.yml @@ -0,0 +1,6 @@ +--- +services: + - name: cache + image: redis + - name: database + image: mongo \ No newline at end of file diff --git a/compiler/native/testdata/stage_inline_template.yml b/compiler/native/testdata/stage_inline_template.yml new file mode 100644 index 000000000..1958bc5b8 --- /dev/null +++ b/compiler/native/testdata/stage_inline_template.yml @@ -0,0 +1,21 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + vars: + image: golang:1.17 + +stages: + test: + steps: + - name: golang + template: + name: golang + vars: + image: golang:latest \ No newline at end of file diff --git a/compiler/native/testdata/starlark_inline_stages.star b/compiler/native/testdata/starlark_inline_stages.star new file mode 100644 index 000000000..55ffee07f --- /dev/null +++ b/compiler/native/testdata/starlark_inline_stages.star @@ -0,0 +1,25 @@ +def main(ctx): + stageNames = ["foo", "bar"] + + stages = {} + + for name in stageNames: + stages[name] = stage(name) + + return { + 'version': '1', + 'stages': stages + } + +def stage(word): + return { + "steps": [ + { + "name": "build_%s" % word, + "image": "alpine", + 'commands': [ + "echo hello from %s" % word + ] + } + ] + } \ No newline at end of file diff --git a/compiler/native/testdata/starlark_inline_steps.star b/compiler/native/testdata/starlark_inline_steps.star new file mode 100644 index 000000000..51a2e6603 --- /dev/null +++ b/compiler/native/testdata/starlark_inline_steps.star @@ -0,0 +1,20 @@ +def main(ctx): + stepNames = ["foo", "bar"] + + steps = [] + + for name in stepNames: + steps.append( + { + "name": "build_%s" % name, + "image": "alpine", + 'commands': [ + "echo hello from %s" % name + ] + } + ) + + return { + 'version': '1', + 'steps': steps + } \ No newline at end of file diff --git a/compiler/native/testdata/step_inline_template.yml b/compiler/native/testdata/step_inline_template.yml new file mode 100644 index 000000000..9df215300 --- /dev/null +++ b/compiler/native/testdata/step_inline_template.yml @@ -0,0 +1,19 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + vars: + image: golang:1.17 + +steps: + - name: golang + template: + name: golang + vars: + image: golang:latest \ No newline at end of file diff --git a/compiler/native/validate.go b/compiler/native/validate.go index c63e65974..dec7c7af9 100644 --- a/compiler/native/validate.go +++ b/compiler/native/validate.go @@ -7,45 +7,64 @@ package native import ( "fmt" + "github.com/hashicorp/go-multierror" + "github.com/go-vela/types/yaml" ) -// Validate verifies the the yaml configuration is valid. +// Validate verifies the yaml configuration is valid. func (c *client) Validate(p *yaml.Build) error { + var result error // check a version is provided if len(p.Version) == 0 { - return fmt.Errorf("no \"version:\" YAML property provided") + result = multierror.Append(result, fmt.Errorf("no \"version:\" YAML property provided")) } // check that stages or steps are provided - if len(p.Stages) == 0 && len(p.Steps) == 0 { - return fmt.Errorf("no stages or steps provided") + if len(p.Stages) == 0 && len(p.Steps) == 0 && (!p.Metadata.RenderInline && len(p.Templates) == 0) { + result = multierror.Append(result, fmt.Errorf("no stages, steps or templates provided")) } // check that stages and steps aren't provided if len(p.Stages) > 0 && len(p.Steps) > 0 { - return fmt.Errorf("stages and steps provided") + result = multierror.Append(result, fmt.Errorf("stages and steps provided")) + } + + if p.Metadata.RenderInline { + for _, step := range p.Steps { + if step.Template.Name != "" { + result = multierror.Append(result, fmt.Errorf("step %s: cannot combine render_inline and a step that references a template", step.Name)) + } + } + + for _, stage := range p.Stages { + for _, step := range stage.Steps { + if step.Template.Name != "" { + result = multierror.Append(result, fmt.Errorf("step %s.%s: cannot combine render_inline and a step that references a template", stage.Name, step.Name)) + } + } + } } // validate the services block provided err := validateServices(p.Services) if err != nil { - return err + result = multierror.Append(result, err) } // validate the stages block provided err = validateStages(p.Stages) if err != nil { - return err + result = multierror.Append(result, err) } // validate the steps block provided err = validateSteps(p.Steps) if err != nil { - return err + result = multierror.Append(result, err) } - return nil + return result } // validateServices is a helper function that verifies the diff --git a/compiler/template/native/render.go b/compiler/template/native/render.go index 265550f02..8066406ec 100644 --- a/compiler/template/native/render.go +++ b/compiler/template/native/render.go @@ -18,13 +18,12 @@ import ( "github.com/buildkite/yaml" ) -// RenderStep combines the template with the step in the yaml pipeline. - -func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, types.ServiceSlice, raw.StringSliceMap, error) { +// Render combines the template with the step in the yaml pipeline. +func Render(tmpl string, name string, tName string, environment raw.StringSliceMap, variables map[string]interface{}) (*types.Build, error) { buffer := new(bytes.Buffer) config := new(types.Build) - velaFuncs := funcHandler{envs: convertPlatformVars(s.Environment, s.Name)} + velaFuncs := funcHandler{envs: convertPlatformVars(environment, name)} templateFuncMap := map[string]interface{}{ "vela": velaFuncs.returnPlatformVar, "toYaml": toYAML, @@ -40,33 +39,33 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // parse the template with Masterminds/sprig functions // // https://pkg.go.dev/github.com/Masterminds/sprig?tab=doc#TxtFuncMap - t, err := template.New(s.Name).Funcs(sf).Funcs(templateFuncMap).Parse(tmpl) + t, err := template.New(name).Funcs(sf).Funcs(templateFuncMap).Parse(tmpl) if err != nil { - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to parse template %s: %w", s.Template.Name, err) + return nil, fmt.Errorf("unable to parse template %s: %w", tName, err) } // apply the variables to the parsed template - err = t.Execute(buffer, s.Template.Variables) + err = t.Execute(buffer, variables) if err != nil { - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to execute template %s: %w", s.Template.Name, err) + return nil, fmt.Errorf("unable to execute template %s: %w", tName, err) } // unmarshal the template to the pipeline err = yaml.Unmarshal(buffer.Bytes(), config) if err != nil { - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %w", err) + return nil, fmt.Errorf("unable to unmarshal yaml: %w", err) } // ensure all templated steps have template prefix for index, newStep := range config.Steps { - config.Steps[index].Name = fmt.Sprintf("%s_%s", s.Name, newStep.Name) + config.Steps[index].Name = fmt.Sprintf("%s_%s", name, newStep.Name) } - return config.Steps, config.Secrets, config.Services, config.Environment, nil + return &types.Build{Steps: config.Steps, Secrets: config.Secrets, Services: config.Services, Environment: config.Environment}, nil } // RenderBuild renders the templated build. -func RenderBuild(b string, envs map[string]string) (*types.Build, error) { +func RenderBuild(b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { buffer := new(bytes.Buffer) config := new(types.Build) @@ -92,7 +91,7 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { } // execute the template - err = t.Execute(buffer, "") + err = t.Execute(buffer, variables) if err != nil { return nil, fmt.Errorf("unable to execute template: %w", err) } diff --git a/compiler/template/native/render_test.go b/compiler/template/native/render_test.go index 3a215d8da..574f9b10f 100644 --- a/compiler/template/native/render_test.go +++ b/compiler/template/native/render_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/yaml" ) -func TestNative_RenderStep(t *testing.T) { +func TestNative_Render(t *testing.T) { type args struct { velaFile string templateFile string @@ -61,9 +61,9 @@ func TestNative_RenderStep(t *testing.T) { t.Error(err) } - steps, secrets, services, environment, err := RenderStep(string(tmpl), b.Steps[0]) + tmplBuild, err := Render(string(tmpl), b.Steps[0].Name, b.Steps[0].Template.Name, b.Steps[0].Environment, b.Steps[0].Template.Variables) if (err != nil) != tt.wantErr { - t.Errorf("RenderStep() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Render() error = %v, wantErr %v", err, tt.wantErr) return } @@ -82,17 +82,17 @@ func TestNative_RenderStep(t *testing.T) { wantServices := w.Services wantEnvironment := w.Environment - if diff := cmp.Diff(wantSteps, steps); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantSteps, tmplBuild.Steps); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantSecrets, secrets); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantSecrets, tmplBuild.Secrets); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantServices, services); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantServices, tmplBuild.Services); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantEnvironment, environment); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantEnvironment, tmplBuild.Environment); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } } }) @@ -125,7 +125,7 @@ func TestNative_RenderBuild(t *testing.T) { got, err := RenderBuild(string(sFile), map[string]string{ "VELA_REPO_FULL_NAME": "octocat/hello-world", "VELA_BUILD_BRANCH": "master", - }) + }, map[string]interface{}{}) if (err != nil) != tt.wantErr { t.Errorf("RenderBuild() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index 0c1b3242c..4ec617d18 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -30,43 +30,44 @@ var ( ErrInvalidPipelineReturn = errors.New("invalid pipeline return in template") ) -// RenderStep combines the template with the step in the yaml pipeline. -func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, types.ServiceSlice, raw.StringSliceMap, error) { +// Render combines the template with the step in the yaml pipeline. +func Render(tmpl string, name string, tName string, environment raw.StringSliceMap, variables map[string]interface{}) (*types.Build, error) { config := new(types.Build) - thread := &starlark.Thread{Name: s.Name} + thread := &starlark.Thread{Name: name} // arbitrarily limiting the steps of the thread to 5000 to help prevent infinite loops // may need to further investigate spawning a separate POSIX process if user input is problematic // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details thread.SetMaxExecutionSteps(5000) - globals, err := starlark.ExecFile(thread, s.Template.Name, tmpl, nil) + globals, err := starlark.ExecFile(thread, tName, tmpl, nil) + if err != nil { - return nil, nil, nil, nil, err + return nil, err } // check the provided template has a main function mainVal, ok := globals["main"] if !ok { - return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrMissingMainFunc, s.Template.Name) + return nil, fmt.Errorf("%w: %s", ErrMissingMainFunc, tName) } // check the provided main is a function main, ok := mainVal.(starlark.Callable) if !ok { - return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrInvalidMainFunc, s.Template.Name) + return nil, fmt.Errorf("%w: %s", ErrInvalidMainFunc, tName) } // load the user provided vars into a starlark type - userVars, err := convertTemplateVars(s.Template.Variables) + userVars, err := convertTemplateVars(variables) if err != nil { - return nil, nil, nil, nil, err + return nil, err } // load the platform provided vars into a starlark type - velaVars, err := convertPlatformVars(s.Environment, s.Name) + velaVars, err := convertPlatformVars(environment, name) if err != nil { - return nil, nil, nil, nil, err + return nil, err } // add the user and platform vars to a context to be used @@ -75,12 +76,12 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, err = context.SetKey(starlark.String("vela"), velaVars) if err != nil { - return nil, nil, nil, nil, err + return nil, err } err = context.SetKey(starlark.String("vars"), userVars) if err != nil { - return nil, nil, nil, nil, err + return nil, err } args := starlark.Tuple([]starlark.Value{context}) @@ -88,7 +89,7 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, // execute Starlark program from Go. mainVal, err = starlark.Call(thread, main, args, nil) if err != nil { - return nil, nil, nil, nil, err + return nil, err } buf := new(bytes.Buffer) @@ -103,7 +104,7 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, err = writeJSON(buf, item) if err != nil { - return nil, nil, nil, nil, err + return nil, err } buf.WriteString("\n") @@ -113,28 +114,30 @@ func RenderStep(tmpl string, s *types.Step) (types.StepSlice, types.SecretSlice, err = writeJSON(buf, v) if err != nil { - return nil, nil, nil, nil, err + return nil, err } default: - return nil, nil, nil, nil, fmt.Errorf("%w: %s", ErrInvalidPipelineReturn, mainVal.Type()) + return nil, fmt.Errorf("%w: %s", ErrInvalidPipelineReturn, mainVal.Type()) } // unmarshal the template to the pipeline err = yaml.Unmarshal(buf.Bytes(), config) if err != nil { - return types.StepSlice{}, types.SecretSlice{}, types.ServiceSlice{}, raw.StringSliceMap{}, fmt.Errorf("unable to unmarshal yaml: %w", err) + return nil, fmt.Errorf("unable to unmarshal yaml: %w", err) } // ensure all templated steps have template prefix for index, newStep := range config.Steps { - config.Steps[index].Name = fmt.Sprintf("%s_%s", s.Name, newStep.Name) + config.Steps[index].Name = fmt.Sprintf("%s_%s", name, newStep.Name) } - return config.Steps, config.Secrets, config.Services, config.Environment, nil + return &types.Build{Steps: config.Steps, Secrets: config.Secrets, Services: config.Services, Environment: config.Environment}, nil } // RenderBuild renders the templated build. -func RenderBuild(b string, envs map[string]string) (*types.Build, error) { +// +// nolint: lll // ignore function length due to input args +func RenderBuild(b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { config := new(types.Build) thread := &starlark.Thread{Name: "templated-base"} @@ -160,6 +163,12 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { return nil, fmt.Errorf("%w: %s", ErrInvalidMainFunc, "templated-base") } + // load the user provided vars into a starlark type + userVars, err := convertTemplateVars(variables) + if err != nil { + return nil, err + } + // load the platform provided vars into a starlark type velaVars, err := convertPlatformVars(envs, "") if err != nil { @@ -175,6 +184,11 @@ func RenderBuild(b string, envs map[string]string) (*types.Build, error) { return nil, err } + err = context.SetKey(starlark.String("vars"), userVars) + if err != nil { + return nil, err + } + args := starlark.Tuple([]starlark.Value{context}) // execute Starlark program from Go. diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index 89dedd041..3d64874c9 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -14,7 +14,7 @@ import ( "github.com/google/go-cmp/cmp" ) -func TestStarlark_RenderStep(t *testing.T) { +func TestStarlark_Render(t *testing.T) { type args struct { velaFile string starlarkFile string @@ -53,9 +53,9 @@ func TestStarlark_RenderStep(t *testing.T) { t.Error(err) } - steps, secrets, services, environment, err := RenderStep(string(tmpl), b.Steps[0]) + tmplBuild, err := Render(string(tmpl), b.Steps[0].Name, b.Steps[0].Template.Name, b.Steps[0].Environment, b.Steps[0].Template.Variables) if (err != nil) != tt.wantErr { - t.Errorf("RenderStep() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Render() error = %v, wantErr %v", err, tt.wantErr) return } @@ -74,17 +74,17 @@ func TestStarlark_RenderStep(t *testing.T) { wantServices := w.Services wantEnvironment := w.Environment - if diff := cmp.Diff(wantSteps, steps); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantSteps, tmplBuild.Steps); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantSecrets, secrets); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantSecrets, tmplBuild.Secrets); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantServices, services); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantServices, tmplBuild.Services); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(wantEnvironment, environment); diff != "" { - t.Errorf("RenderStep() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(wantEnvironment, tmplBuild.Environment); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) } } }) @@ -117,7 +117,7 @@ func TestNative_RenderBuild(t *testing.T) { got, err := RenderBuild(string(sFile), map[string]string{ "VELA_REPO_FULL_NAME": "octocat/hello-world", "VELA_BUILD_BRANCH": "master", - }) + }, map[string]interface{}{}) if (err != nil) != tt.wantErr { t.Errorf("RenderBuild() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/template/template.go b/compiler/template/template.go index 36dec9a6a..75cc8eda9 100644 --- a/compiler/template/template.go +++ b/compiler/template/template.go @@ -12,7 +12,7 @@ type Engine interface { // RenderBuild defines a function that combines // the template with the build. RenderBuild(template string, step *yaml.Step) (yaml.StepSlice, error) - // RenderStep defines a function that combines + // Render defines a function that combines // the template with the step. - RenderStep(template string, step *yaml.Step) (yaml.StepSlice, error) + Render(template string, step *yaml.Step) (yaml.StepSlice, error) } diff --git a/go.mod b/go.mod index cc8bf8ffa..00de393d9 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.1 github.com/hashicorp/go-cleanhttp v0.5.2 + github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/vault/api v1.4.1 github.com/joho/godotenv v1.4.0 @@ -69,7 +70,6 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v0.16.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.4.3 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect diff --git a/secret/native/update_test.go b/secret/native/update_test.go index f8dcf9bec..1538fd368 100644 --- a/secret/native/update_test.go +++ b/secret/native/update_test.go @@ -28,7 +28,7 @@ func TestNative_Update(t *testing.T) { original.SetAllowCommand(true) original.SetCreatedAt(1) original.SetCreatedBy("user") - original.SetUpdatedAt(1) + original.SetUpdatedAt(time.Now().UTC().Unix()) original.SetUpdatedBy("user") want := new(library.Secret) From 60c6de16f7e19fe4697b6d2df3c41fbfbb6218fb Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 16 Mar 2022 14:59:39 -0500 Subject: [PATCH 029/298] enhance: add local template support for CompileLite() (#608) --- api/pipeline.go | 6 ++--- compiler/engine.go | 2 +- compiler/native/compile.go | 42 +++++++++++++++++++++++++++++---- compiler/native/compile_test.go | 2 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/api/pipeline.go b/api/pipeline.go index 98b495ba9..575ca9968 100644 --- a/api/pipeline.go +++ b/api/pipeline.go @@ -265,7 +265,7 @@ func ExpandPipeline(ctx *gin.Context) { return } - pipeline, err := comp.CompileLite(config, true, false) + pipeline, err := comp.CompileLite(config, true, false, nil) if err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) @@ -349,7 +349,7 @@ func ValidatePipeline(ctx *gin.Context) { template = true } - pipeline, err := comp.CompileLite(config, template, false) + pipeline, err := comp.CompileLite(config, template, false, nil) if err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) @@ -428,7 +428,7 @@ func CompilePipeline(ctx *gin.Context) { return } - pipeline, err := comp.CompileLite(config, true, true) + pipeline, err := comp.CompileLite(config, true, true, nil) if err != nil { retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) util.HandleError(ctx, http.StatusBadRequest, retErr) diff --git a/compiler/engine.go b/compiler/engine.go index f8795dd50..fa1778fba 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -25,7 +25,7 @@ type Engine interface { // CompileLite defines a function that produces an light executable // representation of a pipeline from an object. This calls // Parse internally to convert the object to a yaml configuration. - CompileLite(interface{}, bool, bool) (*yaml.Build, error) + CompileLite(interface{}, bool, bool, []string) (*yaml.Build, error) // Duplicate defines a function that // creates a clone of the Engine. diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 7d8e41d51..96ec2f0cf 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -69,7 +69,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { switch { case p.Metadata.RenderInline: - newPipeline, err := c.compileInline(p) + newPipeline, err := c.compileInline(p, nil) if err != nil { return nil, err } @@ -92,14 +92,14 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { } // CompileLite produces a partial of an executable pipeline from a yaml configuration. -func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Build, error) { +func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, error) { p, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) if err != nil { return nil, err } if p.Metadata.RenderInline { - newPipeline, err := c.compileInline(p) + newPipeline, err := c.compileInline(p, localTemplates) if err != nil { return nil, err } @@ -116,6 +116,24 @@ func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Bu // create map of templates for easy lookup templates := mapFromTemplates(p.Templates) + if c.local { + for _, file := range localTemplates { + // local templates override format is : + // + // example: example:/path/to/template.yml + parts := strings.Split(file, ":") + + // make sure the template was configured + _, ok := templates[parts[0]] + if !ok { + return nil, fmt.Errorf("template with name %s is not configured", parts[0]) + } + + // override the source for the given template + templates[parts[0]].Source = parts[1] + } + } + switch { case len(p.Stages) > 0: // inject the templates into the steps @@ -158,17 +176,33 @@ func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Bu } // compileInline parses and expands out inline pipelines. -func (c *client) compileInline(p *yaml.Build) (*yaml.Build, error) { +func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Build, error) { newPipeline := *p newPipeline.Templates = yaml.TemplateSlice{} for _, template := range p.Templates { + if c.local { + for _, file := range localTemplates { + // local templates override format is : + // + // example: example:/path/to/template.yml + parts := strings.Split(file, ":") + + // make sure we're referencing the proper template + if parts[0] == template.Name { + // override the source for the given template + template.Source = parts[1] + } + } + } + bytes, err := c.getTemplate(template, template.Name) if err != nil { return nil, err } format := template.Format + // set the default format to golang if the user did not define anything if template.Format == "" { format = constants.PipelineTypeGo diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index b6befc253..2f213fbff 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -2977,7 +2977,7 @@ func Test_CompileLite(t *testing.T) { t.Errorf("Reading yaml file return err: %v", err) } - got, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute) + got, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute, nil) if (err != nil) != tt.wantErr { t.Errorf("CompileLite() error = %v, wantErr %v", err, tt.wantErr) return From 413ebb31a6bef196a09af164d7c6b4df5253f36c Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Wed, 16 Mar 2022 15:16:50 -0500 Subject: [PATCH 030/298] chore(release): updates for v0.13.0-rc2 (#613) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 00de393d9..9245dbf59 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.13.0-rc1 + github.com/go-vela/types v0.13.0-rc2 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 diff --git a/go.sum b/go.sum index 9833030bd..39f988b56 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.0-rc1 h1:y4A5R/zbjlz/XXdwDE7iOdl+/6hgB0B/jVz9LFDfznw= -github.com/go-vela/types v0.13.0-rc1/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= +github.com/go-vela/types v0.13.0-rc2 h1:NPlRRnew8qFW/lz6rpYbk8CZXUs8VjjCVJBI6dlk9fg= +github.com/go-vela/types v0.13.0-rc2/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From e55ce800b328e72afe3311901409e8e3d9e2ff0b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 12:12:35 -0600 Subject: [PATCH 031/298] fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.0 (#614) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9245dbf59..ca74ee2ac 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 github.com/go-vela/types v0.13.0-rc2 - github.com/golang-jwt/jwt/v4 v4.3.0 + github.com/golang-jwt/jwt/v4 v4.4.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 39f988b56..d62ae0c3c 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= -github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU= +github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= From e5997fdb18420a272a1d1c6dc0d878152bc37ad9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 21:27:59 +0000 Subject: [PATCH 032/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.19.0 (#612) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ca74ee2ac..cdd7a19f0 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.18.0 + github.com/alicebob/miniredis/v2 v2.19.0 github.com/aws/aws-sdk-go v1.43.10 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 diff --git a/go.sum b/go.sum index d62ae0c3c..c0cca2b61 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.18.0 h1:EPUGD69ou4Uw4c81t9NLh0+dSou46k4tFEvf498FJ0g= -github.com/alicebob/miniredis/v2 v2.18.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I= +github.com/alicebob/miniredis/v2 v2.19.0 h1:oexn9tOmXrfpceZsMvH6lKiOOoo/hLop7d5q6grNQrM= +github.com/alicebob/miniredis/v2 v2.19.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= From 6109e5c070a2e8b0d32327493196d5ad73b4f00f Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Thu, 24 Mar 2022 12:33:11 -0500 Subject: [PATCH 033/298] chore(release): dependency updates for v0.13.0 (#618) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cdd7a19f0..0b205dabc 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.13.0-rc2 + github.com/go-vela/types v0.13.0 github.com/golang-jwt/jwt/v4 v4.4.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 diff --git a/go.sum b/go.sum index c0cca2b61..d9c0a54ff 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.0-rc2 h1:NPlRRnew8qFW/lz6rpYbk8CZXUs8VjjCVJBI6dlk9fg= -github.com/go-vela/types v0.13.0-rc2/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= +github.com/go-vela/types v0.13.0 h1:PX/0wtKMXbtqHbrWgwlCDzuBzeh+4V042k56siDSm1o= +github.com/go-vela/types v0.13.0/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From e024e30279288de239c513c1ac01ae819adbbc0b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 13:13:49 -0500 Subject: [PATCH 034/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.20.0 (#616) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0b205dabc..1b4f6730f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.19.0 + github.com/alicebob/miniredis/v2 v2.20.0 github.com/aws/aws-sdk-go v1.43.10 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 @@ -121,7 +121,7 @@ require ( github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/ugorji/go/codec v1.1.11 // indirect - github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect + github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect diff --git a/go.sum b/go.sum index d9c0a54ff..114c5dc31 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.19.0 h1:oexn9tOmXrfpceZsMvH6lKiOOoo/hLop7d5q6grNQrM= -github.com/alicebob/miniredis/v2 v2.19.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I= +github.com/alicebob/miniredis/v2 v2.20.0 h1:NJSfJcoyPvs9t+wqnox5BTcNVn7J9KxYl0RioTcE8S4= +github.com/alicebob/miniredis/v2 v2.20.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= @@ -599,8 +599,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= -github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= -github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= +github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw= +github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= From e48007c5614313ba483a89e86549dbde035057c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Mar 2022 13:38:27 -0500 Subject: [PATCH 035/298] fix(deps): update module github.com/hashicorp/vault/api to v1.5.0 (#620) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1b4f6730f..7b3a1af87 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.0 - github.com/hashicorp/vault/api v1.4.1 + github.com/hashicorp/vault/api v1.5.0 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 diff --git a/go.sum b/go.sum index 114c5dc31..de0a6a880 100644 --- a/go.sum +++ b/go.sum @@ -325,8 +325,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.4.1 h1:mWLfPT0RhxBitjKr6swieCEP2v5pp/M//t70S3kMLRo= -github.com/hashicorp/vault/api v1.4.1/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM= +github.com/hashicorp/vault/api v1.5.0 h1:Bp6yc2bn7CWkOrVIzFT/Qurzx528bdavF3nz590eu28= +github.com/hashicorp/vault/api v1.5.0/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM= github.com/hashicorp/vault/sdk v0.4.1 h1:3SaHOJY687jY1fnB61PtL0cOkKItphrbLmux7T92HBo= github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= From db117c01a21a8f49cec609501b2fe351e2681cd5 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Thu, 31 Mar 2022 10:18:44 -0500 Subject: [PATCH 036/298] feat(database): add support for pipelines (#574) * feat(database): add support for pipelines * chore: update copyright year to 2022 * chore: cleanup comments and imports * enhance(pipeline): add fields for secrets * chore: update go-vela/types dependency * enhance(pipeline): add field for commit * chore: fix tests * feat: add pipeline engine opts * refactor: structure for creating pipeline engine * chore: finalize pipeline engine setup * chore: clean up pipeline database engine * chore: clean up imports * chore: update go-vela/types dependency * fix: error handling for listing pipelines * chore: update go-vela/types dependency Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- database/pipeline/count.go | 25 +++ database/pipeline/count_repo.go | 31 ++++ database/pipeline/count_repo_test.go | 98 ++++++++++++ database/pipeline/count_test.go | 97 ++++++++++++ database/pipeline/create.go | 46 ++++++ database/pipeline/create_test.go | 75 +++++++++ database/pipeline/delete.go | 30 ++++ database/pipeline/delete_test.go | 75 +++++++++ database/pipeline/get.go | 43 +++++ database/pipeline/get_repo.go | 49 ++++++ database/pipeline/get_repo_test.go | 88 +++++++++++ database/pipeline/get_test.go | 88 +++++++++++ database/pipeline/index.go | 24 +++ database/pipeline/index_test.go | 59 +++++++ database/pipeline/last_repo.go | 48 ++++++ database/pipeline/last_repo_test.go | 102 ++++++++++++ database/pipeline/list.go | 62 ++++++++ database/pipeline/list_repo.go | 73 +++++++++ database/pipeline/list_repo_test.go | 108 +++++++++++++ database/pipeline/list_test.go | 109 +++++++++++++ database/pipeline/opts.go | 54 +++++++ database/pipeline/opts_test.go | 216 ++++++++++++++++++++++++++ database/pipeline/pipeline.go | 82 ++++++++++ database/pipeline/pipeline_test.go | 208 +++++++++++++++++++++++++ database/pipeline/service.go | 49 ++++++ database/pipeline/table.go | 76 +++++++++ database/pipeline/table_test.go | 59 +++++++ database/pipeline/update.go | 46 ++++++ database/pipeline/update_test.go | 77 +++++++++ database/postgres/build_list_test.go | 34 ++-- database/postgres/build_test.go | 23 +-- database/postgres/ddl/build.go | 1 + database/postgres/ddl/hook.go | 25 +-- database/postgres/hook_list_test.go | 18 ++- database/postgres/hook_test.go | 22 +-- database/postgres/postgres.go | 39 ++++- database/postgres/postgres_test.go | 45 +++++- database/service.go | 5 + database/sqlite/build_test.go | 1 + database/sqlite/ddl/build.go | 1 + database/sqlite/ddl/hook.go | 25 +-- database/sqlite/hook_count_test.go | 2 + database/sqlite/hook_list_test.go | 4 + database/sqlite/hook_test.go | 5 + database/sqlite/sqlite.go | 36 ++++- go.mod | 2 +- go.sum | 4 +- router/middleware/build/build_test.go | 1 + 48 files changed, 2416 insertions(+), 74 deletions(-) create mode 100644 database/pipeline/count.go create mode 100644 database/pipeline/count_repo.go create mode 100644 database/pipeline/count_repo_test.go create mode 100644 database/pipeline/count_test.go create mode 100644 database/pipeline/create.go create mode 100644 database/pipeline/create_test.go create mode 100644 database/pipeline/delete.go create mode 100644 database/pipeline/delete_test.go create mode 100644 database/pipeline/get.go create mode 100644 database/pipeline/get_repo.go create mode 100644 database/pipeline/get_repo_test.go create mode 100644 database/pipeline/get_test.go create mode 100644 database/pipeline/index.go create mode 100644 database/pipeline/index_test.go create mode 100644 database/pipeline/last_repo.go create mode 100644 database/pipeline/last_repo_test.go create mode 100644 database/pipeline/list.go create mode 100644 database/pipeline/list_repo.go create mode 100644 database/pipeline/list_repo_test.go create mode 100644 database/pipeline/list_test.go create mode 100644 database/pipeline/opts.go create mode 100644 database/pipeline/opts_test.go create mode 100644 database/pipeline/pipeline.go create mode 100644 database/pipeline/pipeline_test.go create mode 100644 database/pipeline/service.go create mode 100644 database/pipeline/table.go create mode 100644 database/pipeline/table_test.go create mode 100644 database/pipeline/update.go create mode 100644 database/pipeline/update_test.go diff --git a/database/pipeline/count.go b/database/pipeline/count.go new file mode 100644 index 000000000..67845adff --- /dev/null +++ b/database/pipeline/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" +) + +// CountPipelines gets the count of all pipelines from the database. +func (e *engine) CountPipelines() (int64, error) { + e.logger.Tracef("getting count of all pipelines from the database") + + // variable to store query results + var p int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TablePipeline). + Count(&p). + Error + + return p, err +} diff --git a/database/pipeline/count_repo.go b/database/pipeline/count_repo.go new file mode 100644 index 000000000..50de5cae7 --- /dev/null +++ b/database/pipeline/count_repo.go @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountPipelinesForRepo gets the count of pipelines by repo ID from the database. +func (e *engine) CountPipelinesForRepo(r *library.Repo) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting count of pipelines for repo %s from the database", r.GetFullName()) + + // variable to store query results + var p int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TablePipeline). + Where("repo_id = ?", r.GetID()). + Count(&p). + Error + + return p, err +} diff --git a/database/pipeline/count_repo_test.go b/database/pipeline/count_repo_test.go new file mode 100644 index 000000000..aff714085 --- /dev/null +++ b/database/pipeline/count_repo_test.go @@ -0,0 +1,98 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { + // setup types + _pipelineOne := testPipeline() + _pipelineOne.SetID(1) + _pipelineOne.SetRepoID(1) + _pipelineOne.SetNumber(1) + _pipelineOne.SetRef("refs/heads/master") + _pipelineOne.SetType("yaml") + _pipelineOne.SetVersion("1") + + _pipelineTwo := testPipeline() + _pipelineTwo.SetID(2) + _pipelineTwo.SetRepoID(2) + _pipelineTwo.SetNumber(1) + _pipelineTwo.SetRef("refs/heads/main") + _pipelineTwo.SetType("yaml") + _pipelineTwo.SetVersion("1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "pipelines" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipelineOne) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + err = _sqlite.CreatePipeline(_pipelineTwo) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}) + + if test.failure { + if err == nil { + t.Errorf("CountPipelinesForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountPipelinesForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountPipelinesForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/count_test.go b/database/pipeline/count_test.go new file mode 100644 index 000000000..2885b5c6b --- /dev/null +++ b/database/pipeline/count_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_CountPipelines(t *testing.T) { + // setup types + _pipelineOne := testPipeline() + _pipelineOne.SetID(1) + _pipelineOne.SetRepoID(1) + _pipelineOne.SetNumber(1) + _pipelineOne.SetRef("refs/heads/master") + _pipelineOne.SetType("yaml") + _pipelineOne.SetVersion("1") + + _pipelineTwo := testPipeline() + _pipelineTwo.SetID(2) + _pipelineTwo.SetRepoID(2) + _pipelineTwo.SetNumber(1) + _pipelineTwo.SetRef("refs/heads/main") + _pipelineTwo.SetType("yaml") + _pipelineTwo.SetVersion("1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "pipelines"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipelineOne) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + err = _sqlite.CreatePipeline(_pipelineTwo) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountPipelines() + + if test.failure { + if err == nil { + t.Errorf("CountPipelines for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountPipelines for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountPipelines for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/create.go b/database/pipeline/create.go new file mode 100644 index 000000000..bc6a5aff8 --- /dev/null +++ b/database/pipeline/create.go @@ -0,0 +1,46 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreatePipeline creates a new pipeline in the database. +func (e *engine) CreatePipeline(p *library.Pipeline) error { + e.logger.WithFields(logrus.Fields{ + "pipeline": p.GetNumber(), + }).Tracef("creating pipeline %d in the database", p.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#PipelineFromLibrary + pipeline := database.PipelineFromLibrary(p) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Validate + err := pipeline.Validate() + if err != nil { + return err + } + + // compress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Compress + err = pipeline.Compress(e.config.CompressionLevel) + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TablePipeline). + Create(pipeline). + Error +} diff --git a/database/pipeline/create_test.go b/database/pipeline/create_test.go new file mode 100644 index 000000000..eced618bf --- /dev/null +++ b/database/pipeline/create_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_CreatePipeline(t *testing.T) { + // setup types + _pipeline := testPipeline() + _pipeline.SetID(1) + _pipeline.SetRepoID(1) + _pipeline.SetNumber(1) + _pipeline.SetRef("refs/heads/master") + _pipeline.SetType("yaml") + _pipeline.SetVersion("1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "pipelines" +("repo_id","number","commit","flavor","platform","ref","type","version","external_secrets","internal_secrets","services","stages","steps","templates","data","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`). + WithArgs(1, 1, nil, nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreatePipeline(_pipeline) + + if test.failure { + if err == nil { + t.Errorf("CreatePipeline for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreatePipeline for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/pipeline/delete.go b/database/pipeline/delete.go new file mode 100644 index 000000000..6b0360fa0 --- /dev/null +++ b/database/pipeline/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeletePipeline deletes an existing pipeline from the database. +func (e *engine) DeletePipeline(p *library.Pipeline) error { + e.logger.WithFields(logrus.Fields{ + "pipeline": p.GetNumber(), + }).Tracef("deleting pipeline %d from the database", p.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#PipelineFromLibrary + pipeline := database.PipelineFromLibrary(p) + + // send query to the database + return e.client. + Table(constants.TablePipeline). + Delete(pipeline). + Error +} diff --git a/database/pipeline/delete_test.go b/database/pipeline/delete_test.go new file mode 100644 index 000000000..0ccfa21a3 --- /dev/null +++ b/database/pipeline/delete_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_DeletePipeline(t *testing.T) { + // setup types + _pipeline := testPipeline() + _pipeline.SetID(1) + _pipeline.SetRepoID(1) + _pipeline.SetNumber(1) + _pipeline.SetRef("refs/heads/master") + _pipeline.SetType("yaml") + _pipeline.SetVersion("1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "pipelines" WHERE "pipelines"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipeline) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeletePipeline(_pipeline) + + if test.failure { + if err == nil { + t.Errorf("DeletePipeline for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeletePipeline for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/pipeline/get.go b/database/pipeline/get.go new file mode 100644 index 000000000..14f1b35a8 --- /dev/null +++ b/database/pipeline/get.go @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetPipeline gets a pipeline by ID from the database. +func (e *engine) GetPipeline(id int64) (*library.Pipeline, error) { + e.logger.Tracef("getting pipeline %d from the database", id) + + // variable to store query results + p := new(database.Pipeline) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TablePipeline). + Where("id = ?", id). + Limit(1). + Scan(p). + Error + if err != nil { + return nil, err + } + + // decompress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress + err = p.Decompress() + if err != nil { + return nil, err + } + + // return the decompressed pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary + return p.ToLibrary(), nil +} diff --git a/database/pipeline/get_repo.go b/database/pipeline/get_repo.go new file mode 100644 index 000000000..c181fc7b7 --- /dev/null +++ b/database/pipeline/get_repo.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetPipelineForRepo gets a pipeline by number and repo ID from the database. +func (e *engine) GetPipelineForRepo(number int, r *library.Repo) (*library.Pipeline, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "pipeline": number, + "repo": r.GetName(), + }).Tracef("getting pipeline %s/%d from the database", r.GetFullName(), number) + + // variable to store query results + p := new(database.Pipeline) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TablePipeline). + Where("repo_id = ?", r.GetID()). + Where("number = ?", number). + Limit(1). + Scan(p). + Error + if err != nil { + return nil, err + } + + // decompress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress + err = p.Decompress() + if err != nil { + return nil, err + } + + // return the decompressed pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary + return p.ToLibrary(), nil +} diff --git a/database/pipeline/get_repo_test.go b/database/pipeline/get_repo_test.go new file mode 100644 index 000000000..c641e9ff6 --- /dev/null +++ b/database/pipeline/get_repo_test.go @@ -0,0 +1,88 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { + // setup types + _pipeline := testPipeline() + _pipeline.SetID(1) + _pipeline.SetRepoID(1) + _pipeline.SetNumber(1) + _pipeline.SetRef("refs/heads/master") + _pipeline.SetType("yaml") + _pipeline.SetVersion("1") + _pipeline.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipeline) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Pipeline + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _pipeline, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _pipeline, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetPipelineForRepo(1, &library.Repo{ID: _pipeline.RepoID}) + + if test.failure { + if err == nil { + t.Errorf("GetPipelineForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetPipelineForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetPipelineForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/get_test.go b/database/pipeline/get_test.go new file mode 100644 index 000000000..d26db6d8a --- /dev/null +++ b/database/pipeline/get_test.go @@ -0,0 +1,88 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_GetPipeline(t *testing.T) { + // setup types + _pipeline := testPipeline() + _pipeline.SetID(1) + _pipeline.SetRepoID(1) + _pipeline.SetNumber(1) + _pipeline.SetRef("refs/heads/master") + _pipeline.SetType("yaml") + _pipeline.SetVersion("1") + _pipeline.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipeline) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Pipeline + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _pipeline, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _pipeline, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetPipeline(1) + + if test.failure { + if err == nil { + t.Errorf("GetPipeline for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetPipeline for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetPipeline for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/index.go b/database/pipeline/index.go new file mode 100644 index 000000000..ef8bb4f20 --- /dev/null +++ b/database/pipeline/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +const ( + // CreateRepoIDIndex represents a query to create an + // index on the pipelines table for the repo_id column. + CreateRepoIDIndex = ` +CREATE INDEX +IF NOT EXISTS +pipelines_repo_id +ON pipelines (repo_id); +` +) + +// CreateIndexes creates the indexes for the pipelines table in the database. +func (e *engine) CreateIndexes() error { + e.logger.Tracef("creating indexes for pipelines table in the database") + + // create the repo_id column index for the pipelines table + return e.client.Exec(CreateRepoIDIndex).Error +} diff --git a/database/pipeline/index_test.go b/database/pipeline/index_test.go new file mode 100644 index 000000000..75e54f90e --- /dev/null +++ b/database/pipeline/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_CreateIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/pipeline/last_repo.go b/database/pipeline/last_repo.go new file mode 100644 index 000000000..dbbb46aeb --- /dev/null +++ b/database/pipeline/last_repo.go @@ -0,0 +1,48 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// LastPipelineForRepo gets the last pipeline by repo ID from the database. +func (e *engine) LastPipelineForRepo(r *library.Repo) (*library.Pipeline, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting last pipeline for repo %s from the database", r.GetFullName()) + + // variable to store query results + p := new(database.Pipeline) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TablePipeline). + Where("repo_id = ?", r.GetID()). + Order("number DESC"). + Limit(1). + Scan(p). + Error + if err != nil { + return nil, err + } + + // decompress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress + err = p.Decompress() + if err != nil { + return nil, err + } + + // return the decompressed pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary + return p.ToLibrary(), nil +} diff --git a/database/pipeline/last_repo_test.go b/database/pipeline/last_repo_test.go new file mode 100644 index 000000000..ef4a91a65 --- /dev/null +++ b/database/pipeline/last_repo_test.go @@ -0,0 +1,102 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_LastPipelineForRepo(t *testing.T) { + // setup types + _pipelineOne := testPipeline() + _pipelineOne.SetID(1) + _pipelineOne.SetRepoID(1) + _pipelineOne.SetNumber(1) + _pipelineOne.SetRef("refs/heads/master") + _pipelineOne.SetType("yaml") + _pipelineOne.SetVersion("1") + _pipelineOne.SetData([]byte("foo")) + + _pipelineTwo := testPipeline() + _pipelineTwo.SetID(2) + _pipelineTwo.SetRepoID(1) + _pipelineTwo.SetNumber(2) + _pipelineTwo.SetRef("refs/heads/main") + _pipelineTwo.SetType("yaml") + _pipelineTwo.SetVersion("1") + _pipelineTwo.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(2, 1, 2, "", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 ORDER BY number DESC LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipelineOne) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + err = _sqlite.CreatePipeline(_pipelineTwo) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Pipeline + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _pipelineTwo, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _pipelineTwo, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.LastPipelineForRepo(&library.Repo{ID: _pipelineOne.RepoID}) + + if test.failure { + if err == nil { + t.Errorf("LastPipelineForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("LastPipelineForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("LastPipelineForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/list.go b/database/pipeline/list.go new file mode 100644 index 000000000..9159a87aa --- /dev/null +++ b/database/pipeline/list.go @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListPipelines gets a list of all pipelines from the database. +func (e *engine) ListPipelines() ([]*library.Pipeline, error) { + e.logger.Trace("listing all pipelines from the database") + + // variables to store query results and return value + count := int64(0) + p := new([]database.Pipeline) + pipelines := []*library.Pipeline{} + + // count the results + count, err := e.CountPipelines() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return pipelines, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TablePipeline). + Find(&p). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, pipeline := range *p { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := pipeline + + // decompress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress + err = tmp.Decompress() + if err != nil { + return nil, err + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary + pipelines = append(pipelines, tmp.ToLibrary()) + } + + return pipelines, nil +} diff --git a/database/pipeline/list_repo.go b/database/pipeline/list_repo.go new file mode 100644 index 000000000..e90db6700 --- /dev/null +++ b/database/pipeline/list_repo.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListPipelinesForRepo gets a list of pipelines by repo ID from the database. +// +// nolint: lll // ignore long line length due to variable names +func (e *engine) ListPipelinesForRepo(r *library.Repo, page, perPage int) ([]*library.Pipeline, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("listing pipelines for repo %s from the database", r.GetFullName()) + + // variables to store query results and return values + count := int64(0) + p := new([]database.Pipeline) + pipelines := []*library.Pipeline{} + + // count the results + count, err := e.CountPipelinesForRepo(r) + if err != nil { + return pipelines, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return pipelines, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + err = e.client. + Table(constants.TablePipeline). + Where("repo_id = ?", r.GetID()). + Limit(perPage). + Offset(offset). + Find(&p). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, pipeline := range *p { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := pipeline + + // decompress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress + err = tmp.Decompress() + if err != nil { + return nil, count, err + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary + pipelines = append(pipelines, tmp.ToLibrary()) + } + + return pipelines, count, nil +} diff --git a/database/pipeline/list_repo_test.go b/database/pipeline/list_repo_test.go new file mode 100644 index 000000000..3fc806a55 --- /dev/null +++ b/database/pipeline/list_repo_test.go @@ -0,0 +1,108 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { + // setup types + _pipelineOne := testPipeline() + _pipelineOne.SetID(1) + _pipelineOne.SetRepoID(1) + _pipelineOne.SetNumber(1) + _pipelineOne.SetRef("refs/heads/master") + _pipelineOne.SetType("yaml") + _pipelineOne.SetVersion("1") + _pipelineOne.SetData([]byte("foo")) + + _pipelineTwo := testPipeline() + _pipelineTwo.SetID(2) + _pipelineTwo.SetRepoID(2) + _pipelineTwo.SetNumber(1) + _pipelineTwo.SetRef("refs/heads/main") + _pipelineTwo.SetType("yaml") + _pipelineTwo.SetVersion("1") + _pipelineTwo.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "pipelines" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipelineOne) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + err = _sqlite.CreatePipeline(_pipelineTwo) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Pipeline + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Pipeline{_pipelineOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Pipeline{_pipelineOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}, 1, 1) + + if test.failure { + if err == nil { + t.Errorf("ListPipelinesForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListPipelinesForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListPipelinesForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/list_test.go b/database/pipeline/list_test.go new file mode 100644 index 000000000..0ba2c98dc --- /dev/null +++ b/database/pipeline/list_test.go @@ -0,0 +1,109 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestPipeline_Engine_ListPipelines(t *testing.T) { + // setup types + _pipelineOne := testPipeline() + _pipelineOne.SetID(1) + _pipelineOne.SetRepoID(1) + _pipelineOne.SetNumber(1) + _pipelineOne.SetRef("refs/heads/master") + _pipelineOne.SetType("yaml") + _pipelineOne.SetVersion("1") + _pipelineOne.SetData([]byte("foo")) + + _pipelineTwo := testPipeline() + _pipelineTwo.SetID(2) + _pipelineTwo.SetRepoID(1) + _pipelineTwo.SetNumber(2) + _pipelineTwo.SetRef("refs/heads/main") + _pipelineTwo.SetType("yaml") + _pipelineTwo.SetVersion("1") + _pipelineTwo.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "pipelines"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}). + AddRow(2, 1, 2, "", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "pipelines"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipelineOne) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + err = _sqlite.CreatePipeline(_pipelineTwo) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Pipeline + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Pipeline{_pipelineOne, _pipelineTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Pipeline{_pipelineOne, _pipelineTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListPipelines() + + if test.failure { + if err == nil { + t.Errorf("ListPipelines for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListPipelines for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListPipelines for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/pipeline/opts.go b/database/pipeline/opts.go new file mode 100644 index 000000000..f04796ff7 --- /dev/null +++ b/database/pipeline/opts.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Pipelines. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Pipelines. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the pipeline engine + e.client = client + + return nil + } +} + +// WithCompressionLevel sets the compression level in the database engine for Pipelines. +func WithCompressionLevel(level int) EngineOpt { + return func(e *engine) error { + // set the compression level in the pipeline engine + e.config.CompressionLevel = level + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Pipelines. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the pipeline engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Pipelines. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the pipeline engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/pipeline/opts_test.go b/database/pipeline/opts_test.go new file mode 100644 index 000000000..94822e33b --- /dev/null +++ b/database/pipeline/opts_test.go @@ -0,0 +1,216 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestPipeline_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestPipeline_EngineOpt_WithCompressionLevel(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + level int + want int + }{ + { + failure: false, + name: "compression level set to -1", + level: -1, + want: -1, + }, + { + failure: false, + name: "compression level set to 0", + level: 0, + want: 0, + }, + { + failure: false, + name: "compression level set to 1", + level: 1, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithCompressionLevel(test.level)(e) + + if test.failure { + if err == nil { + t.Errorf("WithCompressionLevel for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithCompressionLevel returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.CompressionLevel, test.want) { + t.Errorf("WithCompressionLevel is %v, want %v", e.config.CompressionLevel, test.want) + } + }) + } +} + +func TestPipeline_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestPipeline_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/pipeline/pipeline.go b/database/pipeline/pipeline.go new file mode 100644 index 000000000..d6978fad0 --- /dev/null +++ b/database/pipeline/pipeline.go @@ -0,0 +1,82 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the PipelineService interface. + config struct { + // specifies the level of compression to use for the Pipeline engine + CompressionLevel int + // specifies to skip creating tables and indexes for the Pipeline engine + SkipCreation bool + } + + // engine represents the pipeline functionality that implements the PipelineService interface. + engine struct { + // engine configuration settings used in pipeline functions + config *config + + // gorm.io/gorm database client used in pipeline functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in pipeline functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with pipelines in the database. +// +// nolint: revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Pipeline engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating pipeline database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of pipelines table and indexes in the database") + + return e, nil + } + + // create the pipelines table + err := e.CreateTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TablePipeline, err) + } + + // create the indexes for the pipelines table + err = e.CreateIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TablePipeline, err) + } + + return e, nil +} diff --git a/database/pipeline/pipeline_test.go b/database/pipeline/pipeline_test.go new file mode 100644 index 000000000..7456066fb --- /dev/null +++ b/database/pipeline/pipeline_test.go @@ -0,0 +1,208 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestPipeline_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + level int + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + level: 1, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{CompressionLevel: 1, SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + level: 1, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{CompressionLevel: 1, SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithCompressionLevel(test.level), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithCompressionLevel(0), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres pipeline engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithCompressionLevel(0), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite pipeline engine: %v", err) + } + + 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), + Number: new(int), + 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. +// +// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime +type AnyArgument struct{} + +// Match satisfies sqlmock.Argument interface. +func (a AnyArgument) Match(v driver.Value) bool { + return true +} diff --git a/database/pipeline/service.go b/database/pipeline/service.go new file mode 100644 index 000000000..3a3fd45de --- /dev/null +++ b/database/pipeline/service.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/library" +) + +// PipelineService represents the Vela interface for pipeline +// functions with the supported Database backends. +// +// nolint: revive // ignore name stutter +type PipelineService interface { + // Pipeline Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateIndexes creates the indexes for the pipelines table. + CreateIndexes() error + // CreateTable defines a function that creates the pipelines table. + CreateTable(string) error + + // Pipeline Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountPipelines defines a function that gets the count of all pipelines. + CountPipelines() (int64, error) + // CountPipelinesForRepo defines a function that gets the count of pipelines by repo ID. + CountPipelinesForRepo(*library.Repo) (int64, error) + // CreatePipeline defines a function that creates a new pipeline. + CreatePipeline(*library.Pipeline) error + // DeletePipeline defines a function that deletes an existing pipeline. + DeletePipeline(*library.Pipeline) error + // GetPipeline defines a function that gets a pipeline by ID. + GetPipeline(int64) (*library.Pipeline, error) + // GetPipelineForRepo defines a function that gets a pipeline by number and repo ID. + GetPipelineForRepo(int, *library.Repo) (*library.Pipeline, error) + // LastPipelineForRepo defines a function that gets the last pipeline by repo ID. + LastPipelineForRepo(*library.Repo) (*library.Pipeline, error) + // ListPipelines defines a function that gets a list of all pipelines. + ListPipelines() ([]*library.Pipeline, error) + // ListPipelinesForRepo defines a function that gets a list of pipelines by repo ID. + ListPipelinesForRepo(*library.Repo, int, int) ([]*library.Pipeline, int64, error) + // UpdatePipeline defines a function that updates an existing pipeline. + UpdatePipeline(*library.Pipeline) error +} diff --git a/database/pipeline/table.go b/database/pipeline/table.go new file mode 100644 index 000000000..28810c408 --- /dev/null +++ b/database/pipeline/table.go @@ -0,0 +1,76 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import "github.com/go-vela/types/constants" + +const ( + // CreatePostgresTable represents a query to create the Postgres pipelines table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +pipelines ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + number INTEGER, + commit VARCHAR(500), + flavor VARCHAR(100), + platform VARCHAR(100), + ref VARCHAR(500), + type VARCHAR(100), + version VARCHAR(50), + external_secrets BOOLEAN, + internal_secrets BOOLEAN, + services BOOLEAN, + stages BOOLEAN, + steps BOOLEAN, + templates BOOLEAN, + data BYTEA, + UNIQUE(repo_id, number) +); +` + + // CreateSqliteTable represents a query to create the Sqlite pipelines table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +pipelines ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + number INTEGER, + 'commit' TEXT, + flavor TEXT, + platform TEXT, + ref TEXT, + type TEXT, + version TEXT, + external_secrets BOOLEAN, + internal_secrets BOOLEAN, + services BOOLEAN, + stages BOOLEAN, + steps BOOLEAN, + templates BOOLEAN, + data BLOB, + UNIQUE(repo_id, number) +); +` +) + +// CreateTable creates the pipelines table in the database. +func (e *engine) CreateTable(driver string) error { + e.logger.Tracef("creating pipelines table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the pipelines table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the pipelines table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/pipeline/table_test.go b/database/pipeline/table_test.go new file mode 100644 index 000000000..c199f98b5 --- /dev/null +++ b/database/pipeline/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_CreateTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/pipeline/update.go b/database/pipeline/update.go new file mode 100644 index 000000000..ad6bc5671 --- /dev/null +++ b/database/pipeline/update.go @@ -0,0 +1,46 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdatePipeline updates an existing pipeline in the database. +func (e *engine) UpdatePipeline(p *library.Pipeline) error { + e.logger.WithFields(logrus.Fields{ + "pipeline": p.GetNumber(), + }).Tracef("updating pipeline %d in the database", p.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#PipelineFromLibrary + pipeline := database.PipelineFromLibrary(p) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Validate + err := pipeline.Validate() + if err != nil { + return err + } + + // compress data for the pipeline + // + // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Compress + err = pipeline.Compress(e.config.CompressionLevel) + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TablePipeline). + Save(pipeline). + Error +} diff --git a/database/pipeline/update_test.go b/database/pipeline/update_test.go new file mode 100644 index 000000000..adb6fbeb1 --- /dev/null +++ b/database/pipeline/update_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestPipeline_Engine_UpdatePipeline(t *testing.T) { + // setup types + _pipeline := testPipeline() + _pipeline.SetID(1) + _pipeline.SetRepoID(1) + _pipeline.SetNumber(1) + _pipeline.SetRef("refs/heads/master") + _pipeline.SetType("yaml") + _pipeline.SetVersion("1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "pipelines" +SET "repo_id"=$1,"number"=$2,"commit"=$3,"flavor"=$4,"platform"=$5,"ref"=$6,"type"=$7,"version"=$8,"external_secrets"=$9,"internal_secrets"=$10,"services"=$11,"stages"=$12,"steps"=$13,"templates"=$14,"data"=$15 +WHERE "id" = $16`). + WithArgs(1, 1, nil, nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreatePipeline(_pipeline) + if err != nil { + t.Errorf("unable to create test pipeline for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdatePipeline(_pipeline) + + if test.failure { + if err == nil { + t.Errorf("UpdatePipeline for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdatePipeline for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/postgres/build_list_test.go b/database/postgres/build_list_test.go index c0db1066d..17b7a09de 100644 --- a/database/postgres/build_list_test.go +++ b/database/postgres/build_list_test.go @@ -46,9 +46,9 @@ func TestPostgres_Client_GetBuildList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -112,9 +112,9 @@ func TestPostgres_Client_GetDeploymentBuildList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(2, 1, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT * FROM \"builds\" WHERE \"source\" = $1 ORDER BY number DESC LIMIT 3").WillReturnRows(_rows) @@ -182,9 +182,9 @@ func TestPostgres_Client_GetOrgBuildList(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -254,8 +254,8 @@ func TestPostgres_Client_GetOrgBuildList_NonAdmin(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"visibility\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -327,9 +327,9 @@ func TestPostgres_Client_GetOrgBuildListByEvent(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"event\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -412,9 +412,9 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, 2, 0, "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // 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 10`).WillReturnRows(_rows) diff --git a/database/postgres/build_test.go b/database/postgres/build_test.go index 2b6a53c60..e152adfe5 100644 --- a/database/postgres/build_test.go +++ b/database/postgres/build_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/postgres/dml" "github.com/go-vela/types/library" @@ -48,8 +48,8 @@ func TestPostgres_Client_GetBuild(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -125,8 +125,8 @@ func TestPostgres_Client_GetLastBuild(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -202,8 +202,8 @@ func TestPostgres_Client_GetLastBuildByBranch(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -348,8 +348,8 @@ func TestPostgres_Client_CreateBuild(t *testing.T) { _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "builds" ("repo_id","number","parent","event","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","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29) RETURNING "id"`). - WithArgs(1, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectQuery(`INSERT INTO "builds" ("repo_id","pipeline_id","number","parent","event","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","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30) RETURNING "id"`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnRows(_rows) // setup tests @@ -404,8 +404,8 @@ func TestPostgres_Client_UpdateBuild(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "builds" SET "repo_id"=$1,"number"=$2,"parent"=$3,"event"=$4,"status"=$5,"error"=$6,"enqueued"=$7,"created"=$8,"started"=$9,"finished"=$10,"deploy"=$11,"deploy_payload"=$12,"clone"=$13,"source"=$14,"title"=$15,"message"=$16,"commit"=$17,"sender"=$18,"author"=$19,"email"=$20,"link"=$21,"branch"=$22,"ref"=$23,"base_ref"=$24,"head_ref"=$25,"host"=$26,"runtime"=$27,"distribution"=$28 WHERE "id" = $29`). - WithArgs(1, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectExec(`UPDATE "builds" SET "repo_id"=$1,"pipeline_id"=$2,"number"=$3,"parent"=$4,"event"=$5,"status"=$6,"error"=$7,"enqueued"=$8,"created"=$9,"started"=$10,"finished"=$11,"deploy"=$12,"deploy_payload"=$13,"clone"=$14,"source"=$15,"title"=$16,"message"=$17,"commit"=$18,"sender"=$19,"author"=$20,"email"=$21,"link"=$22,"branch"=$23,"ref"=$24,"base_ref"=$25,"head_ref"=$26,"host"=$27,"runtime"=$28,"distribution"=$29 WHERE "id" = $30`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnResult(sqlmock.NewResult(1, 1)) // setup tests @@ -491,6 +491,7 @@ func testBuild() *library.Build { return &library.Build{ ID: &i64, RepoID: &i64, + PipelineID: &i64, Number: &i, Parent: &i, Event: &str, diff --git a/database/postgres/ddl/build.go b/database/postgres/ddl/build.go index 6ed08ec25..f358fce16 100644 --- a/database/postgres/ddl/build.go +++ b/database/postgres/ddl/build.go @@ -13,6 +13,7 @@ IF NOT EXISTS builds ( id SERIAL PRIMARY KEY, repo_id INTEGER, + pipeline_id INTEGER, number INTEGER, parent INTEGER, event VARCHAR(250), diff --git a/database/postgres/ddl/hook.go b/database/postgres/ddl/hook.go index 98e93e1e1..3f6f9333b 100644 --- a/database/postgres/ddl/hook.go +++ b/database/postgres/ddl/hook.go @@ -11,18 +11,19 @@ const ( CREATE TABLE IF NOT EXISTS hooks ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id VARCHAR(250), - created INTEGER, - host VARCHAR(250), - event VARCHAR(250), - branch VARCHAR(500), - error VARCHAR(500), - status VARCHAR(250), - link VARCHAR(1000), + id SERIAL PRIMARY KEY, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id VARCHAR(250), + created INTEGER, + host VARCHAR(250), + event VARCHAR(250), + branch VARCHAR(500), + error VARCHAR(500), + status VARCHAR(250), + link VARCHAR(1000), + webhook_id INTEGER, UNIQUE(repo_id, number) ); ` diff --git a/database/postgres/hook_list_test.go b/database/postgres/hook_list_test.go index c8f4129dc..1266c73b9 100644 --- a/database/postgres/hook_list_test.go +++ b/database/postgres/hook_list_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/postgres/dml" "github.com/go-vela/types/library" @@ -24,6 +24,7 @@ func TestPostgres_Client_GetHookList(t *testing.T) { _hookOne.SetBuildID(1) _hookOne.SetNumber(1) _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) _hookTwo := testHook() _hookTwo.SetID(2) @@ -31,6 +32,7 @@ func TestPostgres_Client_GetHookList(t *testing.T) { _hookTwo.SetBuildID(2) _hookTwo.SetNumber(2) _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) // setup the test database client _database, _mock, err := NewTest() @@ -47,9 +49,9 @@ func TestPostgres_Client_GetHookList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", ""). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "") + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -95,6 +97,7 @@ func TestPostgres_Client_GetRepoHookList(t *testing.T) { _hookOne.SetBuildID(1) _hookOne.SetNumber(1) _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) _hookTwo := testHook() _hookTwo.SetID(2) @@ -102,6 +105,7 @@ func TestPostgres_Client_GetRepoHookList(t *testing.T) { _hookTwo.SetBuildID(2) _hookTwo.SetNumber(2) _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) _repo := testRepo() _repo.SetID(1) @@ -125,9 +129,9 @@ func TestPostgres_Client_GetRepoHookList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", ""). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "") + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) diff --git a/database/postgres/hook_test.go b/database/postgres/hook_test.go index 113cbb468..584b18a7e 100644 --- a/database/postgres/hook_test.go +++ b/database/postgres/hook_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/postgres/dml" "github.com/go-vela/types/library" @@ -31,6 +31,7 @@ func TestPostgres_Client_GetHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, _mock, err := NewTest() @@ -47,8 +48,8 @@ func TestPostgres_Client_GetHook(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "") + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -107,6 +108,7 @@ func TestPostgres_Client_GetLastHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, _mock, err := NewTest() @@ -123,8 +125,8 @@ func TestPostgres_Client_GetLastHook(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "") + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -176,6 +178,7 @@ func TestPostgres_Client_CreateHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, _mock, err := NewTest() @@ -189,8 +192,8 @@ func TestPostgres_Client_CreateHook(t *testing.T) { _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "hooks" ("repo_id","build_id","number","source_id","created","host","event","branch","error","status","link","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) RETURNING "id"`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectQuery(`INSERT INTO "hooks" ("repo_id","build_id","number","source_id","created","host","event","branch","error","status","link","webhook_id","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING "id"`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1, 1). WillReturnRows(_rows) // setup tests @@ -228,6 +231,7 @@ func TestPostgres_Client_UpdateHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, _mock, err := NewTest() @@ -238,8 +242,8 @@ func TestPostgres_Client_UpdateHook(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "hooks" SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"branch"=$8,"error"=$9,"status"=$10,"link"=$11 WHERE "id" = $12`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectExec(`UPDATE "hooks" SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"branch"=$8,"error"=$9,"status"=$10,"link"=$11,"webhook_id"=$12 WHERE "id" = $13`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1, 1). WillReturnResult(sqlmock.NewResult(1, 1)) // setup tests diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index afa221c58..c25048f1b 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -9,6 +9,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -40,6 +41,7 @@ type ( Postgres *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + pipeline.PipelineService } ) @@ -89,6 +91,12 @@ func New(opts ...ClientOpt) (*client, error) { return nil, err } + // create the services for the database + err = createServices(c) + if err != nil { + return nil, err + } + return c, nil } @@ -120,7 +128,7 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { // create new logger for the client // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger) + c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) // create the new mock sql database // @@ -130,6 +138,9 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { return nil, nil, err } + _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // create the new mock Postgres database client // // https://pkg.go.dev/gorm.io/gorm#Open @@ -141,6 +152,12 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { return nil, nil, err } + // setup database with proper configuration + err = createServices(c) + if err != nil { + return nil, nil, err + } + return c, _mock, nil } @@ -333,3 +350,23 @@ func createIndexes(c *client) error { return nil } + +// createServices is a helper function to create the database services. +func createServices(c *client) error { + var err error + + // create the database agnostic pipeline service + // + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New + c.PipelineService, err = pipeline.New( + pipeline.WithClient(c.Postgres), + pipeline.WithCompressionLevel(c.config.CompressionLevel), + pipeline.WithLogger(c.Logger), + pipeline.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + + return nil +} diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 2c0fbc9e5..5188b5c93 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -9,7 +9,8 @@ import ( "testing" "time" - sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" ) @@ -94,6 +95,8 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // setup the skip test database client _skipDatabase, _skipMock, err := NewTest() @@ -239,6 +242,46 @@ func TestPostgres_createIndexes(t *testing.T) { } } +func TestPostgres_createServices(t *testing.T) { + // setup types + // setup the test database client + _database, _mock, err := NewTest() + if err != nil { + t.Errorf("unable to create new postgres test database: %v", err) + } + + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() + + // ensure the mock expects the index queries + _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + tests := []struct { + failure bool + }{ + { + failure: false, + }, + } + + // run tests + for _, test := range tests { + err := createServices(_database) + + if test.failure { + if err == nil { + t.Errorf("createServices should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("createServices returned err: %v", err) + } + } +} + // 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 diff --git a/database/service.go b/database/service.go index 7419cc11e..a25ff57d3 100644 --- a/database/service.go +++ b/database/service.go @@ -5,6 +5,7 @@ package database import ( + "github.com/go-vela/server/database/pipeline" "github.com/go-vela/types/library" ) @@ -113,6 +114,10 @@ type Service interface { // deletes a log by unique ID. DeleteLog(int64) error + // PipelineService provides the interface for functionality + // related to pipelines stored in the database. + pipeline.PipelineService + // Repo Database Interface Functions // GetRepo defines a function that diff --git a/database/sqlite/build_test.go b/database/sqlite/build_test.go index d35cf6952..dcb28b41b 100644 --- a/database/sqlite/build_test.go +++ b/database/sqlite/build_test.go @@ -515,6 +515,7 @@ func testBuild() *library.Build { return &library.Build{ ID: &i64, RepoID: &i64, + PipelineID: &i64, Number: &i, Parent: &i, Event: &str, diff --git a/database/sqlite/ddl/build.go b/database/sqlite/ddl/build.go index d9ed4ff86..87c505df6 100644 --- a/database/sqlite/ddl/build.go +++ b/database/sqlite/ddl/build.go @@ -13,6 +13,7 @@ IF NOT EXISTS builds ( id INTEGER PRIMARY KEY AUTOINCREMENT, repo_id INTEGER, + pipeline_id INTEGER, number INTEGER, parent INTEGER, event TEXT, diff --git a/database/sqlite/ddl/hook.go b/database/sqlite/ddl/hook.go index 80b3397bc..9d350c2fe 100644 --- a/database/sqlite/ddl/hook.go +++ b/database/sqlite/ddl/hook.go @@ -11,18 +11,19 @@ const ( CREATE TABLE IF NOT EXISTS hooks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id TEXT, - created INTEGER, - host TEXT, - event TEXT, - branch TEXT, - error TEXT, - status TEXT, - link TEXT, + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id TEXT, + created INTEGER, + host TEXT, + event TEXT, + branch TEXT, + error TEXT, + status TEXT, + link TEXT, + webhook_id INTEGER, UNIQUE(repo_id, build_id) ); ` diff --git a/database/sqlite/hook_count_test.go b/database/sqlite/hook_count_test.go index 3d5d334cf..c640b9610 100644 --- a/database/sqlite/hook_count_test.go +++ b/database/sqlite/hook_count_test.go @@ -35,6 +35,7 @@ func TestSqlite_Client_GetRepoHookCount(t *testing.T) { _hookOne.SetBuildID(1) _hookOne.SetNumber(1) _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) _hookTwo := testHook() _hookTwo.SetID(2) @@ -42,6 +43,7 @@ func TestSqlite_Client_GetRepoHookCount(t *testing.T) { _hookTwo.SetBuildID(2) _hookTwo.SetNumber(2) _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) _repo := testRepo() _repo.SetID(1) diff --git a/database/sqlite/hook_list_test.go b/database/sqlite/hook_list_test.go index a9d8394ac..9c4784193 100644 --- a/database/sqlite/hook_list_test.go +++ b/database/sqlite/hook_list_test.go @@ -36,6 +36,7 @@ func TestSqlite_Client_GetHookList(t *testing.T) { _hookOne.SetBuildID(1) _hookOne.SetNumber(1) _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) _hookTwo := testHook() _hookTwo.SetID(2) @@ -43,6 +44,7 @@ func TestSqlite_Client_GetHookList(t *testing.T) { _hookTwo.SetBuildID(2) _hookTwo.SetNumber(2) _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) // setup the test database client _database, err := NewTest() @@ -104,6 +106,7 @@ func TestSqlite_Client_GetRepoHookList(t *testing.T) { _hookOne.SetBuildID(1) _hookOne.SetNumber(1) _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) _hookTwo := testHook() _hookTwo.SetID(2) @@ -111,6 +114,7 @@ func TestSqlite_Client_GetRepoHookList(t *testing.T) { _hookTwo.SetBuildID(2) _hookTwo.SetNumber(2) _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) _repo := testRepo() _repo.SetID(1) diff --git a/database/sqlite/hook_test.go b/database/sqlite/hook_test.go index 91a8c0fb5..1ac6fe85d 100644 --- a/database/sqlite/hook_test.go +++ b/database/sqlite/hook_test.go @@ -26,6 +26,7 @@ func TestSqlite_Client_GetHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, err := NewTest() @@ -98,6 +99,7 @@ func TestSqlite_Client_GetLastHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, err := NewTest() @@ -163,6 +165,7 @@ func TestSqlite_Client_CreateHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, err := NewTest() @@ -210,6 +213,7 @@ func TestSqlite_Client_UpdateHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, err := NewTest() @@ -263,6 +267,7 @@ func TestSqlite_Client_DeleteHook(t *testing.T) { _hook.SetBuildID(1) _hook.SetNumber(1) _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) // setup the test database client _database, err := NewTest() diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 291235644..5702c76cd 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -39,6 +40,7 @@ type ( Sqlite *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + pipeline.PipelineService } ) @@ -88,6 +90,12 @@ func New(opts ...ClientOpt) (*client, error) { return nil, err } + // create the services for the database + err = createServices(c) + if err != nil { + return nil, err + } + return c, nil } @@ -119,7 +127,7 @@ func NewTest() (*client, error) { // create new logger for the client // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger) + c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) // create the new Sqlite database client // @@ -134,6 +142,12 @@ func NewTest() (*client, error) { c.Sqlite = _sqlite + // setup database with proper configuration + err = createServices(c) + if err != nil { + return nil, err + } + // create the tables in the database err = createTables(c) if err != nil { @@ -332,3 +346,23 @@ func createIndexes(c *client) error { return nil } + +// createServices is a helper function to create the database services. +func createServices(c *client) error { + var err error + + // create the database agnostic pipeline service + // + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New + c.PipelineService, err = pipeline.New( + pipeline.WithClient(c.Sqlite), + pipeline.WithCompressionLevel(c.config.CompressionLevel), + pipeline.WithLogger(c.Logger), + pipeline.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index 7b3a1af87..ef6078fa2 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.13.0 + github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67 github.com/golang-jwt/jwt/v4 v4.4.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 diff --git a/go.sum b/go.sum index de0a6a880..27c8853cb 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.0 h1:PX/0wtKMXbtqHbrWgwlCDzuBzeh+4V042k56siDSm1o= -github.com/go-vela/types v0.13.0/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= +github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67 h1:j/NvYiMObvY5y9tQ9mTXqrwHyGQG4IQI3HXf/ISCvD0= +github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 9d311e4e8..8c690bcce 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -52,6 +52,7 @@ func TestBuild_Establish(t *testing.T) { want := new(library.Build) want.SetID(1) want.SetRepoID(1) + want.SetPipelineID(0) want.SetNumber(1) want.SetParent(1) want.SetEvent("") From 0022c658a35afe7dbd2c8d9a8f4d155632a2e371 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Apr 2022 10:43:18 -0500 Subject: [PATCH 037/298] chore(deps): update codecov/codecov-action action to v3 (#624) Co-authored-by: Renovate Bot --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f6f20f5bd..713423a15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: go test -race -covermode=atomic -coverprofile=coverage.out ./... - name: coverage - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: coverage.out From 9afad20aee77ca72a7c7f1a0d337fd06c073f684 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 09:37:08 -0500 Subject: [PATCH 038/298] fix(deps): update golang.org/x/oauth2 digest to 6242fa9 (#623) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ef6078fa2..b86be49f4 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.4.0 go.starlark.net v0.0.0-20220302181546-5411bad688d1 - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b + golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.1 diff --git a/go.sum b/go.sum index 27c8853cb..266dd42cf 100644 --- a/go.sum +++ b/go.sum @@ -730,8 +730,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 11d7429e01fe0352042a0bd25a74aa0ae8da16dc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 10:19:50 -0500 Subject: [PATCH 039/298] fix(deps): update go.starlark.net digest to d1966c6 (#621) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b86be49f4..a9716b363 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.1 github.com/urfave/cli/v2 v2.4.0 - go.starlark.net v0.0.0-20220302181546-5411bad688d1 + go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 266dd42cf..12b7742a4 100644 --- a/go.sum +++ b/go.sum @@ -609,8 +609,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220302181546-5411bad688d1 h1:i0Sz4b+qJi5xwOaFZqZ+RNHkIpaKLDofei/Glt+PMNc= -go.starlark.net v0.0.0-20220302181546-5411bad688d1/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM= +go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From cb09250099ae23b9648c6fc9488cfa843c69926a Mon Sep 17 00:00:00 2001 From: Dan Tanner Date: Tue, 12 Apr 2022 16:35:48 -0500 Subject: [PATCH 040/298] modify CI environment value to true (#619) --- compiler/native/environment.go | 2 +- compiler/native/environment_test.go | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/native/environment.go b/compiler/native/environment.go index b6765cf47..7536731a6 100644 --- a/compiler/native/environment.go +++ b/compiler/native/environment.go @@ -306,7 +306,7 @@ func environment(b *library.Build, m *types.Metadata, r *library.Repo, u *librar env["VELA_RUNTIME"] = notImplemented env["VELA_SOURCE"] = notImplemented env["VELA_VERSION"] = notImplemented - env["CI"] = "vela" + env["CI"] = "true" // populate environment variables from metadata if m != nil { diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index f638f41ea..b95d018c5 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -126,7 +126,7 @@ func TestNative_EnvironmentSteps(t *testing.T) { "BUILD_STATUS": "", "BUILD_TITLE": "", "BUILD_WORKSPACE": "/vela/src", - "CI": "vela", + "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", @@ -273,7 +273,7 @@ func TestNative_EnvironmentServices(t *testing.T) { "BUILD_STATUS": "", "BUILD_TITLE": "", "BUILD_WORKSPACE": "/vela/src", - "CI": "vela", + "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", @@ -431,7 +431,7 @@ func TestNative_EnvironmentSecrets(t *testing.T) { "BUILD_STATUS": "", "BUILD_TITLE": "", "BUILD_WORKSPACE": "/vela/src", - "CI": "vela", + "CI": "true", "PARAMETER_FOO": "bar", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", @@ -565,7 +565,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { @@ -574,7 +574,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { @@ -583,7 +583,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { @@ -592,7 +592,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, }, } @@ -679,27 +679,27 @@ func Test_client_EnvironmentBuild(t *testing.T) { metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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, 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: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "vela", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, }, } for _, tt := range tests { From d3ce0c936da395580ad940a033b88640b170233d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 18 Apr 2022 14:43:36 -0600 Subject: [PATCH 041/298] feat(hook): set webhook_id in process webhook function (#625) * set webhook_id in process webhook function * format error in return statement --- scm/github/webhook.go | 8 ++++++++ scm/github/webhook_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 38c9bca28..9b55c16f0 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "strings" "time" @@ -27,6 +28,13 @@ func (c *client) ProcessWebhook(request *http.Request) (*types.Webhook, error) { h := new(library.Hook) h.SetNumber(1) h.SetSourceID(request.Header.Get("X-GitHub-Delivery")) + + hookID, err := strconv.Atoi(request.Header.Get("X-GitHub-Hook-ID")) + if err != nil { + return nil, fmt.Errorf("unable to convert hook id to int64: %w", err) + } + + h.SetWebhookID(int64(hookID)) h.SetCreated(time.Now().UTC().Unix()) h.SetHost("github.com") h.SetEvent(request.Header.Get("X-GitHub-Event")) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 3ae551d33..98aab8daa 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -39,6 +39,7 @@ func TestGithub_ProcessWebhook_Push(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Event", "push") // setup client @@ -48,6 +49,7 @@ func TestGithub_ProcessWebhook_Push(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("push") @@ -113,6 +115,7 @@ func TestGithub_ProcessWebhook_Push_NoSender(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "push") @@ -124,6 +127,7 @@ func TestGithub_ProcessWebhook_Push_NoSender(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("push") @@ -189,6 +193,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "pull_request") @@ -200,6 +205,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("pull_request") @@ -267,6 +273,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedAction(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "pull_request") @@ -278,6 +285,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedAction(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("pull_request") @@ -320,6 +328,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedState(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "pull_request") @@ -331,6 +340,7 @@ func TestGithub_ProcessWebhook_PullRequest_ClosedState(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("pull_request") @@ -364,6 +374,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetBranch("master") wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") @@ -425,6 +436,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "deployment") @@ -469,6 +481,7 @@ func TestGithub_ProcessWebhook_Deployment_Commit(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "deployment") @@ -480,6 +493,7 @@ func TestGithub_ProcessWebhook_Deployment_Commit(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetBranch("master") wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") @@ -545,6 +559,7 @@ func TestGithub_ProcessWebhook_BadGithubEvent(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "foobar") @@ -556,6 +571,7 @@ func TestGithub_ProcessWebhook_BadGithubEvent(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("foobar") @@ -596,6 +612,7 @@ func TestGithub_ProcessWebhook_BadContentType(t *testing.T) { request.Header.Set("Content-Type", "foobar") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "pull_request") @@ -607,6 +624,7 @@ func TestGithub_ProcessWebhook_BadContentType(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("pull_request") @@ -647,6 +665,7 @@ func TestGithub_VerifyWebhook_EmptyRepo(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "deployment") @@ -687,6 +706,7 @@ func TestGithub_VerifyWebhook_NoSecret(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "push") @@ -718,6 +738,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "issue_comment") @@ -729,6 +750,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("comment") @@ -791,6 +813,7 @@ func TestGithub_ProcessWebhook_IssueComment_Created(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "issue_comment") @@ -802,6 +825,7 @@ func TestGithub_ProcessWebhook_IssueComment_Created(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("comment") @@ -864,6 +888,7 @@ func TestGithub_ProcessWebhook_IssueComment_Deleted(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Host", "github.com") request.Header.Set("X-GitHub-Version", "2.16.0") request.Header.Set("X-GitHub-Event", "issue_comment") @@ -875,6 +900,7 @@ func TestGithub_ProcessWebhook_IssueComment_Deleted(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("comment") @@ -917,6 +943,7 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Event", "repository") // setup client @@ -926,6 +953,7 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("repositoryRename") @@ -977,6 +1005,7 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { request.Header.Set("Content-Type", "application/json") request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") request.Header.Set("X-GitHub-Event", "repository") // setup client @@ -986,6 +1015,7 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { wantHook := new(library.Hook) wantHook.SetNumber(1) wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") wantHook.SetEvent("repository") From 29562a46eb6d88e85cf037f6a073b6a83d50cae5 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 20 Apr 2022 10:10:02 -0500 Subject: [PATCH 042/298] chore: remove number field from Pipeline{} (#626) * chore: remove number field from pipelines * chore: update go-vela/types dependency Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- database/pipeline/count_repo_test.go | 12 ++-- database/pipeline/count_test.go | 4 +- database/pipeline/create.go | 4 +- database/pipeline/create_test.go | 8 +-- database/pipeline/delete.go | 4 +- database/pipeline/delete_test.go | 2 +- database/pipeline/get_repo.go | 8 +-- database/pipeline/get_repo_test.go | 10 +-- database/pipeline/get_test.go | 6 +- database/pipeline/last_repo.go | 48 ------------- database/pipeline/last_repo_test.go | 102 --------------------------- database/pipeline/list_repo_test.go | 19 ++--- database/pipeline/list_test.go | 12 ++-- database/pipeline/pipeline_test.go | 1 - database/pipeline/service.go | 6 +- database/pipeline/table.go | 6 +- database/pipeline/update.go | 4 +- database/pipeline/update_test.go | 8 +-- go.mod | 4 +- go.sum | 8 +-- 20 files changed, 61 insertions(+), 215 deletions(-) delete mode 100644 database/pipeline/last_repo.go delete mode 100644 database/pipeline/last_repo_test.go diff --git a/database/pipeline/count_repo_test.go b/database/pipeline/count_repo_test.go index aff714085..9cb91b72b 100644 --- a/database/pipeline/count_repo_test.go +++ b/database/pipeline/count_repo_test.go @@ -17,15 +17,15 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { _pipelineOne := testPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) - _pipelineOne.SetNumber(1) + _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipelineOne.SetRef("refs/heads/master") _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") _pipelineTwo := testPipeline() _pipelineTwo.SetID(2) - _pipelineTwo.SetRepoID(2) - _pipelineTwo.SetNumber(1) + _pipelineTwo.SetRepoID(1) + _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") _pipelineTwo.SetRef("refs/heads/main") _pipelineTwo.SetType("yaml") _pipelineTwo.SetVersion("1") @@ -34,7 +34,7 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // create expected result in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) // ensure the mock expects the query _mock.ExpectQuery(`SELECT count(*) FROM "pipelines" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) @@ -63,13 +63,13 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { failure: false, name: "postgres", database: _postgres, - want: 1, + want: 2, }, { failure: false, name: "sqlite3", database: _sqlite, - want: 1, + want: 2, }, } diff --git a/database/pipeline/count_test.go b/database/pipeline/count_test.go index 2885b5c6b..a811b01df 100644 --- a/database/pipeline/count_test.go +++ b/database/pipeline/count_test.go @@ -16,7 +16,7 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { _pipelineOne := testPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) - _pipelineOne.SetNumber(1) + _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipelineOne.SetRef("refs/heads/master") _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") @@ -24,7 +24,7 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { _pipelineTwo := testPipeline() _pipelineTwo.SetID(2) _pipelineTwo.SetRepoID(2) - _pipelineTwo.SetNumber(1) + _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") _pipelineTwo.SetRef("refs/heads/main") _pipelineTwo.SetType("yaml") _pipelineTwo.SetVersion("1") diff --git a/database/pipeline/create.go b/database/pipeline/create.go index bc6a5aff8..5d6e4771f 100644 --- a/database/pipeline/create.go +++ b/database/pipeline/create.go @@ -14,8 +14,8 @@ import ( // CreatePipeline creates a new pipeline in the database. func (e *engine) CreatePipeline(p *library.Pipeline) error { e.logger.WithFields(logrus.Fields{ - "pipeline": p.GetNumber(), - }).Tracef("creating pipeline %d in the database", p.GetNumber()) + "pipeline": p.GetCommit(), + }).Tracef("creating pipeline %s in the database", p.GetCommit()) // cast the library type to database type // diff --git a/database/pipeline/create_test.go b/database/pipeline/create_test.go index eced618bf..be29ad8fd 100644 --- a/database/pipeline/create_test.go +++ b/database/pipeline/create_test.go @@ -15,7 +15,7 @@ func TestPipeline_Engine_CreatePipeline(t *testing.T) { _pipeline := testPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) - _pipeline.SetNumber(1) + _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") @@ -28,9 +28,9 @@ func TestPipeline_Engine_CreatePipeline(t *testing.T) { // ensure the mock expects the query _mock.ExpectQuery(`INSERT INTO "pipelines" -("repo_id","number","commit","flavor","platform","ref","type","version","external_secrets","internal_secrets","services","stages","steps","templates","data","id") -VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`). - WithArgs(1, 1, nil, nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). +("repo_id","commit","flavor","platform","ref","type","version","external_secrets","internal_secrets","services","stages","steps","templates","data","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). + WithArgs(1, "48afb5bdc41ad69bf22588491333f7cf71135163", nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). WillReturnRows(_rows) _sqlite := testSqlite(t) diff --git a/database/pipeline/delete.go b/database/pipeline/delete.go index 6b0360fa0..eb03db88c 100644 --- a/database/pipeline/delete.go +++ b/database/pipeline/delete.go @@ -14,8 +14,8 @@ import ( // DeletePipeline deletes an existing pipeline from the database. func (e *engine) DeletePipeline(p *library.Pipeline) error { e.logger.WithFields(logrus.Fields{ - "pipeline": p.GetNumber(), - }).Tracef("deleting pipeline %d from the database", p.GetNumber()) + "pipeline": p.GetCommit(), + }).Tracef("deleting pipeline %s from the database", p.GetCommit()) // cast the library type to database type // diff --git a/database/pipeline/delete_test.go b/database/pipeline/delete_test.go index 0ccfa21a3..ff3e7f892 100644 --- a/database/pipeline/delete_test.go +++ b/database/pipeline/delete_test.go @@ -15,7 +15,7 @@ func TestPipeline_Engine_DeletePipeline(t *testing.T) { _pipeline := testPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) - _pipeline.SetNumber(1) + _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") diff --git a/database/pipeline/get_repo.go b/database/pipeline/get_repo.go index c181fc7b7..6df601b08 100644 --- a/database/pipeline/get_repo.go +++ b/database/pipeline/get_repo.go @@ -12,12 +12,12 @@ import ( ) // GetPipelineForRepo gets a pipeline by number and repo ID from the database. -func (e *engine) GetPipelineForRepo(number int, r *library.Repo) (*library.Pipeline, error) { +func (e *engine) GetPipelineForRepo(commit string, r *library.Repo) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), - "pipeline": number, + "pipeline": commit, "repo": r.GetName(), - }).Tracef("getting pipeline %s/%d from the database", r.GetFullName(), number) + }).Tracef("getting pipeline %s/%s from the database", r.GetFullName(), commit) // variable to store query results p := new(database.Pipeline) @@ -26,7 +26,7 @@ func (e *engine) GetPipelineForRepo(number int, r *library.Repo) (*library.Pipel err := e.client. Table(constants.TablePipeline). Where("repo_id = ?", r.GetID()). - Where("number = ?", number). + Where("\"commit\" = ?", commit). Limit(1). Scan(p). Error diff --git a/database/pipeline/get_repo_test.go b/database/pipeline/get_repo_test.go index c641e9ff6..bb956d469 100644 --- a/database/pipeline/get_repo_test.go +++ b/database/pipeline/get_repo_test.go @@ -17,7 +17,7 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { _pipeline := testPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) - _pipeline.SetNumber(1) + _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") @@ -28,11 +28,11 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). - AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + []string{"id", "repo_id", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, "48afb5bdc41ad69bf22588491333f7cf71135163", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) // ensure the mock expects the query - _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 AND "commit" = $2 LIMIT 1`).WithArgs(1, "48afb5bdc41ad69bf22588491333f7cf71135163").WillReturnRows(_rows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -66,7 +66,7 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetPipelineForRepo(1, &library.Repo{ID: _pipeline.RepoID}) + got, err := test.database.GetPipelineForRepo("48afb5bdc41ad69bf22588491333f7cf71135163", &library.Repo{ID: _pipeline.RepoID}) if test.failure { if err == nil { diff --git a/database/pipeline/get_test.go b/database/pipeline/get_test.go index d26db6d8a..050a06c3d 100644 --- a/database/pipeline/get_test.go +++ b/database/pipeline/get_test.go @@ -17,7 +17,7 @@ func TestPipeline_Engine_GetPipeline(t *testing.T) { _pipeline := testPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) - _pipeline.SetNumber(1) + _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") @@ -28,8 +28,8 @@ func TestPipeline_Engine_GetPipeline(t *testing.T) { // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). - AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + []string{"id", "repo_id", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, "48afb5bdc41ad69bf22588491333f7cf71135163", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) diff --git a/database/pipeline/last_repo.go b/database/pipeline/last_repo.go deleted file mode 100644 index dbbb46aeb..000000000 --- a/database/pipeline/last_repo.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package pipeline - -import ( - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// LastPipelineForRepo gets the last pipeline by repo ID from the database. -func (e *engine) LastPipelineForRepo(r *library.Repo) (*library.Pipeline, error) { - e.logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting last pipeline for repo %s from the database", r.GetFullName()) - - // variable to store query results - p := new(database.Pipeline) - - // send query to the database and store result in variable - err := e.client. - Table(constants.TablePipeline). - Where("repo_id = ?", r.GetID()). - Order("number DESC"). - Limit(1). - Scan(p). - Error - if err != nil { - return nil, err - } - - // decompress data for the pipeline - // - // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Decompress - err = p.Decompress() - if err != nil { - return nil, err - } - - // return the decompressed pipeline - // - // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.ToLibrary - return p.ToLibrary(), nil -} diff --git a/database/pipeline/last_repo_test.go b/database/pipeline/last_repo_test.go deleted file mode 100644 index ef4a91a65..000000000 --- a/database/pipeline/last_repo_test.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package pipeline - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/types/library" -) - -func TestPipeline_Engine_LastPipelineForRepo(t *testing.T) { - // setup types - _pipelineOne := testPipeline() - _pipelineOne.SetID(1) - _pipelineOne.SetRepoID(1) - _pipelineOne.SetNumber(1) - _pipelineOne.SetRef("refs/heads/master") - _pipelineOne.SetType("yaml") - _pipelineOne.SetVersion("1") - _pipelineOne.SetData([]byte("foo")) - - _pipelineTwo := testPipeline() - _pipelineTwo.SetID(2) - _pipelineTwo.SetRepoID(1) - _pipelineTwo.SetNumber(2) - _pipelineTwo.SetRef("refs/heads/main") - _pipelineTwo.SetType("yaml") - _pipelineTwo.SetVersion("1") - _pipelineTwo.SetData([]byte("foo")) - - _postgres, _mock := testPostgres(t) - defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() - - // create expected result in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). - AddRow(2, 1, 2, "", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) - - // ensure the mock expects the query - _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 ORDER BY number DESC LIMIT 1`).WithArgs(1).WillReturnRows(_rows) - - _sqlite := testSqlite(t) - defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - - err := _sqlite.CreatePipeline(_pipelineOne) - if err != nil { - t.Errorf("unable to create test pipeline for sqlite: %v", err) - } - - err = _sqlite.CreatePipeline(_pipelineTwo) - if err != nil { - t.Errorf("unable to create test pipeline for sqlite: %v", err) - } - - // setup tests - tests := []struct { - failure bool - name string - database *engine - want *library.Pipeline - }{ - { - failure: false, - name: "postgres", - database: _postgres, - want: _pipelineTwo, - }, - { - failure: false, - name: "sqlite3", - database: _sqlite, - want: _pipelineTwo, - }, - } - - // run tests - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got, err := test.database.LastPipelineForRepo(&library.Repo{ID: _pipelineOne.RepoID}) - - if test.failure { - if err == nil { - t.Errorf("LastPipelineForRepo for %s should have returned err", test.name) - } - - return - } - - if err != nil { - t.Errorf("LastPipelineForRepo for %s returned err: %v", test.name, err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("LastPipelineForRepo for %s is %v, want %v", test.name, got, test.want) - } - }) - } -} diff --git a/database/pipeline/list_repo_test.go b/database/pipeline/list_repo_test.go index 3fc806a55..c1eaef193 100644 --- a/database/pipeline/list_repo_test.go +++ b/database/pipeline/list_repo_test.go @@ -17,7 +17,7 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { _pipelineOne := testPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) - _pipelineOne.SetNumber(1) + _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipelineOne.SetRef("refs/heads/master") _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") @@ -25,8 +25,8 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { _pipelineTwo := testPipeline() _pipelineTwo.SetID(2) - _pipelineTwo.SetRepoID(2) - _pipelineTwo.SetNumber(1) + _pipelineTwo.SetRepoID(1) + _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") _pipelineTwo.SetRef("refs/heads/main") _pipelineTwo.SetType("yaml") _pipelineTwo.SetVersion("1") @@ -43,11 +43,12 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). - AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + []string{"id", "repo_id", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, "48afb5bdc41ad69bf22588491333f7cf71135163", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}). + AddRow(2, 1, "a49aaf4afae6431a79239c95247a2b169fd9f067", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) // ensure the mock expects the query - _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "pipelines" WHERE repo_id = $1 LIMIT 10`).WithArgs(1).WillReturnRows(_rows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -73,20 +74,20 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { failure: false, name: "postgres", database: _postgres, - want: []*library.Pipeline{_pipelineOne}, + want: []*library.Pipeline{_pipelineOne, _pipelineTwo}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.Pipeline{_pipelineOne}, + want: []*library.Pipeline{_pipelineOne, _pipelineTwo}, }, } // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}, 1, 1) + got, _, err := test.database.ListPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}, 1, 10) if test.failure { if err == nil { diff --git a/database/pipeline/list_test.go b/database/pipeline/list_test.go index 0ba2c98dc..bcd5dcef5 100644 --- a/database/pipeline/list_test.go +++ b/database/pipeline/list_test.go @@ -17,7 +17,7 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { _pipelineOne := testPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) - _pipelineOne.SetNumber(1) + _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipelineOne.SetRef("refs/heads/master") _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") @@ -25,8 +25,8 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { _pipelineTwo := testPipeline() _pipelineTwo.SetID(2) - _pipelineTwo.SetRepoID(1) - _pipelineTwo.SetNumber(2) + _pipelineTwo.SetRepoID(2) + _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") _pipelineTwo.SetRef("refs/heads/main") _pipelineTwo.SetType("yaml") _pipelineTwo.SetVersion("1") @@ -43,9 +43,9 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "number", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). - AddRow(1, 1, 1, "", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}). - AddRow(2, 1, 2, "", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) + []string{"id", "repo_id", "commit", "flavor", "platform", "ref", "type", "version", "services", "stages", "steps", "templates", "data"}). + AddRow(1, 1, "48afb5bdc41ad69bf22588491333f7cf71135163", "", "", "refs/heads/master", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}). + AddRow(2, 2, "a49aaf4afae6431a79239c95247a2b169fd9f067", "", "", "refs/heads/main", "yaml", "1", false, false, false, false, []byte{120, 94, 74, 203, 207, 7, 4, 0, 0, 255, 255, 2, 130, 1, 69}) // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "pipelines"`).WillReturnRows(_rows) diff --git a/database/pipeline/pipeline_test.go b/database/pipeline/pipeline_test.go index 7456066fb..f478fe37f 100644 --- a/database/pipeline/pipeline_test.go +++ b/database/pipeline/pipeline_test.go @@ -178,7 +178,6 @@ func testPipeline() *library.Pipeline { return &library.Pipeline{ ID: new(int64), RepoID: new(int64), - Number: new(int), Commit: new(string), Flavor: new(string), Platform: new(string), diff --git a/database/pipeline/service.go b/database/pipeline/service.go index 3a3fd45de..a34e75a28 100644 --- a/database/pipeline/service.go +++ b/database/pipeline/service.go @@ -36,10 +36,8 @@ type PipelineService interface { DeletePipeline(*library.Pipeline) error // GetPipeline defines a function that gets a pipeline by ID. GetPipeline(int64) (*library.Pipeline, error) - // GetPipelineForRepo defines a function that gets a pipeline by number and repo ID. - GetPipelineForRepo(int, *library.Repo) (*library.Pipeline, error) - // LastPipelineForRepo defines a function that gets the last pipeline by repo ID. - LastPipelineForRepo(*library.Repo) (*library.Pipeline, error) + // GetPipelineForRepo defines a function that gets a pipeline by commit SHA and repo ID. + GetPipelineForRepo(string, *library.Repo) (*library.Pipeline, error) // ListPipelines defines a function that gets a list of all pipelines. ListPipelines() ([]*library.Pipeline, error) // ListPipelinesForRepo defines a function that gets a list of pipelines by repo ID. diff --git a/database/pipeline/table.go b/database/pipeline/table.go index 28810c408..b4c222e7b 100644 --- a/database/pipeline/table.go +++ b/database/pipeline/table.go @@ -14,7 +14,6 @@ IF NOT EXISTS pipelines ( id SERIAL PRIMARY KEY, repo_id INTEGER, - number INTEGER, commit VARCHAR(500), flavor VARCHAR(100), platform VARCHAR(100), @@ -28,7 +27,7 @@ pipelines ( steps BOOLEAN, templates BOOLEAN, data BYTEA, - UNIQUE(repo_id, number) + UNIQUE(repo_id, commit) ); ` @@ -39,7 +38,6 @@ IF NOT EXISTS pipelines ( id INTEGER PRIMARY KEY AUTOINCREMENT, repo_id INTEGER, - number INTEGER, 'commit' TEXT, flavor TEXT, platform TEXT, @@ -53,7 +51,7 @@ pipelines ( steps BOOLEAN, templates BOOLEAN, data BLOB, - UNIQUE(repo_id, number) + UNIQUE(repo_id, 'commit') ); ` ) diff --git a/database/pipeline/update.go b/database/pipeline/update.go index ad6bc5671..85add5411 100644 --- a/database/pipeline/update.go +++ b/database/pipeline/update.go @@ -14,8 +14,8 @@ import ( // UpdatePipeline updates an existing pipeline in the database. func (e *engine) UpdatePipeline(p *library.Pipeline) error { e.logger.WithFields(logrus.Fields{ - "pipeline": p.GetNumber(), - }).Tracef("updating pipeline %d in the database", p.GetNumber()) + "pipeline": p.GetCommit(), + }).Tracef("updating pipeline %s in the database", p.GetCommit()) // cast the library type to database type // diff --git a/database/pipeline/update_test.go b/database/pipeline/update_test.go index adb6fbeb1..33e18d738 100644 --- a/database/pipeline/update_test.go +++ b/database/pipeline/update_test.go @@ -15,7 +15,7 @@ func TestPipeline_Engine_UpdatePipeline(t *testing.T) { _pipeline := testPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) - _pipeline.SetNumber(1) + _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") @@ -25,9 +25,9 @@ func TestPipeline_Engine_UpdatePipeline(t *testing.T) { // ensure the mock expects the query _mock.ExpectExec(`UPDATE "pipelines" -SET "repo_id"=$1,"number"=$2,"commit"=$3,"flavor"=$4,"platform"=$5,"ref"=$6,"type"=$7,"version"=$8,"external_secrets"=$9,"internal_secrets"=$10,"services"=$11,"stages"=$12,"steps"=$13,"templates"=$14,"data"=$15 -WHERE "id" = $16`). - WithArgs(1, 1, nil, nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). +SET "repo_id"=$1,"commit"=$2,"flavor"=$3,"platform"=$4,"ref"=$5,"type"=$6,"version"=$7,"external_secrets"=$8,"internal_secrets"=$9,"services"=$10,"stages"=$11,"steps"=$12,"templates"=$13,"data"=$14 +WHERE "id" = $15`). + WithArgs(1, "48afb5bdc41ad69bf22588491333f7cf71135163", nil, nil, "refs/heads/master", "yaml", "1", false, false, false, false, false, false, AnyArgument{}, 1). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) diff --git a/go.mod b/go.mod index a9716b363..44ba2f71d 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.4 - github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67 + github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281 github.com/golang-jwt/jwt/v4 v4.4.0 github.com/google/go-cmp v0.5.7 github.com/google/go-github/v42 v42.0.0 @@ -98,7 +98,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect - github.com/lib/pq v1.10.4 // indirect + github.com/lib/pq v1.10.5 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect diff --git a/go.sum b/go.sum index 12b7742a4..11085422c 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67 h1:j/NvYiMObvY5y9tQ9mTXqrwHyGQG4IQI3HXf/ISCvD0= -github.com/go-vela/types v0.13.1-0.20220328145826-c7a2083f3e67/go.mod h1:n2aGQj5hzLFUvl1LnxyzItaPKSgC7jSiuSq+6XkRly8= +github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281 h1:n+zZS6OkXJ21YaGmDpk8ge4G/8iXBMlKUUUDfZuEc3c= +github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281/go.mod h1:LDI9YXINK8Zz0DvvruJLFLoJyxaxetXme1pZAXvQkhU= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -435,8 +435,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= +github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= From d8f169f1904c1003e0188ee7c8f493df8b36f4cb Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 21 Apr 2022 10:46:53 -0600 Subject: [PATCH 043/298] feat(api/repo): add ability to sort by latest (#611) * feat(api/repo): add ability to sort by latest * make linter happy * make sort_by an enum for api spec * fix weird spacing Co-authored-by: Jordan Brockopp Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/repo.go | 13 ++- api/scm.go | 2 +- api/user.go | 2 +- database/postgres/dml/repo.go | 18 ++++ database/postgres/repo_list.go | 35 +++++--- database/postgres/repo_list_test.go | 83 +++++++++++++++++- database/service.go | 2 +- database/sqlite/dml/repo.go | 18 ++++ database/sqlite/repo_list.go | 34 +++++--- database/sqlite/repo_list_test.go | 126 +++++++++++++++++++++++++++- 10 files changed, 302 insertions(+), 31 deletions(-) diff --git a/api/repo.go b/api/repo.go index 1e86dc7e7..1a3c7a89a 100644 --- a/api/repo.go +++ b/api/repo.go @@ -427,6 +427,14 @@ func GetRepos(c *gin.Context) { // type: integer // maximum: 100 // default: 10 +// - in: query +// name: sort_by +// description: How to sort the results +// type: string +// enum: +// - name +// - latest +// default: name // responses: // '200': // description: Successfully retrieved the repo @@ -488,6 +496,9 @@ func GetOrgRepos(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) + // capture the sort_by query parameter if present + sortBy := c.DefaultQuery("sort_by", "name") + // See if the user is an org admin to bypass individual permission checks perm, err := scm.FromContext(c).OrgAccess(u, org) if err != nil { @@ -513,7 +524,7 @@ func GetOrgRepos(c *gin.Context) { } // send API call to capture the list of repos for the org - r, err := database.FromContext(c).GetOrgRepoList(org, filters, page, perPage) + r, err := database.FromContext(c).GetOrgRepoList(org, filters, page, perPage, sortBy) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) diff --git a/api/scm.go b/api/scm.go index fe072fc0a..4ad82015c 100644 --- a/api/scm.go +++ b/api/scm.go @@ -89,7 +89,7 @@ func SyncRepos(c *gin.Context) { page := 0 // capture all repos belonging to a certain org in database for orgRepos := int64(0); orgRepos < t; orgRepos += 100 { - r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, 100) + r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, 100, "name") if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) diff --git a/api/user.go b/api/user.go index a08df523d..315514c34 100644 --- a/api/user.go +++ b/api/user.go @@ -448,7 +448,7 @@ func GetUserSourceRepos(c *gin.Context) { for page > 0 { // send API call to capture the list of repos for the org - dbReposPart, err := database.FromContext(c).GetOrgRepoList(org, filters, page, 100) + dbReposPart, err := database.FromContext(c).GetOrgRepoList(org, filters, page, 100, "name") if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) diff --git a/database/postgres/dml/repo.go b/database/postgres/dml/repo.go index 3de708b3e..5a1f96cfe 100644 --- a/database/postgres/dml/repo.go +++ b/database/postgres/dml/repo.go @@ -54,5 +54,23 @@ FROM repos; DELETE FROM repos WHERE id = ?; +` + + // ListReposByLastUpdate represents a query to list + // all repos in an org, ordered by latest activity. + // In this case, latest activity is synonymous with + // the created timestamp of the last build for the repo. + ListReposByLastUpdate = ` +SELECT r.* +FROM repos r LEFT JOIN ( + SELECT repos.id, MAX(builds.created) as latest_build + FROM builds INNER JOIN repos + ON builds.repo_id = repos.id + WHERE repos.org = ? + GROUP BY repos.id) t +ON r.id = t.id +ORDER BY latest_build DESC NULLS LAST +LIMIT ? +OFFSET ?; ` ) diff --git a/database/postgres/repo_list.go b/database/postgres/repo_list.go index 52887d2e0..3cafb1a43 100644 --- a/database/postgres/repo_list.go +++ b/database/postgres/repo_list.go @@ -56,7 +56,7 @@ func (c *client) GetRepoList() ([]*library.Repo, error) { } // GetOrgRepoList gets a list of all repos by org from the database. -func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int) ([]*library.Repo, error) { +func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int, sortBy string) ([]*library.Repo, error) { c.Logger.WithFields(logrus.Fields{ "org": org, }).Tracef("listing repos for org %s from the database", org) @@ -68,16 +68,27 @@ func (c *client) GetOrgRepoList(org string, filters map[string]string, page, per offset := perPage * (page - 1) // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Where("org = ?", org). - Where(filters). - Order("name"). - Limit(perPage). - Offset(offset). - Scan(r).Error - if err != nil { - return nil, err + switch sortBy { + case "latest": + err := c.Postgres. + Table(constants.TableRepo). + Raw(dml.ListReposByLastUpdate, org, perPage, offset). + Scan(r).Error + if err != nil { + return nil, err + } + default: + err := c.Postgres. + Table(constants.TableRepo). + Where("org = ?", org). + Where(filters). + Order("name"). + Limit(perPage). + Offset(offset). + Scan(r).Error + if err != nil { + return nil, err + } } // variable we want to return @@ -90,7 +101,7 @@ func (c *client) GetOrgRepoList(org string, filters map[string]string, page, per // decrypt the fields for the repo // // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) + err := tmp.Decrypt(c.config.EncryptionKey) if err != nil { // ensures that the change is backwards compatible // by logging the error instead of returning it diff --git a/database/postgres/repo_list_test.go b/database/postgres/repo_list_test.go index af1a74fd3..feb20bcde 100644 --- a/database/postgres/repo_list_test.go +++ b/database/postgres/repo_list_test.go @@ -149,7 +149,86 @@ func TestPostgres_Client_GetOrgRepoList(t *testing.T) { filters := map[string]string{} // run tests for _, test := range tests { - got, err := _database.GetOrgRepoList("foo", filters, 1, 10) + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") + + if test.failure { + if err == nil { + t.Errorf("GetOrgRepoList should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("GetOrgRepoList returned err: %v", err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) + } + } +} + +func TestPostgres_Client_GetOrgRepoList_LastUpdate(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + _repoOne.SetPreviousName("") + + _repoTwo := testRepo() + _repoTwo.SetID(1) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + _repoTwo.SetPreviousName("oldName") + + // setup the test database client + _database, _mock, err := NewTest() + if err != nil { + t.Errorf("unable to create new postgres test database: %v", err) + } + + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() + + // capture the current expected SQL query + // + // https://gorm.io/docs/sql_builder.html#DryRun-Mode + _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListReposByLastUpdate, "foo", "10", "1").Statement + + // create expected return in mock + _rows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, + ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", ""). + AddRow(1, 1, "baz", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "oldName") + + // ensure the mock expects the query for test case + _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) + + // setup tests + tests := []struct { + failure bool + want []*library.Repo + }{ + { + failure: false, + want: []*library.Repo{_repoOne, _repoTwo}, + }, + } + filters := map[string]string{} + // run tests + for _, test := range tests { + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "latest") if test.failure { if err == nil { @@ -223,7 +302,7 @@ func TestPostgres_Client_GetOrgRepoList_NonAdmin(t *testing.T) { filters["visibility"] = "public" // run tests for _, test := range tests { - got, err := _database.GetOrgRepoList("foo", filters, 1, 10) + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") if test.failure { if err == nil { diff --git a/database/service.go b/database/service.go index a25ff57d3..2c4f880cd 100644 --- a/database/service.go +++ b/database/service.go @@ -128,7 +128,7 @@ type Service interface { GetRepoList() ([]*library.Repo, error) // GetOrgRepoList defines a function that // gets a list of all repos by org excluding repos specified. - GetOrgRepoList(string, map[string]string, int, int) ([]*library.Repo, error) + GetOrgRepoList(string, map[string]string, int, int, string) ([]*library.Repo, error) // GetOrgRepoCount defines a function that // gets the count of repos for an org. GetOrgRepoCount(string, map[string]string) (int64, error) diff --git a/database/sqlite/dml/repo.go b/database/sqlite/dml/repo.go index 3de708b3e..5a1f96cfe 100644 --- a/database/sqlite/dml/repo.go +++ b/database/sqlite/dml/repo.go @@ -54,5 +54,23 @@ FROM repos; DELETE FROM repos WHERE id = ?; +` + + // ListReposByLastUpdate represents a query to list + // all repos in an org, ordered by latest activity. + // In this case, latest activity is synonymous with + // the created timestamp of the last build for the repo. + ListReposByLastUpdate = ` +SELECT r.* +FROM repos r LEFT JOIN ( + SELECT repos.id, MAX(builds.created) as latest_build + FROM builds INNER JOIN repos + ON builds.repo_id = repos.id + WHERE repos.org = ? + GROUP BY repos.id) t +ON r.id = t.id +ORDER BY latest_build DESC NULLS LAST +LIMIT ? +OFFSET ?; ` ) diff --git a/database/sqlite/repo_list.go b/database/sqlite/repo_list.go index 0db0f6fdb..b4807d1ca 100644 --- a/database/sqlite/repo_list.go +++ b/database/sqlite/repo_list.go @@ -56,7 +56,7 @@ func (c *client) GetRepoList() ([]*library.Repo, error) { } // GetOrgRepoList gets a list of all repos by org from the database. -func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int) ([]*library.Repo, error) { +func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int, sortBy string) ([]*library.Repo, error) { c.Logger.WithFields(logrus.Fields{ "org": org, }).Tracef("listing repos for org %s from the database", org) @@ -68,15 +68,27 @@ func (c *client) GetOrgRepoList(org string, filters map[string]string, page, per offset := perPage * (page - 1) // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Where("org = ?", org). - Where(filters). - Limit(perPage). - Offset(offset). - Scan(r).Error - if err != nil { - return nil, err + switch sortBy { + case "latest": + err := c.Sqlite. + Table(constants.TableRepo). + Raw(dml.ListReposByLastUpdate, org, perPage, offset). + Scan(r).Error + if err != nil { + return nil, err + } + default: + err := c.Sqlite. + Table(constants.TableRepo). + Where("org = ?", org). + Where(filters). + Order("name"). + Limit(perPage). + Offset(offset). + Scan(r).Error + if err != nil { + return nil, err + } } // variable we want to return @@ -89,7 +101,7 @@ func (c *client) GetOrgRepoList(org string, filters map[string]string, page, per // decrypt the fields for the repo // // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) + err := tmp.Decrypt(c.config.EncryptionKey) if err != nil { // ensures that the change is backwards compatible // by logging the error instead of returning it diff --git a/database/sqlite/repo_list_test.go b/database/sqlite/repo_list_test.go index 9d20602f2..882e5b3e1 100644 --- a/database/sqlite/repo_list_test.go +++ b/database/sqlite/repo_list_test.go @@ -160,7 +160,7 @@ func TestSqlite_Client_GetOrgRepoList(t *testing.T) { } } - got, err := _database.GetOrgRepoList("foo", filters, 1, 10) + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") if test.failure { if err == nil { @@ -237,7 +237,129 @@ func TestSqlite_Client_GetOrgRepoList_NonAdmin(t *testing.T) { } } - got, err := _database.GetOrgRepoList("foo", filters, 1, 10) + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") + + if test.failure { + if err == nil { + t.Errorf("GetOrgRepoList should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("GetOrgRepoList returned err: %v", err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) + } + } +} + +func TestSqlite_Client_GetOrgRepoList_LastUpdate(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + _repoOne.SetPreviousName("") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + _repoTwo.SetPreviousName("oldName") + + _repoThree := testRepo() + _repoThree.SetID(3) + _repoThree.SetUserID(1) + _repoThree.SetHash("baz") + _repoThree.SetOrg("foo") + _repoThree.SetName("bat") + _repoThree.SetFullName("foo/bat") + _repoThree.SetVisibility("public") + _repoThree.SetPipelineType("yaml") + _repoThree.SetPreviousName("") + + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetCreated(1) + _buildOne.SetNumber(1) + _buildOne.SetRepoID(2) + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetCreated(2) + _buildTwo.SetNumber(1) + _buildTwo.SetRepoID(1) + + _buildThree := testBuild() + _buildThree.SetID(3) + _buildThree.SetCreated(3) + _buildThree.SetNumber(1) + _buildThree.SetRepoID(3) + + // setup the test database client + _database, err := NewTest() + if err != nil { + t.Errorf("unable to create new postgres test database: %v", err) + } + + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + + err = _database.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create build: %v", err) + } + + err = _database.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create build: %v", err) + } + + err = _database.CreateBuild(_buildThree) + if err != nil { + t.Errorf("unable to create build: %v", err) + } + + // setup tests + tests := []struct { + failure bool + want []*library.Repo + }{ + { + failure: false, + want: []*library.Repo{_repoThree, _repoOne, _repoTwo}, + }, + } + + filters := map[string]string{} + + // run tests + for _, test := range tests { + // defer cleanup of the repos table + defer _database.Sqlite.Exec("delete from repos;") + + for _, repo := range test.want { + // create the repo in the database + err := _database.CreateRepo(repo) + if err != nil { + t.Errorf("unable to create test repo: %v", err) + } + } + + got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "latest") if test.failure { if err == nil { From ccfff2af42eea4abeceac8ac3d5b93790b3ef300 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 22 Apr 2022 09:36:19 -0500 Subject: [PATCH 044/298] feat(middleware): add support for pipelines (#627) --- router/middleware/pipeline/context.go | 39 ++++ router/middleware/pipeline/context_test.go | 103 +++++++++ router/middleware/pipeline/doc.go | 12 + router/middleware/pipeline/pipeline.go | 73 ++++++ router/middleware/pipeline/pipeline_test.go | 242 ++++++++++++++++++++ 5 files changed, 469 insertions(+) create mode 100644 router/middleware/pipeline/context.go create mode 100644 router/middleware/pipeline/context_test.go create mode 100644 router/middleware/pipeline/doc.go create mode 100644 router/middleware/pipeline/pipeline.go create mode 100644 router/middleware/pipeline/pipeline_test.go diff --git a/router/middleware/pipeline/context.go b/router/middleware/pipeline/context.go new file mode 100644 index 000000000..6aab4037e --- /dev/null +++ b/router/middleware/pipeline/context.go @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "context" + + "github.com/go-vela/types/library" +) + +const key = "pipeline" + +// Setter defines a context that enables setting values. +type Setter interface { + Set(string, interface{}) +} + +// FromContext returns the Pipeline associated with this context. +func FromContext(c context.Context) *library.Pipeline { + value := c.Value(key) + if value == nil { + return nil + } + + b, ok := value.(*library.Pipeline) + if !ok { + return nil + } + + return b +} + +// ToContext adds the Pipeline to this context if it supports +// the Setter interface. +func ToContext(c Setter, b *library.Pipeline) { + c.Set(key, b) +} diff --git a/router/middleware/pipeline/context_test.go b/router/middleware/pipeline/context_test.go new file mode 100644 index 000000000..ddc5b8bbd --- /dev/null +++ b/router/middleware/pipeline/context_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "reflect" + "testing" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types/library" +) + +func TestPipeline_FromContext(t *testing.T) { + // setup types + _pipeline := new(library.Pipeline) + + gin.SetMode(gin.TestMode) + _context, _ := gin.CreateTestContext(nil) + _context.Set(key, _pipeline) + + _emptyContext, _ := gin.CreateTestContext(nil) + + _nilContext, _ := gin.CreateTestContext(nil) + _nilContext.Set(key, nil) + + _typeContext, _ := gin.CreateTestContext(nil) + _typeContext.Set(key, 1) + + // setup tests + tests := []struct { + name string + context *gin.Context + want *library.Pipeline + }{ + { + name: "context", + context: _context, + want: _pipeline, + }, + { + name: "context with no value", + context: _emptyContext, + want: nil, + }, + { + name: "context with nil value", + context: _nilContext, + want: nil, + }, + { + name: "context with wrong value type", + context: _typeContext, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := FromContext(test.context) + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("FromContext for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +func TestPipeline_ToContext(t *testing.T) { + // setup types + _pipeline := new(library.Pipeline) + + gin.SetMode(gin.TestMode) + _context, _ := gin.CreateTestContext(nil) + + // setup tests + tests := []struct { + name string + context *gin.Context + want *library.Pipeline + }{ + { + name: "context", + context: _context, + want: _pipeline, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ToContext(test.context, test.want) + + got := test.context.Value(key) + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ToContext for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/router/middleware/pipeline/doc.go b/router/middleware/pipeline/doc.go new file mode 100644 index 000000000..70c59a3a4 --- /dev/null +++ b/router/middleware/pipeline/doc.go @@ -0,0 +1,12 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package pipeline provides the ability for inserting +// Vela pipeline resources into or extracting Vela pipeline +// resources from the middleware chain for the API. +// +// Usage: +// +// import "github.com/go-vela/server/router/middleware/pipeline" +package pipeline diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go new file mode 100644 index 000000000..b4cdca1c4 --- /dev/null +++ b/router/middleware/pipeline/pipeline.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// Retrieve gets the pipeline in the given context. +func Retrieve(c *gin.Context) *library.Pipeline { + return FromContext(c) +} + +// Establish sets the pipeline in the given context. +func Establish() gin.HandlerFunc { + return func(c *gin.Context) { + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + if r == nil { + retErr := fmt.Errorf("repo %s/%s not found", c.Param("org"), c.Param("repo")) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + p := c.Param("pipeline") + if len(p) == 0 { + retErr := fmt.Errorf("no pipeline parameter provided") + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p, + "repo": r.GetName(), + "user": u.GetName(), + }).Debugf("reading pipeline %s/%s", r.GetFullName(), p) + + pipeline, err := database.FromContext(c).GetPipelineForRepo(p, r) + if err != nil { + retErr := fmt.Errorf("unable to read pipeline %s/%s: %w", r.GetFullName(), p, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + ToContext(c, pipeline) + + c.Next() + } +} diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go new file mode 100644 index 000000000..1025cdb30 --- /dev/null +++ b/router/middleware/pipeline/pipeline_test.go @@ -0,0 +1,242 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/types/library" +) + +func TestPipeline_Retrieve(t *testing.T) { + // setup types + _pipeline := new(library.Pipeline) + + gin.SetMode(gin.TestMode) + _context, _ := gin.CreateTestContext(nil) + + // setup tests + tests := []struct { + name string + context *gin.Context + want *library.Pipeline + }{ + { + name: "context", + context: _context, + want: _pipeline, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ToContext(test.context, test.want) + + got := Retrieve(test.context) + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Retrieve for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +func TestPipeline_Establish(t *testing.T) { + // setup types + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + want := new(library.Pipeline) + want.SetID(1) + want.SetRepoID(1) + want.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + want.SetFlavor("") + want.SetPlatform("") + want.SetRef("refs/heads/master") + want.SetType("yaml") + want.SetVersion("1") + want.SetExternalSecrets(false) + want.SetInternalSecrets(false) + want.SetServices(false) + want.SetStages(false) + want.SetSteps(false) + want.SetTemplates(false) + want.SetData([]byte{}) + + got := new(library.Pipeline) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from pipelines;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateRepo(r) + _ = db.CreatePipeline(want) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar/48afb5bdc41ad69bf22588491333f7cf71135163", nil) + + // setup mock server + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(Establish()) + engine.GET("/pipelines/:org/:repo/:pipeline", func(c *gin.Context) { + got = Retrieve(c) + + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + 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) + } +} + +func TestPipeline_Establish_NoRepo(t *testing.T) { + // setup database + db, _ := sqlite.NewTest() + defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar/48afb5bdc41ad69bf22588491333f7cf71135163", nil) + + // setup mock server + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(Establish()) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusNotFound { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusNotFound) + } +} + +func TestPipeline_Establish_NoPipelineParameter(t *testing.T) { + // setup types + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateRepo(r) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar", nil) + + // setup mock server + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(Establish()) + engine.GET("/pipelines/:org/:repo", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusBadRequest { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusBadRequest) + } +} + +func TestPipeline_Establish_NoPipeline(t *testing.T) { + // setup types + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateRepo(r) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar/148afb5bdc41ad69bf22588491333f7cf71135163", nil) + + // setup mock server + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(Establish()) + engine.GET("/pipelines/:org/:repo/:pipeline", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusNotFound { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusNotFound) + } +} From 90727d2b465a0e3cf7ded6f42341e1a386a6cca0 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 26 Apr 2022 13:01:42 -0500 Subject: [PATCH 045/298] feat(api)!: add support for pipelines (#615) --- api/build.go | 258 +++++++++++---- api/pipeline.go | 540 -------------------------------- api/pipeline/compile.go | 110 +++++++ api/pipeline/create.go | 121 +++++++ api/pipeline/delete.go | 92 ++++++ api/pipeline/expand.go | 111 +++++++ api/pipeline/get.go | 70 +++++ api/pipeline/list.go | 139 ++++++++ api/pipeline/output.go | 34 ++ api/pipeline/template.go | 150 +++++++++ api/pipeline/update.go | 193 ++++++++++++ api/pipeline/validate.go | 118 +++++++ api/webhook.go | 121 +++++-- compiler/context_test.go | 6 +- compiler/engine.go | 6 +- compiler/native/compile.go | 118 ++++--- compiler/native/compile_test.go | 26 +- compiler/native/parse.go | 51 +-- compiler/native/parse_test.go | 44 +-- go.sum | 2 +- mock/server/pipeline.go | 207 ++++++++---- mock/server/server.go | 14 +- router/pipeline.go | 38 ++- 23 files changed, 1755 insertions(+), 814 deletions(-) delete mode 100644 api/pipeline.go create mode 100644 api/pipeline/compile.go create mode 100644 api/pipeline/create.go create mode 100644 api/pipeline/delete.go create mode 100644 api/pipeline/expand.go create mode 100644 api/pipeline/get.go create mode 100644 api/pipeline/list.go create mode 100644 api/pipeline/output.go create mode 100644 api/pipeline/template.go create mode 100644 api/pipeline/update.go create mode 100644 api/pipeline/validate.go diff --git a/api/build.go b/api/build.go index f70491bd0..add13aa5a 100644 --- a/api/build.go +++ b/api/build.go @@ -85,7 +85,7 @@ import ( // "$ref": "#/definitions/Error" // CreateBuild represents the API handler to create a build in the configured backend. -// nolint: funlen // ignore statement count +// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity func CreateBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) @@ -162,30 +162,24 @@ func CreateBuild(c *gin.Context) { return } - // send API call to capture the last build for the repo - lastBuild, err := database.FromContext(c).GetLastBuild(r) - if err != nil { - retErr := fmt.Errorf("unable to get last build for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // update fields in build object input.SetRepoID(r.GetID()) input.SetStatus(constants.StatusPending) input.SetCreated(time.Now().UTC().Unix()) - input.SetNumber(1) - input.SetParent(input.GetNumber()) - if lastBuild != nil { - input.SetNumber( - lastBuild.GetNumber() + 1, - ) - input.SetParent(lastBuild.GetNumber()) + // set the parent equal to the current repo counter + input.SetParent(r.GetCounter()) + // check if the parent is set to 0 + if input.GetParent() == 0 { + // parent should be "1" if it's the first build ran + input.SetParent(1) } + // update the build numbers based off repo counter + inc := r.GetCounter() + 1 + r.SetCounter(inc) + input.SetNumber(inc) + // populate the build link if a web address is provided if len(m.Vela.WebAddress) > 0 { input.SetLink( @@ -195,8 +189,9 @@ func CreateBuild(c *gin.Context) { // variable to store changeset files var files []string - // check if the build event is not pull_request - if !strings.EqualFold(input.GetEvent(), constants.EventPull) { + // check if the build event is not issue_comment or pull_request + if !strings.EqualFold(input.GetEvent(), constants.EventComment) && + !strings.EqualFold(input.GetEvent(), constants.EventPull) { // send API call to capture list of files changed for the commit files, err = scm.FromContext(c).Changeset(u, r, input.GetCommit()) if err != nil { @@ -208,7 +203,7 @@ func CreateBuild(c *gin.Context) { } } - // handle getting changeset from a pull_request + // check if the build event is a pull_request if strings.EqualFold(input.GetEvent(), constants.EventPull) { // capture number from build number, err := getPRNumberFromBuild(input) @@ -231,18 +226,47 @@ func CreateBuild(c *gin.Context) { } } - // send API call to capture the pipeline configuration file - config, err := scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to get pipeline configuration for %s/%d: %w", r.GetFullName(), input.GetNumber(), err) + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) - util.HandleError(c, http.StatusNotFound, retErr) + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to get pipeline configuration for %s: %w", r.GetFullName(), err) - return + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } else { + config = pipeline.GetData() } + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) + } + + var compiled *library.Pipeline // parse and compile the pipeline configuration file - p, err := compiler.FromContext(c). + p, compiled, err = compiler.FromContext(c). + Duplicate(). WithBuild(input). WithFiles(files). WithMetadata(m). @@ -256,6 +280,13 @@ func CreateBuild(c *gin.Context) { return } + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found skip := skipEmptyBuild(p) @@ -274,6 +305,39 @@ func CreateBuild(c *gin.Context) { return } + // check if the pipeline did not already exist in the database + // + // nolint: dupl // ignore duplicate code + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(input.GetCommit()) + pipeline.SetRef(input.GetRef()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(pipeline) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to create pipeline for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the created pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to create new build: failed to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + input.SetPipelineID(pipeline.GetID()) + // create the objects from the pipeline in the database err = planBuild(database.FromContext(c), p, input, r) if err != nil { @@ -282,6 +346,16 @@ func CreateBuild(c *gin.Context) { return } + // send API call to update repo for ensuring counter is incremented + err = database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to update repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + // send API call to capture the created build input, _ = database.FromContext(c).GetBuild(input.GetNumber(), r) @@ -905,25 +979,8 @@ func RestartBuild(c *gin.Context) { return } - // send API call to capture the last build for the repo - lastBuild, err := database.FromContext(c).GetLastBuild(r) - if err != nil { - retErr := fmt.Errorf("unable to get last build for %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // update the build numbers based off repo counter - inc := r.GetCounter() + 1 - - r.SetCounter(inc) - b.SetNumber(inc) - // update fields in build object b.SetID(0) - b.SetParent(lastBuild.GetNumber()) b.SetCreated(time.Now().UTC().Unix()) b.SetEnqueued(0) b.SetStarted(0) @@ -933,6 +990,13 @@ func RestartBuild(c *gin.Context) { b.SetRuntime("") b.SetDistribution("") + // set the parent equal to the restarted build number + b.SetParent(b.GetNumber()) + // update the build numbers based off repo counter + inc := r.GetCounter() + 1 + r.SetCounter(inc) + b.SetNumber(inc) + // populate the build link if a web address is provided if len(m.Vela.WebAddress) > 0 { b.SetLink( @@ -942,12 +1006,13 @@ func RestartBuild(c *gin.Context) { // variable to store changeset files var files []string - // check if the build event is not pull_request - if !strings.EqualFold(b.GetEvent(), constants.EventPull) { + // check if the build event is not issue_comment or pull_request + if !strings.EqualFold(b.GetEvent(), constants.EventComment) && + !strings.EqualFold(b.GetEvent(), constants.EventPull) { // send API call to capture list of files changed for the commit files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) if err != nil { - retErr := fmt.Errorf("unable to process webhook: failed to get changeset for %s: %w", r.GetFullName(), err) + retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -955,7 +1020,7 @@ func RestartBuild(c *gin.Context) { } } - // handle getting changeset from a pull_request + // check if the build event is a pull_request if strings.EqualFold(b.GetEvent(), constants.EventPull) { // capture number from build number, err := getPRNumberFromBuild(b) @@ -978,18 +1043,57 @@ func RestartBuild(c *gin.Context) { } } - // send API call to capture the pipeline configuration file - config, err := scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", entry, err) + // variables to store pipeline configuration + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) - util.HandleError(c, http.StatusNotFound, retErr) + // check if the build was created after pipeline support was added + if b.GetPipelineID() > 0 { + // send API call to capture the pipeline + pipeline, err = database.FromContext(c).GetPipeline(b.GetPipelineID()) + if err != nil { + retErr := fmt.Errorf("unable to get pipeline for %s: %w", entry, err) - return + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + config = pipeline.GetData() + } else { // keep original behavior for builds ran before pipeline support was added + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) } + var compiled *library.Pipeline // parse and compile the pipeline configuration file - p, err := compiler.FromContext(c). + p, compiled, err = compiler.FromContext(c). + Duplicate(). WithBuild(b). WithFiles(files). WithMetadata(m). @@ -1003,6 +1107,13 @@ func RestartBuild(c *gin.Context) { return } + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found skip := skipEmptyBuild(p) @@ -1013,7 +1124,7 @@ func RestartBuild(c *gin.Context) { // send API call to set the status on the commit err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) if err != nil { - logger.Errorf("unable to set commit status for %s: %v", entry, err) + logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err) } c.JSON(http.StatusOK, skip) @@ -1021,6 +1132,39 @@ func RestartBuild(c *gin.Context) { return } + // check if the pipeline did not already exist in the database + // + // nolint: dupl // ignore duplicate code + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(b.GetCommit()) + pipeline.SetRef(b.GetRef()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(pipeline) + if err != nil { + retErr := fmt.Errorf("unable to create pipeline for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the created pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + b.SetPipelineID(pipeline.GetID()) + // create the objects from the pipeline in the database err = planBuild(database.FromContext(c), p, b, r) if err != nil { diff --git a/api/pipeline.go b/api/pipeline.go deleted file mode 100644 index 575ca9968..000000000 --- a/api/pipeline.go +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/compiler" - "github.com/go-vela/server/compiler/registry/github" - "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/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types" - "github.com/go-vela/types/library" - "github.com/go-vela/types/yaml" - "github.com/sirupsen/logrus" -) - -const ( - outputJSON = "json" - outputYAML = "yaml" -) - -// swagger:operation GET /api/v1/pipelines/{org}/{repo} pipelines GetPipeline -// -// Get a pipeline configuration from the source provider -// -// --- -// produces: -// - application/x-yaml -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: ref -// description: Ref for retrieving pipeline configuration file -// type: string -// - in: query -// name: output -// description: Output string for specifying output format -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the pipeline -// schema: -// "$ref": "#/definitions/PipelineBuild" -// '400': -// description: Unable to retrieve the pipeline configuration templates -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to retrieve the pipeline configuration templates -// schema: -// "$ref": "#/definitions/Error" - -// GetPipeline represents the API handler to capture a -// pipeline configuration for a repo from the the source provider. -func GetPipeline(ctx *gin.Context) { - // capture middleware values - o := org.Retrieve(ctx) - r := repo.Retrieve(ctx) - u := user.Retrieve(ctx) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading pipeline for repo %s", r.GetFullName()) - - config, comp, err := getUnprocessedPipeline(ctx) - if err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{}) - if err != nil { - retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - writeOutput(ctx, pipeline) -} - -// swagger:operation GET /api/v1/pipelines/{org}/{repo}/templates pipelines GetTemplates -// -// Get a map of templates utilized by a pipeline configuration from the source provider -// -// --- -// produces: -// - application/x-yaml -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: ref -// description: Ref for retrieving pipeline configuration file -// type: string -// - in: query -// name: output -// description: Output string for specifying output format -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the map of pipeline templates -// schema: -// "$ref": "#/definitions/Template" -// '400': -// description: Unable to retrieve the pipeline configuration templates -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to retrieve the pipeline configuration templates -// schema: -// "$ref": "#/definitions/Error" - -// GetTemplates represents the API handler to capture a -// map of templates utilized by a pipeline configuration. -func GetTemplates(ctx *gin.Context) { - // capture middleware values - o := org.Retrieve(ctx) - r := repo.Retrieve(ctx) - u := user.Retrieve(ctx) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading templates from pipeline for repo %s", r.GetFullName()) - - config, comp, err := getUnprocessedPipeline(ctx) - if err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - pipeline, err := comp.Parse(config, r.GetPipelineType(), map[string]interface{}{}) - if err != nil { - retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - // create map of templates for response body - templates, err := getTemplateLinks(ctx, pipeline.Templates) - if err != nil { - retErr := fmt.Errorf("unable to set template links for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - writeOutput(ctx, templates) -} - -// swagger:operation POST /api/v1/pipelines/{org}/{repo}/expand pipelines ExpandPipeline -// -// Get and expand a pipeline configuration from the source provider -// -// --- -// produces: -// - application/x-yaml -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: ref -// description: Ref for retrieving pipeline configuration file -// type: string -// - in: query -// name: output -// description: Output string for specifying output format -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved and expanded the pipeline -// type: json -// schema: -// "$ref": "#/definitions/PipelineBuild" -// '400': -// description: Unable to expand the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to retrieve the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" - -// ExpandPipeline represents the API handler to capture and -// expand a pipeline configuration. -// -// nolint: dupl // ignore false positive of duplicate code -func ExpandPipeline(ctx *gin.Context) { - // capture middleware values - o := org.Retrieve(ctx) - r := repo.Retrieve(ctx) - u := user.Retrieve(ctx) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("expanding templates from pipeline for repo %s", r.GetFullName()) - - config, comp, err := getUnprocessedPipeline(ctx) - if err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - pipeline, err := comp.CompileLite(config, true, false, nil) - if err != nil { - retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - writeOutput(ctx, pipeline) -} - -// swagger:operation POST /api/v1/pipelines/{org}/{repo}/validate pipelines ValidatePipeline -// -// Get, expand and validate a pipeline configuration from the source provider -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: ref -// description: Ref for retrieving pipeline configuration file -// type: string -// - in: query -// name: output -// description: Output string for specifying output format -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved, expanded and validated the pipeline -// schema: -// type: string -// '400': -// description: Unable to validate the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to retrieve the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" - -// ValidatePipeline represents the API handler to capture, expand and -// validate a pipeline configuration. -func ValidatePipeline(ctx *gin.Context) { - // capture middleware values - o := org.Retrieve(ctx) - r := repo.Retrieve(ctx) - u := user.Retrieve(ctx) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("validating pipeline for repo %s", r.GetFullName()) - - config, comp, err := getUnprocessedPipeline(ctx) - if err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - template := false - - // check optional template query parameter - if ok, _ := strconv.ParseBool(ctx.DefaultQuery("template", "true")); ok { - template = true - } - - pipeline, err := comp.CompileLite(config, template, false, nil) - if err != nil { - retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - writeOutput(ctx, pipeline) -} - -// swagger:operation POST /api/v1/pipelines/{org}/{repo}/compile pipelines CompilePipeline -// -// Get, expand and compile a pipeline configuration from the source provider -// -// --- -// produces: -// - application/x-yaml -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: ref -// description: Ref for retrieving pipeline configuration file -// type: string -// - in: query -// name: output -// description: Output string for specifying output format -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved and compiled the pipeline -// schema: -// "$ref": "#/definitions/PipelineBuild" -// '400': -// description: Unable to validate the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to retrieve the pipeline configuration -// schema: -// "$ref": "#/definitions/Error" - -// CompilePipeline represents the API handler to capture, -// expand and compile a pipeline configuration. -// nolint: dupl // ignore false positive of duplicate code -func CompilePipeline(ctx *gin.Context) { - // capture middleware values - o := org.Retrieve(ctx) - r := repo.Retrieve(ctx) - u := user.Retrieve(ctx) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("compiling pipeline for repo %s", r.GetFullName()) - - config, comp, err := getUnprocessedPipeline(ctx) - if err != nil { - util.HandleError(ctx, http.StatusBadRequest, err) - - return - } - - pipeline, err := comp.CompileLite(config, true, true, nil) - if err != nil { - retErr := fmt.Errorf("unable to validate pipeline configuration for %s: %w", repoName(ctx), err) - util.HandleError(ctx, http.StatusBadRequest, retErr) - - return - } - - writeOutput(ctx, pipeline) -} - -// getUnprocessedPipeline retrieves the unprocessed pipeline from a given context -// and creates an instance of the compiler with metadata. -func getUnprocessedPipeline(ctx *gin.Context) ([]byte, compiler.Engine, error) { - // capture middleware values - meta := ctx.MustGet("metadata").(*types.Metadata) - repo := repo.Retrieve(ctx) - - // capture query parameters - ref := ctx.DefaultQuery("ref", repo.GetBranch()) - - // send API call to capture the repo owner - user, err := database.FromContext(ctx).GetUser(repo.GetUserID()) - if err != nil { - return nil, nil, fmt.Errorf("unable to get owner for %s: %w", repo.GetFullName(), err) - } - - // send API call to capture the pipeline configuration file - config, err := scm.FromContext(ctx).ConfigBackoff(user, repo, ref) - if err != nil { - return nil, nil, fmt.Errorf("unable to get pipeline configuration for %s: %w", repoName(ctx), err) - } - - // create the compiler with extra information embedded into it - comp := compiler.FromContext(ctx). - WithMetadata(meta). - WithRepo(repo). - WithUser(user) - - return config, comp, nil -} - -// getTemplateLinks helper function that retrieves source provider links -// for a list of templates and returns a map of library templates. -func getTemplateLinks(ctx *gin.Context, templates yaml.TemplateSlice) (map[string]*library.Template, error) { - r := repo.Retrieve(ctx) - - u, err := database.FromContext(ctx).GetUser(r.GetUserID()) - if err != nil { - return nil, err - } - - m := make(map[string]*library.Template) - - for _, t := range templates { - // convert to library type - tmpl := t.ToLibrary() - - // create a new compiler github client for parsing, - // no address or token needed for Parse - cl, err := github.New("", "") - if err != nil { - return nil, fmt.Errorf("unable to create compiler github client: %w", err) - } - - // parse template source - src, err := cl.Parse(tmpl.GetSource()) - if err != nil { - return nil, fmt.Errorf("unable to parse source for %s: %w", tmpl.GetSource(), err) - } - - // retrieve link to template file from github - link, err := scm.FromContext(ctx).GetHTMLURL(u, src.Org, src.Repo, src.Name, src.Ref) - if err != nil { - return nil, fmt.Errorf("unable to get html url for %s/%s/%s/@%s: %w", src.Org, src.Repo, src.Name, src.Ref, err) - } - - // set link to template file - tmpl.SetLink(link) - - m[tmpl.GetName()] = tmpl - } - - return m, nil -} - -// repoName takes the given context and returns a string friendly -// representation with the format of 'repository@reference'. -func repoName(ctx *gin.Context) string { - repo := repo.Retrieve(ctx) - ref := ctx.DefaultQuery("ref", repo.GetBranch()) - - return fmt.Sprintf("%s@%s", repo.GetFullName(), ref) -} - -// writeOutput returns writes output to the request based on the preferred -// output as defined in the request's 'output' query defaulting to YAML. -func writeOutput(ctx *gin.Context, pipeline interface{}) { - output := ctx.DefaultQuery("output", outputYAML) - - // format response body based off output query parameter - switch strings.ToLower(output) { - case outputJSON: - ctx.JSON(http.StatusOK, pipeline) - case outputYAML: - fallthrough - default: - ctx.YAML(http.StatusOK, pipeline) - } -} diff --git a/api/pipeline/compile.go b/api/pipeline/compile.go new file mode 100644 index 000000000..2195b0144 --- /dev/null +++ b/api/pipeline/compile.go @@ -0,0 +1,110 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore similar code with expand +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/pipelines/{org}/{repo}/{pipeline}/compile pipelines CompilePipeline +// +// Get, expand and compile a pipeline from the configured backend +// +// --- +// produces: +// - application/x-yaml +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to retrieve +// required: true +// type: string +// - in: query +// name: output +// description: Output string for specifying output format +// type: string +// default: yaml +// enum: +// - json +// - yaml +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved and compiled the pipeline +// schema: +// "$ref": "#/definitions/PipelineBuild" +// '400': +// description: Unable to validate the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to retrieve the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" + +// CompilePipeline represents the API handler to capture, +// expand and compile a pipeline configuration. +func CompilePipeline(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("compiling pipeline %s", entry) + + // ensure we use the expected pipeline type when compiling + r.SetPipelineType(p.GetType()) + + // create the compiler object + compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + + // compile the pipeline + pipeline, _, err := compiler.CompileLite(p.GetData(), true, true, nil) + if err != nil { + retErr := fmt.Errorf("unable to compile pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + writeOutput(c, pipeline) +} diff --git a/api/pipeline/create.go b/api/pipeline/create.go new file mode 100644 index 000000000..2b8bbfaf0 --- /dev/null +++ b/api/pipeline/create.go @@ -0,0 +1,121 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/pipelines/{org}/{repo} pipelines CreatePipeline +// +// Create a pipeline in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the pipeline to create +// required: true +// schema: +// "$ref": "#/definitions/Pipeline" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the pipeline +// type: json +// schema: +// "$ref": "#/definitions/Pipeline" +// '400': +// description: Unable to create the pipeline +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to create the pipeline +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the pipeline +// schema: +// "$ref": "#/definitions/Error" + +// CreatePipeline represents the API handler to +// create a pipeline in the configured backend. +func CreatePipeline(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logger := logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }) + + logger.Infof("creating new pipeline for repo %s", r.GetFullName()) + + // capture body from API request + input := new(library.Pipeline) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new build for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in pipeline object + input.SetRepoID(r.GetID()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(input) + if err != nil { + retErr := fmt.Errorf("unable to create pipeline %s/%s: %w", r.GetFullName(), input.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created pipeline + p, err := database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) + if err != nil { + retErr := fmt.Errorf("unable to capture pipeline %s/%s: %w", r.GetFullName(), input.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusCreated, p) +} diff --git a/api/pipeline/delete.go b/api/pipeline/delete.go new file mode 100644 index 000000000..da8b0ecf1 --- /dev/null +++ b/api/pipeline/delete.go @@ -0,0 +1,92 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/pipelines/{org}/{repo}/{pipeline} pipelines DeletePipeline +// +// Delete a pipeline from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to delete +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the pipeline +// schema: +// type: string +// '400': +// description: Unable to delete the pipeline +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to delete the pipeline +// schema: +// "$ref": "#/definitions/Error" + +// DeletePipeline represents the API handler to remove +// a pipeline for a repo from the configured backend. +func DeletePipeline(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("deleting pipeline %s", entry) + + // send API call to remove the build + err := database.FromContext(c).DeletePipeline(p) + if err != nil { + retErr := fmt.Errorf("unable to delete pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("pipeline %s deleted", entry)) +} diff --git a/api/pipeline/expand.go b/api/pipeline/expand.go new file mode 100644 index 000000000..0013776e0 --- /dev/null +++ b/api/pipeline/expand.go @@ -0,0 +1,111 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore similar code with compile +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/pipelines/{org}/{repo}/{pipeline}/expand pipelines ExpandPipeline +// +// Get and expand a pipeline from the configured backend +// +// --- +// produces: +// - application/x-yaml +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to retrieve +// required: true +// type: string +// - in: query +// name: output +// description: Output string for specifying output format +// type: string +// default: yaml +// enum: +// - json +// - yaml +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved and expanded the pipeline +// type: json +// schema: +// "$ref": "#/definitions/PipelineBuild" +// '400': +// description: Unable to expand the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to retrieve the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" + +// ExpandPipeline represents the API handler to capture and +// expand a pipeline configuration. +func ExpandPipeline(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("expanding templates for pipeline %s", entry) + + // ensure we use the expected pipeline type when compiling + r.SetPipelineType(p.GetType()) + + // create the compiler object + compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + + // expand the templates in the pipeline + pipeline, _, err := compiler.CompileLite(p.GetData(), true, false, nil) + if err != nil { + retErr := fmt.Errorf("unable to expand pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + writeOutput(c, pipeline) +} diff --git a/api/pipeline/get.go b/api/pipeline/get.go new file mode 100644 index 000000000..45beb61dc --- /dev/null +++ b/api/pipeline/get.go @@ -0,0 +1,70 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/user" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/pipelines/{org}/{repo}/{pipeline} pipelines GetPipeline +// +// Get a pipeline from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to retrieve +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the pipeline +// type: json +// schema: +// "$ref": "#/definitions/Pipeline" + +// GetPipeline represents the API handler to capture +// a pipeline for a repo from the configured backend. +func GetPipeline(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading pipeline %s/%s", r.GetFullName(), p.GetCommit()) + + c.JSON(http.StatusOK, p) +} diff --git a/api/pipeline/list.go b/api/pipeline/list.go new file mode 100644 index 000000000..c6a443bd7 --- /dev/null +++ b/api/pipeline/list.go @@ -0,0 +1,139 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/pipelines/{org}/{repo} pipelines ListPipelines +// +// List pipelines from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the pipelines +// schema: +// type: array +// items: +// "$ref": "#/definitions/Pipeline" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of pipelines +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of pipelines +// schema: +// "$ref": "#/definitions/Error" + +// ListPipelines represents the API handler to capture a list +// of pipelines for a repo from the configured backend. +func ListPipelines(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("listing pipelines for repo %s", r.GetFullName()) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + // + // nolint: gomnd // ignore magic number + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + p, t, err := database.FromContext(c).ListPipelinesForRepo(r, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to list pipelines for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, p) +} diff --git a/api/pipeline/output.go b/api/pipeline/output.go new file mode 100644 index 000000000..c9adfbd97 --- /dev/null +++ b/api/pipeline/output.go @@ -0,0 +1,34 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "net/http" + "strings" + + "github.com/gin-gonic/gin" +) + +const ( + outputJSON = "json" + outputYAML = "yaml" +) + +// writeOutput is a helper function to return the provided value to the +// request based off the output query parameter provided. If no output +// query parameter is provided, then YAML is used by default. +func writeOutput(c *gin.Context, value interface{}) { + output := c.DefaultQuery("output", outputYAML) + + // format response body based off output query parameter + switch strings.ToLower(output) { + case outputJSON: + c.JSON(http.StatusOK, value) + case outputYAML: + fallthrough + default: + c.YAML(http.StatusOK, value) + } +} diff --git a/api/pipeline/template.go b/api/pipeline/template.go new file mode 100644 index 000000000..9992efde8 --- /dev/null +++ b/api/pipeline/template.go @@ -0,0 +1,150 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/compiler/registry/github" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "github.com/go-vela/server/router/middleware/repo" + "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" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/pipelines/{org}/{repo}/{pipeline}/templates pipelines GetTemplates +// +// Get a map of templates utilized by a pipeline from the configured backend +// +// --- +// produces: +// - application/x-yaml +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to retrieve +// required: true +// type: string +// - in: query +// name: output +// description: Output string for specifying output format +// type: string +// default: yaml +// enum: +// - json +// - yaml +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the map of pipeline templates +// schema: +// "$ref": "#/definitions/Template" +// '400': +// description: Unable to retrieve the pipeline configuration templates +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to retrieve the pipeline configuration templates +// schema: +// "$ref": "#/definitions/Error" + +// GetTemplates represents the API handler to capture a +// map of templates utilized by a pipeline configuration. +func GetTemplates(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading templates from pipeline %s", entry) + + // create the compiler object + compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + + // parse the pipeline configuration + pipeline, _, err := compiler.Parse(p.GetData(), p.GetType(), map[string]interface{}{}) + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("unable to parse pipeline %s: %w", entry, err)) + + return + } + + // send API call to capture the repo owner + user, err := database.FromContext(c).GetUser(r.GetUserID()) + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err)) + + return + } + + baseErr := fmt.Sprintf("unable to set template links for %s", entry) + + templates := make(map[string]*library.Template) + for name, template := range pipeline.Templates.Map() { + templates[name] = template.ToLibrary() + + // create a compiler registry client for parsing (no address or token needed for Parse) + registry, err := github.New("", "") + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("%s: unable to create compiler github client: %w", baseErr, err)) + + return + } + + // parse the source for the template using the compiler registry client + src, err := registry.Parse(template.Source) + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("%s: unable to parse source for %s: %w", baseErr, template.Source, err)) + + return + } + + // retrieve link to template file from github + link, err := scm.FromContext(c).GetHTMLURL(user, src.Org, src.Repo, src.Name, src.Ref) + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("%s: unable to get html url for %s/%s/%s/@%s: %w", baseErr, src.Org, src.Repo, src.Name, src.Ref, err)) + + return + } + + // set link to file for template + templates[name].SetLink(link) + } + + writeOutput(c, templates) +} diff --git a/api/pipeline/update.go b/api/pipeline/update.go new file mode 100644 index 000000000..c769cfb7b --- /dev/null +++ b/api/pipeline/update.go @@ -0,0 +1,193 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/pipelines/{org}/{repo}/{pipeline} pipelines UpdatePipeline +// +// Update a pipeline in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to update +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the pipeline to update +// required: true +// schema: +// "$ref": "#/definitions/Pipeline" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the pipeline +// schema: +// "$ref": "#/definitions/Pipeline" +// '404': +// description: Unable to update the pipeline +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the pipeline +// schema: +// "$ref": "#/definitions/Error" + +// UpdatePipeline represents the API handler to update +// a pipeline for a repo in the configured backend. +func UpdatePipeline(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("updating pipeline %s", entry) + + // capture body from API request + input := new(library.Pipeline) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if the Flavor field in the pipeline was provided + if len(input.GetFlavor()) > 0 { + // update the Flavor field + p.SetFlavor(input.GetFlavor()) + } + + // check if the Platform field in the pipeline was provided + if len(input.GetPlatform()) > 0 { + // update the Platform field + p.SetPlatform(input.GetPlatform()) + } + + // check if the Ref field in the pipeline was provided + if len(input.GetRef()) > 0 { + // update the Ref field + p.SetRef(input.GetRef()) + } + + // check if the Type field in the pipeline was provided + if len(input.GetType()) > 0 { + // update the Type field + p.SetType(input.GetType()) + } + + // check if the Version field in the pipeline was provided + if len(input.GetVersion()) > 0 { + // update the Version field + p.SetVersion(input.GetVersion()) + } + + // check if the ExternalSecrets field in the pipeline was provided + if input.ExternalSecrets != nil { + // update the ExternalSecrets field + p.SetExternalSecrets(input.GetExternalSecrets()) + } + + // check if the InternalSecrets field in the pipeline was provided + if input.InternalSecrets != nil { + // update the InternalSecrets field + p.SetInternalSecrets(input.GetInternalSecrets()) + } + + // check if the Services field in the pipeline was provided + if input.Services != nil { + // update the Services field + p.SetServices(input.GetServices()) + } + + // check if the Stages field in the pipeline was provided + if input.Stages != nil { + // update the Stages field + p.SetStages(input.GetStages()) + } + + // check if the Steps field in the pipeline was provided + if input.Steps != nil { + // update the Steps field + p.SetSteps(input.GetSteps()) + } + + // check if the Templates field in the pipeline was provided + if input.Templates != nil { + // update the Templates field + p.SetTemplates(input.GetTemplates()) + } + + // check if the Data field in the pipeline was provided + if len(input.GetData()) > 0 { + // update the data field + p.SetData(input.GetData()) + } + + // send API call to update the pipeline + err = database.FromContext(c).UpdatePipeline(p) + if err != nil { + retErr := fmt.Errorf("unable to update pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated pipeline + p, err = database.FromContext(c).GetPipelineForRepo(p.GetCommit(), r) + if err != nil { + retErr := fmt.Errorf("unable to capture pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, p) +} diff --git a/api/pipeline/validate.go b/api/pipeline/validate.go new file mode 100644 index 000000000..01fa574d3 --- /dev/null +++ b/api/pipeline/validate.go @@ -0,0 +1,118 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package pipeline + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/pipeline" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/pipelines/{org}/{repo}/{pipeline}/validate pipelines ValidatePipeline +// +// Get, expand and validate a pipeline from the configured backend +// +// --- +// produces: +// - application/x-yaml +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: pipeline +// description: Commit SHA for pipeline to retrieve +// required: true +// type: string +// - in: query +// name: output +// description: Output string for specifying output format +// type: string +// default: yaml +// enum: +// - json +// - yaml +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved, expanded and validated the pipeline +// schema: +// type: string +// '400': +// description: Unable to validate the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to retrieve the pipeline configuration +// schema: +// "$ref": "#/definitions/Error" + +// ValidatePipeline represents the API handler to capture, +// expand and validate a pipeline configuration. +func ValidatePipeline(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + o := org.Retrieve(c) + p := pipeline.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "pipeline": p.GetCommit(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("validating pipeline %s", entry) + + // ensure we use the expected pipeline type when compiling + r.SetPipelineType(p.GetType()) + + // create the compiler object + compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + + // capture optional template query parameter + template, err := strconv.ParseBool(c.DefaultQuery("template", "true")) + if err != nil { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("unable to parse template query parameter for %s: %w", entry, err)) + + return + } + + // validate the pipeline + pipeline, _, err := compiler.CompileLite(p.GetData(), template, false, nil) + if err != nil { + retErr := fmt.Errorf("unable to validate pipeline %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + writeOutput(c, pipeline) +} diff --git a/api/webhook.go b/api/webhook.go index 882a23331..83f14ec37 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -174,7 +174,6 @@ func PostWebhook(c *gin.Context) { // send API call to capture parsed repo from webhook r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) - if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -340,21 +339,19 @@ func PostWebhook(c *gin.Context) { // variable to store changeset files var files []string - // check if the build event is not issue_comment - if !strings.EqualFold(b.GetEvent(), constants.EventComment) { - // check if the build event is not pull_request - if !strings.EqualFold(b.GetEvent(), constants.EventPull) { - // send API call to capture list of files changed for the commit - files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) - util.HandleError(c, http.StatusInternalServerError, retErr) + // check if the build event is not issue_comment or pull_request + if !strings.EqualFold(b.GetEvent(), constants.EventComment) && + !strings.EqualFold(b.GetEvent(), constants.EventPull) { + // send API call to capture list of files changed for the commit + files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusInternalServerError, retErr) - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) - return - } + return } } @@ -373,22 +370,36 @@ func PostWebhook(c *gin.Context) { } } - // send API call to capture the pipeline configuration file - config, err := scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("%s: failed to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) - util.HandleError(c, http.StatusNotFound, retErr) + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to control number of times to retry compiling pipeline + retryLimit = 3 + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("%s: failed to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusNotFound, retErr) - return - } + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) - // variable to store pipeline - var p *pipeline.Build - // number of times to retry - retryLimit := 3 + return + } + } else { + config = pipeline.GetData() + } // iterate through with a retryLimit for i := 0; i < retryLimit; i++ { @@ -421,7 +432,6 @@ func PostWebhook(c *gin.Context) { // update the build numbers based off repo counter inc := r.GetCounter() + 1 - r.SetCounter(inc) b.SetNumber(inc) @@ -432,8 +442,19 @@ func PostWebhook(c *gin.Context) { ) } + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) + } + + var compiled *library.Pipeline // parse and compile the pipeline configuration file - p, err = compiler.FromContext(c). + p, compiled, err = compiler.FromContext(c). Duplicate(). WithBuild(b). WithComment(webhook.Comment). @@ -457,6 +478,13 @@ func PostWebhook(c *gin.Context) { return } + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found skip := skipEmptyBuild(p) @@ -475,6 +503,41 @@ func PostWebhook(c *gin.Context) { return } + // check if the pipeline did not already exist in the database + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(b.GetCommit()) + pipeline.SetRef(b.GetRef()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(pipeline) + if err != nil { + retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusBadRequest, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + + // send API call to capture the created pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + // nolint: lll // ignore long line length due to error message + retErr := fmt.Errorf("%s: failed to get new pipeline %s/%s: %w", baseErr, r.GetFullName(), pipeline.GetCommit(), err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + } + + b.SetPipelineID(pipeline.GetID()) + // create the objects from the pipeline in the database err = planBuild(database.FromContext(c), p, b, r) if err != nil { diff --git a/compiler/context_test.go b/compiler/context_test.go index 97dd383d2..cc4fbee7a 100644 --- a/compiler/context_test.go +++ b/compiler/context_test.go @@ -22,7 +22,7 @@ func TestCompiler_FromContext(t *testing.T) { want Engine }{ { - // nolint: staticcheck // ignore using string with context value + // nolint: staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, _engine), want: _engine, }, @@ -31,7 +31,7 @@ func TestCompiler_FromContext(t *testing.T) { want: nil, }, { - // nolint: staticcheck // ignore using string with context value + // nolint: staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, "foo"), want: nil, }, @@ -92,7 +92,7 @@ func TestCompiler_WithContext(t *testing.T) { // setup types var _engine Engine - // nolint: staticcheck // ignore using string with context value + // nolint: staticcheck, revive // ignore using string with context value want := context.WithValue(context.Background(), key, _engine) // run test diff --git a/compiler/engine.go b/compiler/engine.go index fa1778fba..3fbc7d02c 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -20,12 +20,12 @@ type Engine interface { // Compile defines a function that produces an executable // representation of a pipeline from an object. This calls // Parse internally to convert the object to a yaml configuration. - Compile(interface{}) (*pipeline.Build, error) + Compile(interface{}) (*pipeline.Build, *library.Pipeline, error) // CompileLite defines a function that produces an light executable // representation of a pipeline from an object. This calls // Parse internally to convert the object to a yaml configuration. - CompileLite(interface{}, bool, bool, []string) (*yaml.Build, error) + CompileLite(interface{}, bool, bool, []string) (*yaml.Build, *library.Pipeline, error) // Duplicate defines a function that // creates a clone of the Engine. @@ -33,7 +33,7 @@ type Engine interface { // Parse defines a function that converts // an object to a yaml configuration. - Parse(interface{}, string, map[string]interface{}) (*yaml.Build, error) + Parse(interface{}, string, map[string]interface{}) (*yaml.Build, []byte, error) // ParseRaw defines a function that converts // an object to a string. diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 96ec2f0cf..9144ba718 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -41,16 +41,21 @@ type ModifyResponse struct { } // Compile produces an executable pipeline from a yaml configuration. -func (c *client) Compile(v interface{}) (*pipeline.Build, error) { - p, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) +func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, error) { + p, data, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) if err != nil { - return nil, err + return nil, nil, err } + // create the library pipeline object from the yaml configuration + _pipeline := p.ToPipelineLibrary() + _pipeline.SetData(data) + _pipeline.SetType(c.repo.GetPipelineType()) + // validate the yaml configuration err = c.Validate(p) if err != nil { - return nil, err + return nil, _pipeline, err } // create map of templates for easy lookup @@ -71,42 +76,47 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, error) { case p.Metadata.RenderInline: newPipeline, err := c.compileInline(p, nil) if err != nil { - return nil, err + return nil, _pipeline, err } // validate the yaml configuration err = c.Validate(newPipeline) if err != nil { - return nil, err + return nil, _pipeline, err } if len(newPipeline.Stages) > 0 { - return c.compileStages(newPipeline, map[string]*yaml.Template{}, r) + return c.compileStages(newPipeline, _pipeline, map[string]*yaml.Template{}, r) } - return c.compileSteps(newPipeline, map[string]*yaml.Template{}, r) + return c.compileSteps(newPipeline, _pipeline, map[string]*yaml.Template{}, r) case len(p.Stages) > 0: - return c.compileStages(p, templates, r) + return c.compileStages(p, _pipeline, templates, r) default: - return c.compileSteps(p, templates, r) + return c.compileSteps(p, _pipeline, templates, r) } } // CompileLite produces a partial of an executable pipeline from a yaml configuration. -func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, error) { - p, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) +func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, *library.Pipeline, error) { + p, data, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) if err != nil { - return nil, err + return nil, nil, err } + // create the library pipeline object from the yaml configuration + _pipeline := p.ToPipelineLibrary() + _pipeline.SetData(data) + _pipeline.SetType(c.repo.GetPipelineType()) + if p.Metadata.RenderInline { newPipeline, err := c.compileInline(p, localTemplates) if err != nil { - return nil, err + return nil, _pipeline, err } // validate the yaml configuration err = c.Validate(newPipeline) if err != nil { - return nil, err + return nil, _pipeline, err } p = newPipeline @@ -126,7 +136,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp // make sure the template was configured _, ok := templates[parts[0]] if !ok { - return nil, fmt.Errorf("template with name %s is not configured", parts[0]) + return nil, _pipeline, fmt.Errorf("template with name %s is not configured", parts[0]) } // override the source for the given template @@ -139,28 +149,28 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp // inject the templates into the steps p, err = c.ExpandStages(p, templates) if err != nil { - return nil, err + return nil, _pipeline, err } if substitute { // inject the substituted environment variables into the steps p.Stages, err = c.SubstituteStages(p.Stages) if err != nil { - return nil, err + return nil, _pipeline, err } } case len(p.Steps) > 0: // inject the templates into the steps p, err = c.ExpandSteps(p, templates) if err != nil { - return nil, err + return nil, _pipeline, err } if substitute { // inject the substituted environment variables into the steps p.Steps, err = c.SubstituteSteps(p.Steps) if err != nil { - return nil, err + return nil, _pipeline, err } } } @@ -169,10 +179,10 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp // validate the yaml configuration err = c.Validate(p) if err != nil { - return nil, err + return nil, _pipeline, err } - return p, nil + return p, _pipeline, nil } // compileInline parses and expands out inline pipelines. @@ -208,7 +218,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu format = constants.PipelineTypeGo } - parsed, err := c.Parse(bytes, format, template.Variables) + parsed, _, err := c.Parse(bytes, format, template.Variables) if err != nil { return nil, err } @@ -270,7 +280,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu // compileSteps executes the workflow for converting a YAML pipeline into an executable struct. // // nolint:dupl,lll // linter thinks the steps and stages workflows are identical -func (c *client) compileSteps(p *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, error) { +func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) { var err error // check if the pipeline disabled the clone @@ -278,34 +288,34 @@ func (c *client) compileSteps(p *yaml.Build, tmpls map[string]*yaml.Template, r // inject the clone step p, err = c.CloneStep(p) if err != nil { - return nil, err + return nil, _pipeline, err } } // inject the init step p, err = c.InitStep(p) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the templates into the steps p, err = c.ExpandSteps(p, tmpls) if err != nil { - return nil, err + return nil, _pipeline, err } if c.ModificationService.Endpoint != "" { // send config to external endpoint for modification p, err = c.modifyConfig(p, c.build, c.repo) if err != nil { - return nil, err + return nil, _pipeline, err } } // validate the yaml configuration err = c.Validate(p) if err != nil { - return nil, err + return nil, _pipeline, err } // Create some default global environment inject vars @@ -328,41 +338,46 @@ func (c *client) compileSteps(p *yaml.Build, tmpls map[string]*yaml.Template, r // inject the environment variables into the services p.Services, err = c.EnvironmentServices(p.Services, envGlobalServices) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the environment variables into the secrets p.Secrets, err = c.EnvironmentSecrets(p.Secrets, envGlobalSecrets) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the environment variables into the steps p.Steps, err = c.EnvironmentSteps(p.Steps, envGlobalSteps) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the substituted environment variables into the steps p.Steps, err = c.SubstituteSteps(p.Steps) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the scripts into the steps p.Steps, err = c.ScriptSteps(p.Steps) if err != nil { - return nil, err + return nil, _pipeline, err + } + + // create executable representation + build, err := c.TransformSteps(r, p) + if err != nil { + return nil, _pipeline, err } - // return executable representation - return c.TransformSteps(r, p) + return build, _pipeline, nil } // compileStages executes the workflow for converting a YAML pipeline into an executable struct. // // nolint:dupl,lll // linter thinks the steps and stages workflows are identical -func (c *client) compileStages(p *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, error) { +func (c *client) compileStages(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) { var err error // check if the pipeline disabled the clone @@ -370,34 +385,34 @@ func (c *client) compileStages(p *yaml.Build, tmpls map[string]*yaml.Template, r // inject the clone stage p, err = c.CloneStage(p) if err != nil { - return nil, err + return nil, _pipeline, err } } // inject the init stage p, err = c.InitStage(p) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the templates into the stages p, err = c.ExpandStages(p, tmpls) if err != nil { - return nil, err + return nil, _pipeline, err } if c.ModificationService.Endpoint != "" { // send config to external endpoint for modification p, err = c.modifyConfig(p, c.build, c.repo) if err != nil { - return nil, err + return nil, _pipeline, err } } // validate the yaml configuration err = c.Validate(p) if err != nil { - return nil, err + return nil, _pipeline, err } // Create some default global environment inject vars @@ -420,35 +435,40 @@ func (c *client) compileStages(p *yaml.Build, tmpls map[string]*yaml.Template, r // inject the environment variables into the services p.Services, err = c.EnvironmentServices(p.Services, envGlobalServices) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the environment variables into the secrets p.Secrets, err = c.EnvironmentSecrets(p.Secrets, envGlobalSecrets) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the environment variables into the stages p.Stages, err = c.EnvironmentStages(p.Stages, envGlobalSteps) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the substituted environment variables into the stages p.Stages, err = c.SubstituteStages(p.Stages) if err != nil { - return nil, err + return nil, _pipeline, err } // inject the scripts into the stages p.Stages, err = c.ScriptStages(p.Stages) if err != nil { - return nil, err + return nil, _pipeline, err + } + + // create executable representation + build, err := c.TransformStages(r, p) + if err != nil { + return nil, _pipeline, err } - // return executable representation - return c.TransformStages(r, p) + return build, _pipeline, nil } // errorHandler ensures the error contains the number of request attempts. diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 2f213fbff..252683309 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -254,7 +254,7 @@ func TestNative_Compile_StagesPipeline(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -335,7 +335,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { repo: &library.Repo{Name: &author}, build: &library.Build{Author: &name, Number: &number}, } - _, err := compiler.Compile(yaml) + _, _, err := compiler.Compile(yaml) if (err != nil) != tt.wantErr { t.Errorf("Compile() error = %v, wantErr %v", err, tt.wantErr) return @@ -403,7 +403,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { repo: tt.args.repo, build: tt.args.libraryBuild, } - _, err := compiler.Compile(yaml) + _, _, err := compiler.Compile(yaml) if (err != nil) != tt.wantErr { t.Errorf("Compile() error = %v, wantErr %v", err, tt.wantErr) return @@ -584,7 +584,7 @@ func TestNative_Compile_StepsPipeline(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -835,7 +835,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -1072,7 +1072,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -1148,7 +1148,7 @@ func TestNative_Compile_InvalidType(t *testing.T) { compiler.WithMetadata(m) - _, err = compiler.Compile(invalidYaml) + _, _, err = compiler.Compile(invalidYaml) if err == nil { t.Error("Compile should have returned an err") } @@ -1331,7 +1331,7 @@ func TestNative_Compile_Clone(t *testing.T) { compiler.WithMetadata(m) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -1535,7 +1535,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { compiler.WithMetadata(m) compiler.WithRepo(&library.Repo{PipelineType: &tt.args.pipelineType}) - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err != nil { t.Errorf("Compile returned err: %v", err) } @@ -1569,7 +1569,7 @@ func TestNative_Compile_NoStepsorStages(t *testing.T) { compiler.repo = &library.Repo{Name: &author} compiler.build = &library.Build{Author: &name, Number: &number} - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err == nil { t.Errorf("Compile should have returned err") } @@ -1601,7 +1601,7 @@ func TestNative_Compile_StepsandStages(t *testing.T) { compiler.repo = &library.Repo{Name: &author} compiler.build = &library.Build{Author: &name, Number: &number} - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if err == nil { t.Errorf("Compile should have returned err") } @@ -2648,7 +2648,7 @@ func Test_Compile_Inline(t *testing.T) { compiler.WithRepo(&library.Repo{PipelineType: &tt.args.pipelineType}) } - got, err := compiler.Compile(yaml) + got, _, err := compiler.Compile(yaml) if (err != nil) != tt.wantErr { t.Errorf("Compile() error = %v, wantErr %v", err, tt.wantErr) return @@ -2977,7 +2977,7 @@ func Test_CompileLite(t *testing.T) { t.Errorf("Reading yaml file return err: %v", err) } - got, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute, nil) + got, _, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute, nil) if (err != nil) != tt.wantErr { t.Errorf("CompileLite() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/native/parse.go b/compiler/native/parse.go index 8bca88c41..8ae8ac660 100644 --- a/compiler/native/parse.go +++ b/compiler/native/parse.go @@ -43,31 +43,40 @@ func (c *client) ParseRaw(v interface{}) (string, error) { } // Parse converts an object to a yaml configuration. -func (c *client) Parse(v interface{}, pipelineType string, variables map[string]interface{}) (*types.Build, error) { - var p *types.Build +func (c *client) Parse(v interface{}, pipelineType string, variables map[string]interface{}) (*types.Build, []byte, error) { + var ( + p *types.Build + raw []byte + ) switch pipelineType { case constants.PipelineTypeGo, "golang": // expand the base configuration parsedRaw, err := c.ParseRaw(v) if err != nil { - return nil, err + return nil, nil, err } + // capture the raw pipeline configuration + raw = []byte(parsedRaw) + p, err = native.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) if err != nil { - return nil, err + return nil, raw, err } case constants.PipelineTypeStarlark: // expand the base configuration parsedRaw, err := c.ParseRaw(v) if err != nil { - return nil, err + return nil, nil, err } + // capture the raw pipeline configuration + raw = []byte(parsedRaw) + p, err = starlark.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) if err != nil { - return nil, err + return nil, raw, err } case constants.PipelineTypeYAML, "": switch v := v.(type) { @@ -88,30 +97,30 @@ func (c *client) Parse(v interface{}, pipelineType string, variables map[string] // parse string as yaml configuration return ParseString(v) default: - return nil, fmt.Errorf("unable to parse yaml: unrecognized type %T", v) + return nil, nil, fmt.Errorf("unable to parse yaml: unrecognized type %T", v) } default: - return nil, fmt.Errorf("unable to parse config: unrecognized pipeline_type of %s", c.repo.GetPipelineType()) + return nil, nil, fmt.Errorf("unable to parse config: unrecognized pipeline_type of %s", c.repo.GetPipelineType()) } - return p, nil + return p, raw, nil } // ParseBytes converts a byte slice to a yaml configuration. -func ParseBytes(b []byte) (*types.Build, error) { +func ParseBytes(data []byte) (*types.Build, []byte, error) { config := new(types.Build) // unmarshal the bytes into the yaml configuration - err := yaml.Unmarshal(b, config) + err := yaml.Unmarshal(data, config) if err != nil { - return nil, fmt.Errorf("unable to unmarshal yaml: %w", err) + return nil, data, fmt.Errorf("unable to unmarshal yaml: %w", err) } - return config, nil + return config, data, nil } // ParseFile converts an os.File into a yaml configuration. -func ParseFile(f *os.File) (*types.Build, error) { +func ParseFile(f *os.File) (*types.Build, []byte, error) { return ParseReader(f) } @@ -121,11 +130,11 @@ func ParseFileRaw(f *os.File) (string, error) { } // ParsePath converts a file path into a yaml configuration. -func ParsePath(p string) (*types.Build, error) { +func ParsePath(p string) (*types.Build, []byte, error) { // open the file for reading f, err := os.Open(p) if err != nil { - return nil, fmt.Errorf("unable to open yaml file %s: %w", p, err) + return nil, nil, fmt.Errorf("unable to open yaml file %s: %w", p, err) } defer f.Close() @@ -147,14 +156,14 @@ func ParsePathRaw(p string) (string, error) { } // ParseReader converts an io.Reader into a yaml configuration. -func ParseReader(r io.Reader) (*types.Build, error) { +func ParseReader(r io.Reader) (*types.Build, []byte, error) { // read all the bytes from the reader - b, err := ioutil.ReadAll(r) + data, err := ioutil.ReadAll(r) if err != nil { - return nil, fmt.Errorf("unable to read bytes for yaml: %w", err) + return nil, nil, fmt.Errorf("unable to read bytes for yaml: %w", err) } - return ParseBytes(b) + return ParseBytes(data) } // ParseReaderRaw converts an io.Reader into a yaml configuration. @@ -169,6 +178,6 @@ func ParseReaderRaw(r io.Reader) (string, error) { } // ParseString converts a string into a yaml configuration. -func ParseString(s string) (*types.Build, error) { +func ParseString(s string) (*types.Build, []byte, error) { return ParseBytes([]byte(s)) } diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index bf9b9a3d3..1c5016a50 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -41,7 +41,7 @@ func TestNative_Parse_Metadata_Bytes(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -71,7 +71,7 @@ func TestNative_Parse_Metadata_File(t *testing.T) { defer f.Close() - got, err := client.Parse(f, "", map[string]interface{}{}) + got, _, err := client.Parse(f, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -86,7 +86,7 @@ func TestNative_Parse_Metadata_Invalid(t *testing.T) { client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) // run test - got, err := client.Parse(nil, "", map[string]interface{}{}) + got, _, err := client.Parse(nil, "", map[string]interface{}{}) if err == nil { t.Error("Parse should have returned err") @@ -110,7 +110,7 @@ func TestNative_Parse_Metadata_Path(t *testing.T) { } // run test - got, err := client.Parse("testdata/metadata.yml", "", map[string]interface{}{}) + got, _, err := client.Parse("testdata/metadata.yml", "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -138,7 +138,7 @@ func TestNative_Parse_Metadata_Reader(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(bytes.NewReader(b), "", map[string]interface{}{}) + got, _, err := client.Parse(bytes.NewReader(b), "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -166,7 +166,7 @@ func TestNative_Parse_Metadata_String(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(string(b), "", map[string]interface{}{}) + got, _, err := client.Parse(string(b), "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -213,7 +213,7 @@ func TestNative_Parse_Parameters(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -339,7 +339,7 @@ func TestNative_Parse_StagesPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -436,7 +436,7 @@ func TestNative_Parse_StepsPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -499,7 +499,7 @@ func TestNative_Parse_Secrets(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -575,7 +575,7 @@ func TestNative_Parse_Stages(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -633,7 +633,7 @@ func TestNative_Parse_Steps(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", map[string]interface{}{}) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -661,7 +661,7 @@ func TestNative_ParseBytes_Metadata(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := ParseBytes(b) + got, _, err := ParseBytes(b) if err != nil { t.Errorf("ParseBytes returned err: %v", err) @@ -679,7 +679,7 @@ func TestNative_ParseBytes_Invalid(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := ParseBytes(b) + got, _, err := ParseBytes(b) if err == nil { t.Error("ParseBytes should have returned err") @@ -709,7 +709,7 @@ func TestNative_ParseFile_Metadata(t *testing.T) { defer f.Close() - got, err := ParseFile(f) + got, _, err := ParseFile(f) if err != nil { t.Errorf("ParseFile returned err: %v", err) @@ -729,7 +729,7 @@ func TestNative_ParseFile_Invalid(t *testing.T) { f.Close() - got, err := ParseFile(f) + got, _, err := ParseFile(f) if err == nil { t.Error("ParseFile should have returned err") @@ -752,7 +752,7 @@ func TestNative_ParsePath_Metadata(t *testing.T) { } // run test - got, err := ParsePath("testdata/metadata.yml") + got, _, err := ParsePath("testdata/metadata.yml") if err != nil { t.Errorf("ParsePath returned err: %v", err) @@ -765,7 +765,7 @@ func TestNative_ParsePath_Metadata(t *testing.T) { func TestNative_ParsePath_Invalid(t *testing.T) { // run test - got, err := ParsePath("testdata/foobar.yml") + got, _, err := ParsePath("testdata/foobar.yml") if err == nil { t.Error("ParsePath should have returned err") @@ -793,7 +793,7 @@ func TestNative_ParseReader_Metadata(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := ParseReader(bytes.NewReader(b)) + got, _, err := ParseReader(bytes.NewReader(b)) if err != nil { t.Errorf("ParseReader returned err: %v", err) @@ -806,7 +806,7 @@ func TestNative_ParseReader_Metadata(t *testing.T) { func TestNative_ParseReader_Invalid(t *testing.T) { // run test - got, err := ParseReader(FailReader{}) + got, _, err := ParseReader(FailReader{}) if err == nil { t.Error("ParseFile should have returned err") @@ -834,7 +834,7 @@ func TestNative_ParseString_Metadata(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, err := ParseString(string(b)) + got, _, err := ParseString(string(b)) if err != nil { t.Errorf("ParseString returned err: %v", err) @@ -907,7 +907,7 @@ func Test_client_Parse(t *testing.T) { } } - got, err := c.Parse(content, tt.args.pipelineType, map[string]interface{}{}) + got, _, err := c.Parse(content, tt.args.pipelineType, map[string]interface{}{}) if (err != nil) != tt.wantErr { t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/go.sum b/go.sum index 11085422c..b3088bb04 100644 --- a/go.sum +++ b/go.sum @@ -1052,4 +1052,4 @@ sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNza sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= \ No newline at end of file diff --git a/mock/server/pipeline.go b/mock/server/pipeline.go index 6d886e0e7..021960ea3 100644 --- a/mock/server/pipeline.go +++ b/mock/server/pipeline.go @@ -5,10 +5,13 @@ package server import ( + "encoding/json" "fmt" "net/http" "strings" + "github.com/go-vela/types/library" + "github.com/gin-gonic/gin" "github.com/go-vela/types" "github.com/go-vela/types/yaml" @@ -102,37 +105,62 @@ templates: source: github.com/go-vela/vela-tutorials/templates/sample.yml type: github ` - - // PipelineResp represents a YAML return for a single pipeline. - PipelineResp = `--- -version: "1" - -secrets: - - name: docker_username - key: go-vela/docker/username - engine: native - type: org - - - name: docker_password - key: go-vela/docker/password - engine: native - type: org - -steps: - - name: go - template: - name: sample - - - name: non-template-echo - image: golang:latest - commands: - - echo hello - -templates: - - name: sample - source: github.com/go-vela/vela-tutorials/templates/sample.yml - type: github -` + // PipelineResp represents a JSON return for a single pipeline. + PipelineResp = `{ + "id": 1, + "repo_id": 1, + "commit": "48afb5bdc41ad69bf22588491333f7cf71135163", + "flavor": "", + "platform": "", + "ref": "refs/heads/master", + "type": "yaml", + "version": "1", + "external_secrets": false, + "internal_secrets": false, + "services": false, + "stages": false, + "steps": true, + "templates": false, + "data": "LS0tCnZlcnNpb246ICIxIgoKc3RlcHM6CiAgLSBuYW1lOiBlY2hvCiAgICBpbWFnZTogYWxwaW5lOmxhdGVzdAogICAgY29tbWFuZHM6IFtlY2hvIGZvb10=" +}` + + // PipelinesResp represents a JSON return for one to many hooks. + PipelinesResp = `[ + { + "id": 2 + "repo_id": 1, + "commit": "a49aaf4afae6431a79239c95247a2b169fd9f067", + "flavor": "", + "platform": "", + "ref": "refs/heads/master", + "type": "yaml", + "version": "1", + "external_secrets": false, + "internal_secrets": false, + "services": false, + "stages": false, + "steps": true, + "templates": false, + "data": "LS0tCnZlcnNpb246ICIxIgoKc3RlcHM6CiAgLSBuYW1lOiBlY2hvCiAgICBpbWFnZTogYWxwaW5lOmxhdGVzdAogICAgY29tbWFuZHM6IFtlY2hvIGZvb10=" + }, + { + "id": 1, + "repo_id": 1, + "commit": "48afb5bdc41ad69bf22588491333f7cf71135163", + "flavor": "", + "platform": "", + "ref": "refs/heads/master", + "type": "yaml", + "version": "1", + "external_secrets": false, + "internal_secrets": false, + "services": false, + "stages": false, + "steps": true, + "templates": false, + "data": "LS0tCnZlcnNpb246ICIxIgoKc3RlcHM6CiAgLSBuYW1lOiBlY2hvCiAgICBpbWFnZTogYWxwaW5lOmxhdGVzdAogICAgY29tbWFuZHM6IFtlY2hvIGZvb10=" + } +]` // TemplateResp represents a YAML return for templates in a pipeline. TemplateResp = `--- @@ -143,14 +171,24 @@ sample: ` ) -// getPipeline has a param :repo returns mock YAML for a http GET. +// getPipelines returns mock JSON for a http GET. +func getPipelines(c *gin.Context) { + data := []byte(PipelinesResp) + + var body []library.Pipeline + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// getPipeline has a param :pipeline returns mock YAML for a http GET. // -// Pass "not-found" to :repo to test receiving a http 404 response. +// Pass "0" to :pipeline to test receiving a http 404 response. func getPipeline(c *gin.Context) { - r := c.Param("repo") + p := c.Param("pipeline") - if strings.Contains(r, "not-found") { - msg := fmt.Sprintf("Repo %s does not exist", r) + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) @@ -159,20 +197,71 @@ func getPipeline(c *gin.Context) { data := []byte(PipelineResp) - var body yaml.Build - _ = yml.Unmarshal(data, &body) + var body library.Pipeline + _ = json.Unmarshal(data, &body) - c.YAML(http.StatusOK, body) + c.JSON(http.StatusOK, body) +} + +// addPipeline returns mock JSON for a http POST. +func addPipeline(c *gin.Context) { + data := []byte(PipelineResp) + + var body library.Pipeline + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusCreated, body) +} + +// updatePipeline has a param :pipeline returns mock JSON for a http PUT. +// +// Pass "0" to :pipeline to test receiving a http 404 response. +func updatePipeline(c *gin.Context) { + if !strings.Contains(c.FullPath(), "admin") { + p := c.Param("pipeline") + + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + } + + data := []byte(PipelineResp) + + var body library.Pipeline + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// removePipeline has a param :pipeline returns mock JSON for a http DELETE. +// +// Pass "0" to :pipeline to test receiving a http 404 response. +func removePipeline(c *gin.Context) { + p := c.Param("pipeline") + + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("Pipeline %s removed", p)) } -// compilePipeline has a param :repo returns mock YAML for a http GET. +// compilePipeline has a param :pipeline returns mock YAML for a http GET. // -// Pass "not-found" to :repo to test receiving a http 404 response. +// Pass "0" to :pipeline to test receiving a http 404 response. func compilePipeline(c *gin.Context) { - r := c.Param("repo") + p := c.Param("pipeline") - if strings.Contains(r, "not-found") { - msg := fmt.Sprintf("Repo %s does not exist", r) + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) @@ -187,14 +276,14 @@ func compilePipeline(c *gin.Context) { c.YAML(http.StatusOK, body) } -// expandPipeline has a param :repo returns mock YAML for a http GET. +// expandPipeline has a param :pipeline returns mock YAML for a http GET. // -// Pass "not-found" to :repo to test receiving a http 404 response. +// Pass "0" to :pipeline to test receiving a http 404 response. func expandPipeline(c *gin.Context) { - r := c.Param("repo") + p := c.Param("pipeline") - if strings.Contains(r, "not-found") { - msg := fmt.Sprintf("Repo %s does not exist", r) + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) @@ -209,14 +298,14 @@ func expandPipeline(c *gin.Context) { c.YAML(http.StatusOK, body) } -// getTemplates has a param :repo returns mock YAML for a http GET. +// getTemplates has a param :pipeline returns mock YAML for a http GET. // -// Pass "not-found" to :repo to test receiving a http 404 response. +// Pass "0" to :pipeline to test receiving a http 404 response. func getTemplates(c *gin.Context) { - r := c.Param("repo") + p := c.Param("pipeline") - if strings.Contains(r, "not-found") { - msg := fmt.Sprintf("Repo %s does not exist", r) + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) @@ -231,14 +320,14 @@ func getTemplates(c *gin.Context) { c.YAML(http.StatusOK, body) } -// validatePipeline has a param :repo returns mock YAML for a http GET. +// validatePipeline has a param :pipeline returns mock YAML for a http GET. // -// Pass "not-found" to :repo to test receiving a http 404 response. +// Pass "0" to :pipeline to test receiving a http 404 response. func validatePipeline(c *gin.Context) { - r := c.Param("repo") + p := c.Param("pipeline") - if strings.Contains(r, "not-found") { - msg := fmt.Sprintf("Repo %s does not exist", r) + if strings.EqualFold(p, "0") { + msg := fmt.Sprintf("Pipeline %s does not exist", p) c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) diff --git a/mock/server/server.go b/mock/server/server.go index e36b1076e..14df28d7f 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -70,11 +70,15 @@ func FakeHandler() http.Handler { e.DELETE("/api/v1/repos/:org/:repo/builds/:build/steps/:step/logs", removeStepLog) // mock endpoints for pipeline calls - e.GET("/api/v1/pipelines/:org/:repo", getPipeline) - e.POST("/api/v1/pipelines/:org/:repo/compile", compilePipeline) - e.POST("/api/v1/pipelines/:org/:repo/expand", expandPipeline) - e.GET("/api/v1/pipelines/:org/:repo/templates", getTemplates) - e.POST("/api/v1/pipelines/:org/:repo/validate", validatePipeline) + e.POST("/api/v1/pipelines/:org/:repo", addPipeline) + e.GET("/api/v1/pipelines/:org/:repo", getPipelines) + e.GET("/api/v1/pipelines/:org/:repo/:pipeline", getPipeline) + e.PUT("/api/v1/pipelines/:org/:repo/:pipeline", updatePipeline) + e.DELETE("/api/v1/pipelines/:org/:repo/:pipeline", removePipeline) + e.POST("/api/v1/pipelines/:org/:repo/:pipeline/compile", compilePipeline) + e.POST("/api/v1/pipelines/:org/:repo/:pipeline/expand", expandPipeline) + e.GET("/api/v1/pipelines/:org/:repo/:pipeline/templates", getTemplates) + e.POST("/api/v1/pipelines/:org/:repo/:pipeline/validate", validatePipeline) // mock endpoints for repo calls e.GET("/api/v1/repos/:org/:repo", getRepo) diff --git a/router/pipeline.go b/router/pipeline.go index 9f2668b0e..dfcf5aa2c 100644 --- a/router/pipeline.go +++ b/router/pipeline.go @@ -6,27 +6,41 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/pipeline" "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/perm" + pmiddleware "github.com/go-vela/server/router/middleware/pipeline" "github.com/go-vela/server/router/middleware/repo" ) // PipelineHandlers is a function that extends the provided base router group // with the API handlers for pipeline functionality. // -// GET /api/v1/pipelines/:org/:repo -// GET /api/v1/pipelines/:org/:repo/templates -// POST /api/v1/pipelines/:org/:repo/expand -// POST /api/v1/pipelines/:org/:repo/compile -// POST /api/v1/pipelines/:org/:repo/validate . +// POST /api/v1/pipelines/:org/:repo +// GET /api/v1/pipelines/:org/:repo +// GET /api/v1/pipelines/:org/:repo/:pipeline +// PUT /api/v1/pipelines/:org/:repo/:pipeline +// DELETE /api/v1/pipelines/:org/:repo/:pipeline +// GET /api/v1/pipelines/:org/:repo/:pipeline/templates +// POST /api/v1/pipelines/:org/:repo/:pipeline/expand +// POST /api/v1/pipelines/:org/:repo/:pipeline/compile +// POST /api/v1/pipelines/:org/:repo/:pipeline/validate . func PipelineHandlers(base *gin.RouterGroup) { // Pipelines endpoints - pipelines := base.Group("pipelines/:org/:repo", org.Establish(), repo.Establish()) + _pipelines := base.Group("pipelines/:org/:repo", org.Establish(), repo.Establish()) { - pipelines.GET("", api.GetPipeline) - pipelines.GET("/templates", api.GetTemplates) - pipelines.POST("/expand", api.ExpandPipeline) - pipelines.POST("/validate", api.ValidatePipeline) - pipelines.POST("/compile", api.CompilePipeline) + _pipelines.POST("", perm.MustAdmin(), pipeline.CreatePipeline) + _pipelines.GET("", perm.MustRead(), pipeline.ListPipelines) + + _pipeline := _pipelines.Group("/:pipeline", pmiddleware.Establish()) + { + _pipeline.GET("", perm.MustRead(), pipeline.GetPipeline) + _pipeline.PUT("", perm.MustWrite(), pipeline.UpdatePipeline) + _pipeline.DELETE("", perm.MustPlatformAdmin(), pipeline.DeletePipeline) + _pipeline.GET("/templates", perm.MustRead(), pipeline.GetTemplates) + _pipeline.POST("/compile", perm.MustWrite(), pipeline.CompilePipeline) + _pipeline.POST("/expand", perm.MustWrite(), pipeline.ExpandPipeline) + _pipeline.POST("/validate", perm.MustWrite(), pipeline.ValidatePipeline) + } // end of pipeline endpoints } // end of pipelines endpoints } From e8907bf11da4b4c52334d1ecd3bc2fbba85a4639 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Apr 2022 01:01:30 +0000 Subject: [PATCH 046/298] chore(deps): update github/codeql-action action to v2 (#628) Co-authored-by: Renovate Bot --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e9c2f66e5..fc1738a88 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From 35867ec326ea5343702b0794da7a83df5fc1bb03 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Apr 2022 09:04:45 -0500 Subject: [PATCH 047/298] fix(deps): update deps (patch) (#603) --- compiler/native/compile.go | 11 ++--- database/postgres/repo_count_test.go | 2 +- database/postgres/repo_list_test.go | 2 +- database/sqlite/secret_list_test.go | 20 ++++++++ go.mod | 28 +++++------ go.sum | 73 +++++++++++++++------------- secret/native/count_test.go | 2 + secret/native/delete_test.go | 2 + 8 files changed, 84 insertions(+), 56 deletions(-) diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 9144ba718..08957cc7f 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -513,17 +513,16 @@ func (c *client) modifyConfig(build *yaml.Build, libraryBuild *library.Build, re Backoff: retryablehttp.DefaultBackoff, } + // ensure the overall request(s) do not take over the defined timeout + ctx, cancel := context.WithTimeout(context.Background(), c.ModificationService.Timeout) + defer cancel() + // create POST request - req, err := retryablehttp.NewRequest("POST", c.ModificationService.Endpoint, bytes.NewBuffer(b)) + req, err := retryablehttp.NewRequestWithContext(ctx, "POST", c.ModificationService.Endpoint, bytes.NewBuffer(b)) if err != nil { return nil, err } - // ensure the overall request(s) do not take over the defined timeout - ctx, cancel := context.WithTimeout(req.Request.Context(), c.ModificationService.Timeout) - defer cancel() - req.WithContext(ctx) - // add content-type and auth headers req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.ModificationService.Secret)) diff --git a/database/postgres/repo_count_test.go b/database/postgres/repo_count_test.go index 4213f36e1..324915eb5 100644 --- a/database/postgres/repo_count_test.go +++ b/database/postgres/repo_count_test.go @@ -264,7 +264,7 @@ func TestPostgres_Client_GetOrgRepoCount_NonAdmin(t *testing.T) { _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"repos\" WHERE (org = $1) AND \"visibility\" = $2").WillReturnRows(_rows) + _mock.ExpectQuery("SELECT count(*) FROM \"repos\" WHERE org = $1 AND \"visibility\" = $2").WillReturnRows(_rows) // setup tests tests := []struct { diff --git a/database/postgres/repo_list_test.go b/database/postgres/repo_list_test.go index feb20bcde..65871d82f 100644 --- a/database/postgres/repo_list_test.go +++ b/database/postgres/repo_list_test.go @@ -286,7 +286,7 @@ func TestPostgres_Client_GetOrgRepoList_NonAdmin(t *testing.T) { ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") // ensure the mock expects the query - _mock.ExpectQuery("SELECT * FROM \"repos\" WHERE (org = $1) AND \"visibility\" = $2 ORDER BY name LIMIT 10").WillReturnRows(_rows) + _mock.ExpectQuery("SELECT * FROM \"repos\" WHERE org = $1 AND \"visibility\" = $2 ORDER BY name LIMIT 10").WillReturnRows(_rows) // setup tests tests := []struct { diff --git a/database/sqlite/secret_list_test.go b/database/sqlite/secret_list_test.go index 027f01a94..a4bb354ee 100644 --- a/database/sqlite/secret_list_test.go +++ b/database/sqlite/secret_list_test.go @@ -37,6 +37,8 @@ func TestSqlite_Client_GetSecretList(t *testing.T) { _secretOne.SetName("baz") _secretOne.SetValue("foob") _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetUpdatedAt(1) _secretTwo := testSecret() _secretTwo.SetID(2) @@ -45,6 +47,8 @@ func TestSqlite_Client_GetSecretList(t *testing.T) { _secretTwo.SetName("foob") _secretTwo.SetValue("baz") _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetUpdatedAt(1) // setup the test database client _database, err := NewTest() @@ -107,6 +111,8 @@ func TestSqlite_Client_GetTypeSecretList_Org(t *testing.T) { _secretOne.SetName("baz") _secretOne.SetValue("bar") _secretOne.SetType("org") + _secretOne.SetCreatedAt(1) + _secretOne.SetUpdatedAt(1) _secretTwo := testSecret() _secretTwo.SetID(2) @@ -115,6 +121,8 @@ func TestSqlite_Client_GetTypeSecretList_Org(t *testing.T) { _secretTwo.SetName("bar") _secretTwo.SetValue("baz") _secretTwo.SetType("org") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetUpdatedAt(1) // setup the test database client _database, err := NewTest() @@ -177,6 +185,8 @@ func TestSqlite_Client_GetTypeSecretList_Repo(t *testing.T) { _secretOne.SetName("baz") _secretOne.SetValue("foob") _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetUpdatedAt(1) _secretTwo := testSecret() _secretTwo.SetID(2) @@ -185,6 +195,8 @@ func TestSqlite_Client_GetTypeSecretList_Repo(t *testing.T) { _secretTwo.SetName("foob") _secretTwo.SetValue("baz") _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetUpdatedAt(1) // setup the test database client _database, err := NewTest() @@ -247,6 +259,8 @@ func TestSqlite_Client_GetTypeSecretList_Shared(t *testing.T) { _secretOne.SetName("baz") _secretOne.SetValue("foob") _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetUpdatedAt(1) _secretTwo := testSecret() _secretTwo.SetID(2) @@ -255,6 +269,8 @@ func TestSqlite_Client_GetTypeSecretList_Shared(t *testing.T) { _secretTwo.SetName("foob") _secretTwo.SetValue("baz") _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetUpdatedAt(1) // setup the test database client _database, err := NewTest() @@ -317,6 +333,8 @@ func TestSqlite_Client_GetTypeSecretList_Shared_wildcard(t *testing.T) { _secretOne.SetName("baz") _secretOne.SetValue("foob") _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetUpdatedAt(1) _secretTwo := testSecret() _secretTwo.SetID(2) @@ -325,6 +343,8 @@ func TestSqlite_Client_GetTypeSecretList_Shared_wildcard(t *testing.T) { _secretTwo.SetName("foob") _secretTwo.SetValue("baz") _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetUpdatedAt(1) // setup the test database client _database, err := NewTest() diff --git a/go.mod b/go.mod index 44ba2f71d..690b47429 100644 --- a/go.mod +++ b/go.mod @@ -13,31 +13,31 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 - github.com/go-redis/redis/v8 v8.11.4 + github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281 - github.com/golang-jwt/jwt/v4 v4.4.0 - github.com/google/go-cmp v0.5.7 + github.com/golang-jwt/jwt/v4 v4.4.1 + github.com/google/go-cmp v0.5.8 github.com/google/go-github/v42 v42.0.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.1 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-retryablehttp v0.7.0 + github.com/hashicorp/go-retryablehttp v0.7.1 github.com/hashicorp/vault/api v1.5.0 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 - github.com/spf13/afero v1.8.1 + github.com/spf13/afero v1.8.2 github.com/urfave/cli/v2 v2.4.0 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.1 - gorm.io/driver/sqlite v1.3.1 - gorm.io/gorm v1.23.1 - k8s.io/apimachinery v0.23.4 + gorm.io/driver/postgres v1.3.5 + gorm.io/driver/sqlite v1.3.2 + gorm.io/gorm v1.23.5 + k8s.io/apimachinery v0.23.6 ) require ( @@ -85,15 +85,15 @@ require ( github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.10.1 // indirect + github.com/jackc/pgconn v1.12.0 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.2.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.9.1 // indirect - github.com/jackc/pgx/v4 v4.14.1 // indirect + github.com/jackc/pgtype v1.11.0 // indirect + github.com/jackc/pgx/v4 v4.16.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.4 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kr/pretty v0.3.0 // indirect diff --git a/go.sum b/go.sum index b3088bb04..c81d82212 100644 --- a/go.sum +++ b/go.sum @@ -174,8 +174,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= -github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= @@ -188,8 +188,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU= -github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -236,8 +236,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec= github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg= @@ -260,6 +260,7 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -299,8 +300,8 @@ github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= @@ -350,8 +351,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= -github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.0 h1:/RvQ24k3TnNdfBSW0ou9EOi5jx2cX7zfE8n2nLKuiP0= +github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -368,33 +369,34 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= -github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= +github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= -github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= +github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU= -github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= +github.com/jackc/pgx/v4 v4.16.0 h1:4k1tROTJctHotannFYzu77dY3bgtMRymQP7tXQjqpPk= +github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -454,7 +456,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -500,13 +502,16 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= @@ -567,8 +572,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.8.1 h1:izYHOT71f9iZ7iq37Uqjael60/vYC6vMtzedudZ0zEk= -github.com/spf13/afero v1.8.1/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -888,7 +893,6 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1022,12 +1026,13 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.1 h1:Pyv+gg1Gq1IgsLYytj/S2k7ebII3CzEdpqQkPOdH24g= -gorm.io/driver/postgres v1.3.1/go.mod h1:WwvWOuR9unCLpGWCL6Y3JOeBWvbKi6JLhayiVclSZZU= -gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk= -gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg= -gorm.io/gorm v1.23.1 h1:aj5IlhDzEPsoIyOPtTRVI+SyaN1u6k613sbt4pwbxG0= -gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/driver/postgres v1.3.5 h1:oVLmefGqBTlgeEVG6LKnH6krOlo4TZ3Q/jIK21KUMlw= +gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= +gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg= +gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= +gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= +gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1035,8 +1040,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= -k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.23.6 h1:RH1UweWJkWNTlFx0D8uxOpaU1tjIOvVVWV/bu5b3/NQ= +k8s.io/apimachinery v0.23.6/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= @@ -1052,4 +1057,4 @@ sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNza sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= \ No newline at end of file +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/secret/native/count_test.go b/secret/native/count_test.go index d9e7e94ab..faed10a88 100644 --- a/secret/native/count_test.go +++ b/secret/native/count_test.go @@ -22,6 +22,8 @@ func TestNative_Count(t *testing.T) { sec.SetType("repo") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) + sec.SetCreatedAt(1) + sec.SetUpdatedAt(1) want := 1 diff --git a/secret/native/delete_test.go b/secret/native/delete_test.go index 556046ea4..743288f62 100644 --- a/secret/native/delete_test.go +++ b/secret/native/delete_test.go @@ -24,6 +24,8 @@ func TestNative_Delete(t *testing.T) { sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) sec.SetAllowCommand(false) + sec.SetCreatedAt(1) + sec.SetUpdatedAt(1) // setup database db, _ := sqlite.NewTest() From bc71c9031c30ab956a989db4ef0ac943d2b76e26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Apr 2022 14:25:11 -0500 Subject: [PATCH 048/298] fix(deps): update module github.com/urfave/cli/v2 to v2.5.1 (#629) --- go.mod | 2 +- go.sum | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 690b47429..abb707fe9 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.2 - github.com/urfave/cli/v2 v2.4.0 + github.com/urfave/cli/v2 v2.5.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index c81d82212..df963167a 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -595,8 +596,8 @@ github.com/ugorji/go v1.1.11/go.mod h1:kbRrdMyHY64ADdazOwkrQP9btxt35Z26OJueD3Tq0 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.11 h1:GaQDxjNe1J3vCZvlVaDjUIHIbFuUByFXY7rMqnhB5ck= github.com/ugorji/go/codec v1.1.11/go.mod h1:svMFxxx5FVQJPnJ9vbpAgscNufuiXDyldvzApI86qQo= -github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I= -github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg= +github.com/urfave/cli/v2 v2.5.1 h1:YKwdkyA0xTBzOaP2G0DVxBnCheHGP+Y9VbKAs4K1Ess= +github.com/urfave/cli/v2 v2.5.1/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 8d3befc958fa6eb9baac996a50ddb9a99defeb50 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Apr 2022 08:18:39 -0500 Subject: [PATCH 049/298] chore(deps): update dependency redis to v7 (#631) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2132da2a3..7f9710d94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -112,7 +112,7 @@ services: # https://redis.io/ redis: container_name: redis - image: redis:6-alpine + image: redis:7-alpine networks: - vela ports: From ee9e80a9c13047cd8256f7eb9762882f21cf23ec Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 2 May 2022 10:14:08 -0600 Subject: [PATCH 050/298] feat(compiler/database/scm)!: add event action build field and use for rulesets (#630) * add edit to scm/webhook * populate event action field and use for rules if provided * get rid of event action setter for tag event - mistake * handle all types of edited actions Co-authored-by: Easton Crupper --- compiler/native/compile.go | 10 +++++++- compiler/native/environment_test.go | 25 ++++++++++++-------- database/postgres/build_list_test.go | 34 +++++++++++++-------------- database/postgres/build_test.go | 21 +++++++++-------- database/postgres/ddl/build.go | 1 + database/sqlite/build_test.go | 1 + database/sqlite/ddl/build.go | 1 + go.mod | 2 +- go.sum | 4 ++-- router/middleware/build/build_test.go | 1 + scm/github/webhook.go | 7 ++++-- scm/github/webhook_test.go | 3 +++ 12 files changed, 67 insertions(+), 43 deletions(-) diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 08957cc7f..9a2b0eb51 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -61,11 +61,19 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err // create map of templates for easy lookup templates := mapFromTemplates(p.Templates) + event := c.build.GetEvent() + action := c.build.GetEventAction() + + // if the build has an event action, concatenate event and event action for matching + if !strings.EqualFold(action, "") { + event = event + ":" + action + } + // create the ruledata to purge steps r := &pipeline.RuleData{ Branch: c.build.GetBranch(), Comment: c.comment, - Event: c.build.GetEvent(), + Event: event, Path: c.files, Repo: c.repo.GetFullName(), Tag: strings.TrimPrefix(c.build.GetRef(), "refs/tags/"), diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index b95d018c5..c61cb0984 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -156,6 +156,7 @@ func TestNative_EnvironmentSteps(t *testing.T) { "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "0", "VELA_BUILD_EVENT": "", + "VELA_BUILD_EVENT_ACTION": "", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "", @@ -303,6 +304,7 @@ func TestNative_EnvironmentServices(t *testing.T) { "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "0", "VELA_BUILD_EVENT": "", + "VELA_BUILD_EVENT_ACTION": "", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "", @@ -462,6 +464,7 @@ func TestNative_EnvironmentSecrets(t *testing.T) { "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "0", "VELA_BUILD_EVENT": "", + "VELA_BUILD_EVENT_ACTION": "", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "", @@ -545,6 +548,7 @@ func TestNative_environment(t *testing.T) { tagref := "refs/tags/1" // pull_request pull := "pull_request" + pullact := "opened" pullref := "refs/pull/1/head" // deployment deploy := "deployment" @@ -565,7 +569,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { @@ -574,16 +578,16 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { w: workspace, - b: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &pull, 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: &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}, m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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 { @@ -592,7 +596,7 @@ func TestNative_environment(t *testing.T) { m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, }, } @@ -657,6 +661,7 @@ func Test_client_EnvironmentBuild(t *testing.T) { tagref := "refs/tags/1" // pull_request pull := "pull_request" + pullact := "opened" pullref := "refs/pull/1/head" // deployment deploy := "deployment" @@ -679,27 +684,27 @@ func Test_client_EnvironmentBuild(t *testing.T) { metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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, 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: &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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "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_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, }, } for _, tt := range tests { diff --git a/database/postgres/build_list_test.go b/database/postgres/build_list_test.go index 17b7a09de..bd2e34878 100644 --- a/database/postgres/build_list_test.go +++ b/database/postgres/build_list_test.go @@ -46,9 +46,9 @@ func TestPostgres_Client_GetBuildList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -112,9 +112,9 @@ func TestPostgres_Client_GetDeploymentBuildList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT * FROM \"builds\" WHERE \"source\" = $1 ORDER BY number DESC LIMIT 3").WillReturnRows(_rows) @@ -182,9 +182,9 @@ func TestPostgres_Client_GetOrgBuildList(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -254,8 +254,8 @@ func TestPostgres_Client_GetOrgBuildList_NonAdmin(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"visibility\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -327,9 +327,9 @@ func TestPostgres_Client_GetOrgBuildListByEvent(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"event\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) @@ -412,9 +412,9 @@ func TestPostgres_Client_GetRepoBuildList(t *testing.T) { // create expected return in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // 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 10`).WillReturnRows(_rows) diff --git a/database/postgres/build_test.go b/database/postgres/build_test.go index e152adfe5..b490ee6a1 100644 --- a/database/postgres/build_test.go +++ b/database/postgres/build_test.go @@ -48,8 +48,8 @@ func TestPostgres_Client_GetBuild(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -125,8 +125,8 @@ func TestPostgres_Client_GetLastBuild(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -202,8 +202,8 @@ func TestPostgres_Client_GetLastBuildByBranch(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -348,8 +348,8 @@ func TestPostgres_Client_CreateBuild(t *testing.T) { _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "builds" ("repo_id","pipeline_id","number","parent","event","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","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30) RETURNING "id"`). - WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectQuery(`INSERT INTO "builds" ("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","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31) RETURNING "id"`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnRows(_rows) // setup tests @@ -404,8 +404,8 @@ func TestPostgres_Client_UpdateBuild(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "builds" SET "repo_id"=$1,"pipeline_id"=$2,"number"=$3,"parent"=$4,"event"=$5,"status"=$6,"error"=$7,"enqueued"=$8,"created"=$9,"started"=$10,"finished"=$11,"deploy"=$12,"deploy_payload"=$13,"clone"=$14,"source"=$15,"title"=$16,"message"=$17,"commit"=$18,"sender"=$19,"author"=$20,"email"=$21,"link"=$22,"branch"=$23,"ref"=$24,"base_ref"=$25,"head_ref"=$26,"host"=$27,"runtime"=$28,"distribution"=$29 WHERE "id" = $30`). - WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + _mock.ExpectExec(`UPDATE "builds" SET "repo_id"=$1,"pipeline_id"=$2,"number"=$3,"parent"=$4,"event"=$5,"event_action"=$6,"status"=$7,"error"=$8,"enqueued"=$9,"created"=$10,"started"=$11,"finished"=$12,"deploy"=$13,"deploy_payload"=$14,"clone"=$15,"source"=$16,"title"=$17,"message"=$18,"commit"=$19,"sender"=$20,"author"=$21,"email"=$22,"link"=$23,"branch"=$24,"ref"=$25,"base_ref"=$26,"head_ref"=$27,"host"=$28,"runtime"=$29,"distribution"=$30 WHERE "id" = $31`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnResult(sqlmock.NewResult(1, 1)) // setup tests @@ -495,6 +495,7 @@ func testBuild() *library.Build { Number: &i, Parent: &i, Event: &str, + EventAction: &str, Status: &str, Error: &str, Enqueued: &i64, diff --git a/database/postgres/ddl/build.go b/database/postgres/ddl/build.go index f358fce16..fd4d77db7 100644 --- a/database/postgres/ddl/build.go +++ b/database/postgres/ddl/build.go @@ -17,6 +17,7 @@ builds ( number INTEGER, parent INTEGER, event VARCHAR(250), + event_action VARCHAR(250), status VARCHAR(250), error VARCHAR(1000), enqueued INTEGER, diff --git a/database/sqlite/build_test.go b/database/sqlite/build_test.go index dcb28b41b..c275ae6c7 100644 --- a/database/sqlite/build_test.go +++ b/database/sqlite/build_test.go @@ -519,6 +519,7 @@ func testBuild() *library.Build { Number: &i, Parent: &i, Event: &str, + EventAction: &str, Status: &str, Error: &str, Enqueued: &i64, diff --git a/database/sqlite/ddl/build.go b/database/sqlite/ddl/build.go index 87c505df6..db9f5d5cc 100644 --- a/database/sqlite/ddl/build.go +++ b/database/sqlite/ddl/build.go @@ -17,6 +17,7 @@ builds ( number INTEGER, parent INTEGER, event TEXT, + event_action TEXT, status TEXT, error TEXT, enqueued INTEGER, diff --git a/go.mod b/go.mod index abb707fe9..42d2f0442 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281 + github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v42 v42.0.0 diff --git a/go.sum b/go.sum index df963167a..918738627 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281 h1:n+zZS6OkXJ21YaGmDpk8ge4G/8iXBMlKUUUDfZuEc3c= -github.com/go-vela/types v0.13.1-0.20220419120049-00bb10826281/go.mod h1:LDI9YXINK8Zz0DvvruJLFLoJyxaxetXme1pZAXvQkhU= +github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281 h1:2QYp82wFAUZQ/3gL5GKaCmIJn9iU8playVu6SdVUwB4= +github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281/go.mod h1:LDI9YXINK8Zz0DvvruJLFLoJyxaxetXme1pZAXvQkhU= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 8c690bcce..1822164b4 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -56,6 +56,7 @@ func TestBuild_Establish(t *testing.T) { want.SetNumber(1) want.SetParent(1) want.SetEvent("") + want.SetEventAction("") want.SetStatus("") want.SetError("") want.SetEnqueued(0) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 9b55c16f0..67b3a17dd 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -184,9 +184,10 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven return &types.Webhook{Hook: h}, nil } - // skip if the pull request action is not opened or synchronize + // skip if the pull request action is not opened, synchronize, or edited if !strings.EqualFold(payload.GetAction(), "opened") && - !strings.EqualFold(payload.GetAction(), "synchronize") { + !strings.EqualFold(payload.GetAction(), "synchronize") && + !strings.EqualFold(payload.GetAction(), "edited") { return &types.Webhook{Hook: h}, nil } @@ -206,6 +207,7 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven // convert payload to library build b := new(library.Build) b.SetEvent(constants.EventPull) + b.SetEventAction(payload.GetAction()) b.SetClone(repo.GetCloneURL()) b.SetSource(payload.GetPullRequest().GetHTMLURL()) b.SetTitle(fmt.Sprintf("%s received from %s", constants.EventPull, repo.GetHTMLURL())) @@ -372,6 +374,7 @@ func (c *client) processIssueCommentEvent(h *library.Hook, payload *github.Issue // convert payload to library build b := new(library.Build) b.SetEvent(constants.EventComment) + b.SetEventAction(payload.GetAction()) b.SetClone(repo.GetCloneURL()) b.SetSource(payload.Issue.GetHTMLURL()) b.SetTitle(fmt.Sprintf("%s received from %s", constants.EventComment, repo.GetHTMLURL())) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 98aab8daa..2d0eccff0 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -224,6 +224,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantBuild := new(library.Build) wantBuild.SetEvent("pull_request") + wantBuild.SetEventAction("opened") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") wantBuild.SetSource("https://github.com/Codertocat/Hello-World/pull/1") wantBuild.SetTitle("pull_request received from https://github.com/Codertocat/Hello-World") @@ -768,6 +769,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { wantBuild := new(library.Build) wantBuild.SetEvent("comment") + wantBuild.SetEventAction("created") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") wantBuild.SetSource("https://github.com/Codertocat/Hello-World/pull/1") wantBuild.SetTitle("comment received from https://github.com/Codertocat/Hello-World") @@ -843,6 +845,7 @@ func TestGithub_ProcessWebhook_IssueComment_Created(t *testing.T) { wantBuild := new(library.Build) wantBuild.SetEvent("comment") + wantBuild.SetEventAction("created") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") wantBuild.SetSource("https://github.com/Codertocat/Hello-World/issues/1") wantBuild.SetTitle("comment received from https://github.com/Codertocat/Hello-World") From efe4228e9a525436242b54cc32f080e3e78b8ca1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 11:43:30 -0500 Subject: [PATCH 051/298] fix(deps): update golang.org/x/oauth2 digest to 9780585 (#632) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 42d2f0442..0a2a6a225 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.8.2 github.com/urfave/cli/v2 v2.5.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd - golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a + golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.5 diff --git a/go.sum b/go.sum index 918738627..de2c76916 100644 --- a/go.sum +++ b/go.sum @@ -736,8 +736,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 5b0c40882b93e8b95aa44038a797d0ca9a25e91f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 12:25:49 -0500 Subject: [PATCH 052/298] fix(deps): update module github.com/aws/aws-sdk-go to v1.44.4 (#633) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a2a6a225..fabee8b2d 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.20.0 - github.com/aws/aws-sdk-go v1.43.10 + github.com/aws/aws-sdk-go v1.44.4 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 diff --git a/go.sum b/go.sum index de2c76916..a23503ecb 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.43.10 h1:lFX6gzTBltYBnlJBjd2DWRCmqn2CbTcs6PW99/Dme7k= -github.com/aws/aws-sdk-go v1.43.10/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= +github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= From ffec8aed4a8cfe81819adf000debd6303e9726c3 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 2 May 2022 13:14:01 -0600 Subject: [PATCH 053/298] feat(scm/api/hook): create in-house webhook redelivery method (#622) * stash apply * handle webhook redelivery * fix merge conflict fallout Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/hook.go | 97 ++++++++++++++++++ compiler/native/compile_test.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/github_test.go | 2 +- compiler/registry/github/template.go | 2 +- database/postgres/hook_test.go | 25 ++--- database/sqlite/hook_test.go | 25 ++--- go.mod | 2 +- go.sum | 9 +- router/hook.go | 4 +- scm/github/access.go | 2 +- scm/github/authentication.go | 2 +- scm/github/changeset.go | 2 +- scm/github/deployment.go | 2 +- scm/github/github.go | 2 +- scm/github/github_test.go | 2 +- scm/github/repo.go | 2 +- scm/github/testdata/delivery_summaries.json | 72 ++++++++++++++ scm/github/webhook.go | 62 +++++++++++- scm/github/webhook_test.go | 103 ++++++++++++++++++++ scm/service.go | 4 + 21 files changed, 381 insertions(+), 44 deletions(-) create mode 100644 scm/github/testdata/delivery_summaries.json diff --git a/api/hook.go b/api/hook.go index 50efde981..76af6f11f 100644 --- a/api/hook.go +++ b/api/hook.go @@ -12,6 +12,7 @@ import ( "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/database" "github.com/go-vela/server/router/middleware/repo" @@ -588,3 +589,99 @@ func DeleteHook(c *gin.Context) { c.JSON(http.StatusOK, fmt.Sprintf("hook %s deleted", entry)) } + +// swagger:operation POST /api/v1/hooks/{org}/{repo}/{hook}/redeliver webhook RedeliverHook +// +// Redeliver a webhook from the SCM +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: hook +// description: Number of the hook +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully redelivered the webhook +// schema: +// "$ref": "#/definitions/Webhook" +// '400': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" + +// RedeliverHook represents the API handler to redeliver +// a webhook from the SCM. + +func RedeliverHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + hook := c.Param("hook") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "hook": hook, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("redelivering hook %s", entry) + + number, err := strconv.Atoi(hook) + if err != nil { + retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the webhook + h, err := database.FromContext(c).GetHook(number, r) + if err != nil { + retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + err = scm.FromContext(c).RedeliverWebhook(c, u, r, h) + if err != nil { + retErr := fmt.Errorf("unable to redeliver hook %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("hook %s redelivered", entry)) +} diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 252683309..b8cea0052 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/raw" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" "testing" "time" diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index 08c85cff3..35435c33a 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -9,7 +9,7 @@ import ( "net/url" "strings" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index 6318226af..760ce9018 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index 3ce99f0b0..ea6b94a32 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // Template captures the templated pipeline configuration from the GitHub repo. diff --git a/database/postgres/hook_test.go b/database/postgres/hook_test.go index 584b18a7e..380a32fab 100644 --- a/database/postgres/hook_test.go +++ b/database/postgres/hook_test.go @@ -327,17 +327,18 @@ func testHook() *library.Hook { str := "" return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, + ID: &i64, + RepoID: &i64, + BuildID: &i64, + Number: &i, + SourceID: &str, + Created: &i64, + Host: &str, + Event: &str, + Branch: &str, + Error: &str, + Status: &str, + Link: &str, + WebhookID: &i64, } } diff --git a/database/sqlite/hook_test.go b/database/sqlite/hook_test.go index 1ac6fe85d..03d27b9ac 100644 --- a/database/sqlite/hook_test.go +++ b/database/sqlite/hook_test.go @@ -322,17 +322,18 @@ func testHook() *library.Hook { str := "" return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, + ID: &i64, + RepoID: &i64, + BuildID: &i64, + Number: &i, + SourceID: &str, + Created: &i64, + Host: &str, + Event: &str, + Branch: &str, + Error: &str, + Status: &str, + Link: &str, + WebhookID: &i64, } } diff --git a/go.mod b/go.mod index fabee8b2d..e23d027c6 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 - github.com/google/go-github/v42 v42.0.0 + github.com/google/go-github/v44 v44.0.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.1 github.com/hashicorp/go-cleanhttp v0.5.2 diff --git a/go.sum b/go.sum index a23503ecb..355e8b9f2 100644 --- a/go.sum +++ b/go.sum @@ -84,7 +84,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bradleyfalzon/ghinstallation/v2 v2.0.3/go.mod h1:tlgi+JWCXnKFx/Y4WtnDbZEINo31N5bcvnCoqieefmk= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= @@ -188,7 +187,6 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -236,12 +234,11 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v39 v39.0.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= -github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec= -github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg= +github.com/google/go-github/v44 v44.0.0 h1:1Lfk2mhM7pTWqwGC6Ft16S3c2LBw8DLcw9TOhYoQ9zE= +github.com/google/go-github/v44 v44.0.0/go.mod h1:CqZYQRxOcb81M+ufZB7duWNS0lFfas/r7cEAKpLBYww= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/router/hook.go b/router/hook.go index 97c7d53f3..8237cc87a 100644 --- a/router/hook.go +++ b/router/hook.go @@ -19,7 +19,8 @@ import ( // GET /api/v1/hooks/:org/:repo // GET /api/v1/hooks/:org/:repo/:hook // PUT /api/v1/hooks/:org/:repo/:hook -// DELETE /api/v1/hooks/:org/:repo/:hook . +// DELETE /api/v1/hooks/:org/:repo/:hook +// POST /api/v1/hooks/:org/:repo/:hook/redeliver . func HookHandlers(base *gin.RouterGroup) { // Hooks endpoints hooks := base.Group("/hooks/:org/:repo", org.Establish(), repo.Establish()) @@ -29,5 +30,6 @@ func HookHandlers(base *gin.RouterGroup) { hooks.GET("/:hook", perm.MustRead(), api.GetHook) hooks.PUT("/:hook", perm.MustPlatformAdmin(), api.UpdateHook) hooks.DELETE("/:hook", perm.MustPlatformAdmin(), api.DeleteHook) + hooks.POST("/:hook/redeliver", perm.MustWrite(), api.RedeliverHook) } // end of hooks endpoints } diff --git a/scm/github/access.go b/scm/github/access.go index d8d7a8afd..ba9d4826c 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // OrgAccess captures the user's access level for an org. diff --git a/scm/github/authentication.go b/scm/github/authentication.go index 0d3bf4b26..fafc1be94 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -14,7 +14,7 @@ import ( "github.com/go-vela/server/random" "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // Authorize uses the given access token to authorize the user. diff --git a/scm/github/changeset.go b/scm/github/changeset.go index 72ffee69c..d2ad5187d 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // Changeset captures the list of files changed for a commit. diff --git a/scm/github/deployment.go b/scm/github/deployment.go index 68b127450..a1a112efa 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/raw" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // GetDeployment gets a deployment from the GitHub repo. diff --git a/scm/github/github.go b/scm/github/github.go index f3d8e5665..037c779f2 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" "github.com/sirupsen/logrus" "golang.org/x/oauth2" diff --git a/scm/github/github_test.go b/scm/github/github_test.go index 059b6392d..5131e161d 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" "golang.org/x/oauth2" ) diff --git a/scm/github/repo.go b/scm/github/repo.go index 96afc608b..40a6c2bd4 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // ConfigBackoff is a wrapper for Config that will retry five times if the function diff --git a/scm/github/testdata/delivery_summaries.json b/scm/github/testdata/delivery_summaries.json new file mode 100644 index 000000000..12d8e3ae5 --- /dev/null +++ b/scm/github/testdata/delivery_summaries.json @@ -0,0 +1,72 @@ +[ + { + "id": 22948189250, + "guid": "b6552230-aee1-11ec-949c-91a5dc3f8159", + "delivered_at": "2022-03-28T21:54:59Z", + "redelivery": false, + "duration": 0.4, + "status": "Invalid HTTP Response: 404", + "status_code": 404, + "event": "pull_request", + "action": "edited", + "installation_id": null, + "repository_id": 219518422, + "url": "" + }, + { + "id": 22948188373, + "guid": "b595f0e0-aee1-11ec-86cf-9418381395c4", + "delivered_at": "2022-03-28T21:54:58Z", + "redelivery": false, + "duration": 0.31, + "status": "Invalid HTTP Response: 404", + "status_code": 404, + "event": "pull_request", + "action": "synchronize", + "installation_id": null, + "repository_id": 219518422, + "url": "" + }, + { + "id": 22948187625, + "guid": "b4f5b1a2-aee1-11ec-94e7-28efa21cef07", + "delivered_at": "2022-03-28T21:54:57Z", + "redelivery": false, + "duration": 0.28, + "status": "Invalid HTTP Response: 404", + "status_code": 404, + "event": "push", + "action": null, + "installation_id": null, + "repository_id": 219518422, + "url": "" + }, + { + "id": 22939666537, + "guid": "5275f5b0-aec7-11ec-9778-f09445731fb3", + "delivered_at": "2022-03-28T18:46:05Z", + "redelivery": false, + "duration": 0.29, + "status": "Invalid HTTP Response: 404", + "status_code": 404, + "event": "pull_request", + "action": "synchronize", + "installation_id": null, + "repository_id": 219518422, + "url": "" + }, + { + "id": 22939665716, + "guid": "51d8149e-aec7-11ec-8377-b51dc14c4d81", + "delivered_at": "2022-03-28T18:46:04Z", + "redelivery": false, + "duration": 0.3, + "status": "Invalid HTTP Response: 404", + "status_code": 404, + "event": "push", + "action": null, + "installation_id": null, + "repository_id": 219518422, + "url": "" + } +] \ No newline at end of file diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 67b3a17dd..6e063b65a 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -5,6 +5,7 @@ package github import ( + "context" "encoding/json" "fmt" "net/http" @@ -17,7 +18,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v42/github" + "github.com/google/go-github/v44/github" ) // nolint: nilerr // ignore webhook returning nil @@ -88,6 +89,28 @@ func (c *client) VerifyWebhook(request *http.Request, r *library.Repo) error { return nil } +// RedeliverWebhook redelivers webhooks from GitHub. +func (c *client) RedeliverWebhook(ctx context.Context, u *library.User, r *library.Repo, h *library.Hook) error { + // create GitHub OAuth client with user's token + // nolint: contextcheck // do not need to pass context in this instance + client := c.newClientToken(*u.Token) + + // capture the delivery ID of the hook using GitHub API + deliveryID, err := c.getDeliveryID(ctx, client, r, h) + if err != nil { + return err + } + + // redeliver the webhook + _, _, err = client.Repositories.RedeliverHookDelivery(ctx, r.GetOrg(), r.GetName(), h.GetWebhookID(), deliveryID) + + if err != nil { + return err + } + + return nil +} + // processPushEvent is a helper function to process the push event. func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (*types.Webhook, error) { c.Logger.WithFields(logrus.Fields{ @@ -440,3 +463,40 @@ func (c *client) processRepositoryEvent(h *library.Hook, payload *github.Reposit Repo: r, }, nil } + +// getDeliveryID gets the last 100 webhook deliveries for a repo and +// finds the matching delivery id with the source id in the hook. +func (c *client) getDeliveryID(ctx context.Context, ghClient *github.Client, r *library.Repo, h *library.Hook) (int64, error) { + c.Logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("searching for delivery id for hook: %s", h.GetSourceID()) + + // set per page to 100 to retrieve last 100 hook summaries + opt := &github.ListCursorOptions{PerPage: 100} + + // send API call to capture delivery summaries that contain Delivery ID value + deliveries, resp, err := ghClient.Repositories.ListHookDeliveries(ctx, r.GetOrg(), r.GetName(), h.GetWebhookID(), opt) + + // version check: if GitHub API is older than version 3.2, this call will not work + if resp.StatusCode == 415 { + err = fmt.Errorf("requires GitHub version 3.2 or later") + return 0, err + } + + if err != nil { + return 0, err + } + + // cycle through delivery summaries and match Source ID/GUID. Capture Delivery ID + for _, delivery := range deliveries { + if delivery.GetGUID() == h.GetSourceID() { + return delivery.GetID(), nil + } + } + + // if not found, webhook was not recent enough for GitHub + err = fmt.Errorf("webhook not one of the 100 most recent deliveries") + + return 0, err +} diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 2d0eccff0..f82d2d2a1 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/types/raw" "github.com/google/go-cmp/cmp" @@ -1051,3 +1052,105 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { t.Errorf("ProcessWebhook is %v, want %v", got, want) } } + +func TestGithub_Redeliver_Webhook(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.POST("/api/v3/repos/:org/:repo/hooks/:repo_id/deliveries/:delivery_id/attempts", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/hooks/push.json") + }) + engine.GET("/api/v3/repos/:org/:repo/hooks/:hook_id/deliveries", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/delivery_summaries.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("octocat") + u.SetToken("foo") + + _hook := new(library.Hook) + _hook.SetSourceID("b595f0e0-aee1-11ec-86cf-9418381395c4") + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetWebhookID(1234) + + _repo := new(library.Repo) + _repo.SetID(1) + _repo.SetName("bar") + _repo.SetOrg("foo") + + client, _ := NewTest(s.URL, "https://foo.bar.com") + + // run test + err := client.RedeliverWebhook(ctx, u, _repo, _hook) + + if err != nil { + t.Errorf("RedeliverWebhook returned err: %v", err) + } +} + +func TestGithub_GetDeliveryID(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + engine.GET("/api/v3/repos/:org/:repo/hooks/:hook_id/deliveries", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/delivery_summaries.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("octocat") + u.SetToken("foo") + + _hook := new(library.Hook) + _hook.SetSourceID("b595f0e0-aee1-11ec-86cf-9418381395c4") + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetWebhookID(1234) + + _repo := new(library.Repo) + _repo.SetID(1) + _repo.SetName("bar") + _repo.SetOrg("foo") + + want := int64(22948188373) + + client, _ := NewTest(s.URL, "https://foo.bar.com") + + ghClient := client.newClientToken(*u.Token) + + // run test + got, err := client.getDeliveryID(ctx, ghClient, _repo, _hook) + + if err != nil { + t.Errorf("RedeliverWebhook returned err: %v", err) + } + + if got != want { + t.Errorf("getDeliveryID returned: %v; want: %v", got, want) + } +} diff --git a/scm/service.go b/scm/service.go index efcf6d8fb..75f3685bd 100644 --- a/scm/service.go +++ b/scm/service.go @@ -5,6 +5,7 @@ package scm import ( + "context" "net/http" "github.com/go-vela/types" @@ -122,6 +123,9 @@ type Service interface { // VerifyWebhook defines a function that // verifies the webhook from a repo. VerifyWebhook(*http.Request, *library.Repo) error + // RedeliverWebhook defines a function that + // redelivers the webhook from the SCM. + RedeliverWebhook(context.Context, *library.User, *library.Repo, *library.Hook) error // TODO: Add convert functions to interface? } From 7ce7bd82d9adc752a56e63b4c13dd12d6e97bde3 Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Mon, 2 May 2022 15:33:24 -0500 Subject: [PATCH 054/298] chore(release): dependency updates for v0.14.0-rc1 (#634) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e23d027c6..42fdefa7b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281 + github.com/go-vela/types v0.14.0-rc1 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.0.0 diff --git a/go.sum b/go.sum index 355e8b9f2..91a5142a8 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281 h1:2QYp82wFAUZQ/3gL5GKaCmIJn9iU8playVu6SdVUwB4= -github.com/go-vela/types v0.13.1-0.20220426202924-efda5bc01281/go.mod h1:LDI9YXINK8Zz0DvvruJLFLoJyxaxetXme1pZAXvQkhU= +github.com/go-vela/types v0.14.0-rc1 h1:zckr7Cywbw97IfYu/F/e1yscIW72HL0VhhNtp1NV5kQ= +github.com/go-vela/types v0.14.0-rc1/go.mod h1:g2C+XdTuq2hzrsEUt+jVLLqmhgogoXryQEok3EK3HkE= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From 0951009a47f12b1572bba7bc8e7a6d865760acdd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 May 2022 12:10:00 -0500 Subject: [PATCH 055/298] fix(deps): update module k8s.io/apimachinery to v0.24.0 (#635) Co-authored-by: Renovate Bot --- go.mod | 6 +++--- go.sum | 24 +++++++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 42fdefa7b..8e2827db4 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( gorm.io/driver/postgres v1.3.5 gorm.io/driver/sqlite v1.3.2 gorm.io/gorm v1.23.5 - k8s.io/apimachinery v0.23.6 + k8s.io/apimachinery v0.24.0 ) require ( @@ -125,7 +125,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect @@ -133,5 +133,5 @@ require ( google.golang.org/grpc v1.41.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.30.0 // indirect + k8s.io/klog/v2 v2.60.1 // indirect ) diff --git a/go.sum b/go.sum index 91a5142a8..e21ac4429 100644 --- a/go.sum +++ b/go.sum @@ -74,6 +74,7 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= @@ -224,6 +225,7 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -266,8 +268,6 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= @@ -720,7 +720,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -806,10 +805,10 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -819,7 +818,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1038,20 +1036,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.23.6 h1:RH1UweWJkWNTlFx0D8uxOpaU1tjIOvVVWV/bu5b3/NQ= -k8s.io/apimachinery v0.23.6/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ= +k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= From 168d207f101e89e4d0193196a1f4af581e87c8b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 08:41:07 -0500 Subject: [PATCH 056/298] fix(deps): update module github.com/urfave/cli/v2 to v2.6.0 (#638) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8e2827db4..3fe5ec703 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.2 - github.com/urfave/cli/v2 v2.5.1 + github.com/urfave/cli/v2 v2.6.0 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index e21ac4429..c7b62dc70 100644 --- a/go.sum +++ b/go.sum @@ -593,8 +593,8 @@ github.com/ugorji/go v1.1.11/go.mod h1:kbRrdMyHY64ADdazOwkrQP9btxt35Z26OJueD3Tq0 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.11 h1:GaQDxjNe1J3vCZvlVaDjUIHIbFuUByFXY7rMqnhB5ck= github.com/ugorji/go/codec v1.1.11/go.mod h1:svMFxxx5FVQJPnJ9vbpAgscNufuiXDyldvzApI86qQo= -github.com/urfave/cli/v2 v2.5.1 h1:YKwdkyA0xTBzOaP2G0DVxBnCheHGP+Y9VbKAs4K1Ess= -github.com/urfave/cli/v2 v2.5.1/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= +github.com/urfave/cli/v2 v2.6.0 h1:yj2Drkflh8X/zUrkWlWlUjZYHyWN7WMmpVxyxXIUyv8= +github.com/urfave/cli/v2 v2.6.0/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 1c061a4a9e8a0c3d669bb1355055a9e478a6eece Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 11:32:30 -0500 Subject: [PATCH 057/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.21.0 (#636) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3fe5ec703..ae8abe75b 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.20.0 + github.com/alicebob/miniredis/v2 v2.21.0 github.com/aws/aws-sdk-go v1.44.4 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 diff --git a/go.sum b/go.sum index c7b62dc70..8791bebff 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.20.0 h1:NJSfJcoyPvs9t+wqnox5BTcNVn7J9KxYl0RioTcE8S4= -github.com/alicebob/miniredis/v2 v2.20.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= +github.com/alicebob/miniredis/v2 v2.21.0 h1:CdmwIlKUWFBDS+4464GtQiQ0R1vpzOgu4Vnd74rBL7M= +github.com/alicebob/miniredis/v2 v2.21.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= From 9c892824c5ca9843f29046905b9b6b0944f3e3f2 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 18 May 2022 14:15:38 -0500 Subject: [PATCH 058/298] fix(api/build): restarting before pipeline support (#642) --- api/build.go | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/api/build.go b/api/build.go index add13aa5a..3f3d290ec 100644 --- a/api/build.go +++ b/api/build.go @@ -1055,20 +1055,9 @@ func RestartBuild(c *gin.Context) { pipelineType = r.GetPipelineType() ) - // check if the build was created after pipeline support was added - if b.GetPipelineID() > 0 { - // send API call to capture the pipeline - pipeline, err = database.FromContext(c).GetPipeline(b.GetPipelineID()) - if err != nil { - retErr := fmt.Errorf("unable to get pipeline for %s: %w", entry, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - config = pipeline.GetData() - } else { // keep original behavior for builds ran before pipeline support was added + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) // send API call to capture the pipeline configuration file config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) if err != nil { @@ -1078,6 +1067,8 @@ func RestartBuild(c *gin.Context) { return } + } else { + config = pipeline.GetData() } // ensure we use the expected pipeline type when compiling From 24d566d2af931c066e8990fb07733f6d903147cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 May 2022 10:53:09 +0000 Subject: [PATCH 059/298] fix(deps): update deps (patch) (#640) Co-authored-by: Renovate Bot --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index ae8abe75b..696096d2a 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.21.0 - github.com/aws/aws-sdk-go v1.44.4 + github.com/aws/aws-sdk-go v1.44.17 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.7.7 @@ -26,7 +26,7 @@ require ( github.com/hashicorp/vault/api v1.5.0 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/client_golang v1.12.2 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.2 github.com/urfave/cli/v2 v2.6.0 diff --git a/go.sum b/go.sum index 8791bebff..39b1db29c 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= -github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.17 h1:of8MirZuVDat3BJgRbSwDO/GM/cgXh5Znf2tyEAv/vE= +github.com/aws/aws-sdk-go v1.44.17/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -527,8 +527,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From 8db1ffdadd004e611aa834c80a41e6b4f93610b2 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 24 May 2022 19:18:53 -0500 Subject: [PATCH 060/298] fix: all alerts flagged by CodeQL (#645) --- api/authenticate.go | 8 ++-- api/badge.go | 7 ++-- api/deployment.go | 9 ++--- api/hook.go | 17 ++++---- api/login.go | 8 ++-- api/pipeline/output.go | 3 +- api/repo.go | 29 ++++++-------- api/secret.go | 50 ++++++++++++------------ api/user.go | 10 ++--- router/middleware/build/build.go | 12 +++--- router/middleware/executors/executors.go | 11 ++---- router/middleware/logger.go | 12 +++--- router/middleware/org/org.go | 6 +-- router/middleware/perm/perm.go | 12 +++--- router/middleware/pipeline/pipeline.go | 4 +- router/middleware/repo/repo.go | 16 ++++---- router/middleware/service/service.go | 14 +++---- router/middleware/step/step.go | 14 +++---- router/middleware/worker/worker.go | 10 ++--- util/util.go | 31 ++++++++++++++- 20 files changed, 141 insertions(+), 142 deletions(-) diff --git a/api/authenticate.go b/api/authenticate.go index a31903f72..4f14465b0 100644 --- a/api/authenticate.go +++ b/api/authenticate.go @@ -9,15 +9,13 @@ import ( "fmt" "net/http" + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/token" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -247,8 +245,8 @@ func AuthenticateType(c *gin.Context) { logrus.Info("redirecting for final auth flow destination") // capture the path elements - t := c.Param("type") - p := c.Param("port") + t := util.PathParameter(c, "type") + p := util.PathParameter(c, "port") // capture the current query parameters - // they should contain the "code" and "state" values diff --git a/api/badge.go b/api/badge.go index 79ef4e008..799de69ab 100644 --- a/api/badge.go +++ b/api/badge.go @@ -7,13 +7,12 @@ package api import ( "net/http" + "github.com/gin-gonic/gin" "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/util" "github.com/go-vela/types/constants" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -47,7 +46,7 @@ func GetBadge(c *gin.Context) { // capture middleware values o := org.Retrieve(c) r := repo.Retrieve(c) - branch := c.DefaultQuery("branch", r.GetBranch()) + branch := util.QueryParameter(c, "branch", r.GetBranch()) // update engine logger with API metadata // diff --git a/api/deployment.go b/api/deployment.go index fda280d15..293dbbc6e 100644 --- a/api/deployment.go +++ b/api/deployment.go @@ -9,17 +9,14 @@ import ( "net/http" "strconv" - "github.com/go-vela/server/router/middleware/org" - + "github.com/gin-gonic/gin" "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/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -305,7 +302,7 @@ func GetDeployment(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) - deployment := c.Param("deployment") + deployment := util.PathParameter(c, "deployment") entry := fmt.Sprintf("%s/%s", r.GetFullName(), deployment) diff --git a/api/hook.go b/api/hook.go index 76af6f11f..29a1ffae9 100644 --- a/api/hook.go +++ b/api/hook.go @@ -10,17 +10,14 @@ import ( "strconv" "time" + "github.com/gin-gonic/gin" + "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/scm" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -305,7 +302,7 @@ func GetHook(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) - hook := c.Param("hook") + hook := util.PathParameter(c, "hook") entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) @@ -397,7 +394,7 @@ func UpdateHook(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) - hook := c.Param("hook") + hook := util.PathParameter(c, "hook") entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) @@ -544,7 +541,7 @@ func DeleteHook(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) - hook := c.Param("hook") + hook := util.PathParameter(c, "hook") entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) @@ -641,7 +638,7 @@ func RedeliverHook(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) - hook := c.Param("hook") + hook := util.PathParameter(c, "hook") entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) diff --git a/api/login.go b/api/login.go index 1aa816730..74ac91226 100644 --- a/api/login.go +++ b/api/login.go @@ -9,9 +9,9 @@ import ( "net/http" "net/url" - "github.com/go-vela/types" - "github.com/gin-gonic/gin" + "github.com/go-vela/server/util" + "github.com/go-vela/types" "github.com/sirupsen/logrus" ) @@ -43,8 +43,8 @@ func Login(c *gin.Context) { m := c.MustGet("metadata").(*types.Metadata) // capture query params - t := c.Request.FormValue("type") - p := c.Request.FormValue("port") + t := util.FormParameter(c, "type") + p := util.FormParameter(c, "port") // temp variable to hold redirect destination r := "" diff --git a/api/pipeline/output.go b/api/pipeline/output.go index c9adfbd97..46fcace56 100644 --- a/api/pipeline/output.go +++ b/api/pipeline/output.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/gin-gonic/gin" + "github.com/go-vela/server/util" ) const ( @@ -20,7 +21,7 @@ const ( // request based off the output query parameter provided. If no output // query parameter is provided, then YAML is used by default. func writeOutput(c *gin.Context, value interface{}) { - output := c.DefaultQuery("output", outputYAML) + output := util.QueryParameter(c, "output", outputYAML) // format response body based off output query parameter switch strings.ToLower(output) { diff --git a/api/repo.go b/api/repo.go index 1a3c7a89a..b0347a489 100644 --- a/api/repo.go +++ b/api/repo.go @@ -11,18 +11,15 @@ import ( "strconv" "strings" - "github.com/go-vela/server/router/middleware/org" - + "github.com/gin-gonic/gin" "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/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -462,16 +459,16 @@ func GetRepos(c *gin.Context) { // of repos for an org from the configured backend. func GetOrgRepos(c *gin.Context) { // capture middleware values + o := org.Retrieve(c) u := user.Retrieve(c) - org := c.Param("org") // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields logrus.WithFields(logrus.Fields{ - "org": org, + "org": o, "user": u.GetName(), - }).Infof("reading repos for org %s", org) + }).Infof("reading repos for org %s", o) // capture page query parameter if present page, err := strconv.Atoi(c.DefaultQuery("page", "1")) @@ -497,12 +494,12 @@ func GetOrgRepos(c *gin.Context) { perPage = util.MaxInt(1, util.MinInt(100, perPage)) // capture the sort_by query parameter if present - sortBy := c.DefaultQuery("sort_by", "name") + sortBy := util.QueryParameter(c, "sort_by", "name") // See if the user is an org admin to bypass individual permission checks - perm, err := scm.FromContext(c).OrgAccess(u, org) + perm, err := scm.FromContext(c).OrgAccess(u, o) if err != nil { - logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), org) + logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) } filters := map[string]string{} @@ -511,12 +508,12 @@ func GetOrgRepos(c *gin.Context) { filters["visibility"] = "public" } - filters["active"] = c.DefaultQuery("active", "true") + filters["active"] = util.QueryParameter(c, "active", "true") // send API call to capture the total number of repos for the org - t, err := database.FromContext(c).GetOrgRepoCount(org, filters) + t, err := database.FromContext(c).GetOrgRepoCount(o, filters) if err != nil { - retErr := fmt.Errorf("unable to get repo count for org %s: %w", org, err) + retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -524,9 +521,9 @@ func GetOrgRepos(c *gin.Context) { } // send API call to capture the list of repos for the org - r, err := database.FromContext(c).GetOrgRepoList(org, filters, page, perPage, sortBy) + r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, perPage, sortBy) if err != nil { - retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) + retErr := fmt.Errorf("unable to get repos for org %s: %w", o, err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/api/secret.go b/api/secret.go index ab293b58c..bb35c80f6 100644 --- a/api/secret.go +++ b/api/secret.go @@ -11,15 +11,13 @@ import ( "strings" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/secret" "github.com/go-vela/server/util" - "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -83,10 +81,10 @@ import ( func CreateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") entry := fmt.Sprintf("%s/%s/%s", t, o, n) @@ -260,10 +258,10 @@ func CreateSecret(c *gin.Context) { func GetSecrets(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") var teams []string // get list of user's teams if type is shared secret and team is '*' @@ -428,11 +426,11 @@ func GetSecrets(c *gin.Context) { func GetSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") - s := strings.TrimPrefix(c.Param("secret"), "/") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) @@ -548,11 +546,11 @@ func GetSecret(c *gin.Context) { func UpdateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") - s := strings.TrimPrefix(c.Param("secret"), "/") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) @@ -695,11 +693,11 @@ func UpdateSecret(c *gin.Context) { func DeleteSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") - s := strings.TrimPrefix(c.Param("secret"), "/") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) diff --git a/api/user.go b/api/user.go index 315514c34..87e0922f1 100644 --- a/api/user.go +++ b/api/user.go @@ -10,15 +10,13 @@ import ( "net/http" "strconv" + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/token" "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" - - "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -355,7 +353,7 @@ func UpdateCurrentUser(c *gin.Context) { func GetUser(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - user := c.Param("user") + user := util.PathParameter(c, "user") // update engine logger with API metadata // @@ -528,7 +526,7 @@ func GetUserSourceRepos(c *gin.Context) { func UpdateUser(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - user := c.Param("user") + user := util.PathParameter(c, "user") // update engine logger with API metadata // @@ -625,7 +623,7 @@ func UpdateUser(c *gin.Context) { func DeleteUser(c *gin.Context) { // capture middleware values u := user.Retrieve(c) - user := c.Param("user") + user := util.PathParameter(c, "user") // update engine logger with API metadata // diff --git a/router/middleware/build/build.go b/router/middleware/build/build.go index 5b521bf36..87b25185b 100644 --- a/router/middleware/build/build.go +++ b/router/middleware/build/build.go @@ -9,15 +9,13 @@ import ( "net/http" "strconv" - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - + "github.com/gin-gonic/gin" "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" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -34,13 +32,13 @@ func Establish() gin.HandlerFunc { u := user.Retrieve(c) if r == nil { - retErr := fmt.Errorf("repo %s/%s not found", c.Param("org"), c.Param("repo")) + retErr := fmt.Errorf("repo %s/%s not found", util.PathParameter(c, "org"), util.PathParameter(c, "repo")) util.HandleError(c, http.StatusNotFound, retErr) return } - bParam := c.Param("build") + bParam := util.PathParameter(c, "build") if len(bParam) == 0 { retErr := fmt.Errorf("no build parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index 87eeb248f..ac775ac27 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -7,19 +7,16 @@ package executors import ( "context" "encoding/json" + "fmt" "io/ioutil" + "net/http" "time" - "github.com/go-vela/types/library" - + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/util" - - "fmt" - "net/http" - - "github.com/gin-gonic/gin" + "github.com/go-vela/types/library" ) // Retrieve gets the executors in the given context. diff --git a/router/middleware/logger.go b/router/middleware/logger.go index 6e8506059..2d49023c6 100644 --- a/router/middleware/logger.go +++ b/router/middleware/logger.go @@ -7,15 +7,15 @@ package middleware import ( "time" - "github.com/go-vela/server/router/middleware/org" - "github.com/gin-gonic/gin" "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/service" "github.com/go-vela/server/router/middleware/step" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/router/middleware/worker" + "github.com/go-vela/server/util" "github.com/sirupsen/logrus" ) @@ -31,7 +31,7 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc return func(c *gin.Context) { start := time.Now() // some evil middlewares modify this values - path := c.Request.URL.Path + path := util.EscapeValue(c.Request.URL.Path) c.Next() @@ -45,13 +45,13 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc // prevent us from logging the health endpoint if c.Request.URL.Path != "/health" { fields := logrus.Fields{ - "ip": c.ClientIP(), + "ip": util.EscapeValue(c.ClientIP()), "latency": latency, "method": c.Request.Method, "path": path, "status": c.Writer.Status(), - "user-agent": c.Request.UserAgent(), - "version": c.GetHeader("X-Vela-Version"), + "user-agent": util.EscapeValue(c.Request.UserAgent()), + "version": util.EscapeValue(c.GetHeader("X-Vela-Version")), } body := c.Value("payload") diff --git a/router/middleware/org/org.go b/router/middleware/org/org.go index 17b384234..153807e4b 100644 --- a/router/middleware/org/org.go +++ b/router/middleware/org/org.go @@ -5,12 +5,11 @@ package org import ( - "github.com/go-vela/server/util" - "fmt" "net/http" "github.com/gin-gonic/gin" + "github.com/go-vela/server/util" ) // Retrieve gets the org in the given context. @@ -21,7 +20,7 @@ func Retrieve(c *gin.Context) string { // Establish used to check if org param is used only. func Establish() gin.HandlerFunc { return func(c *gin.Context) { - oParam := c.Param("org") + oParam := util.PathParameter(c, "org") if len(oParam) == 0 { retErr := fmt.Errorf("no org parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) @@ -30,6 +29,7 @@ func Establish() gin.HandlerFunc { } ToContext(c, oParam) + c.Next() } } diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 60056df9e..92a7e8687 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -9,17 +9,15 @@ import ( "net/http" "strings" + "github.com/gin-gonic/gin" "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/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -52,10 +50,10 @@ func MustPlatformAdmin() gin.HandlerFunc { func MustSecretAdmin() gin.HandlerFunc { return func(c *gin.Context) { u := user.Retrieve(c) - e := c.Param("engine") - t := c.Param("type") - o := c.Param("org") - n := c.Param("name") + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") m := c.Request.Method // create log fields from API metadata diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go index b4cdca1c4..c0b5e2790 100644 --- a/router/middleware/pipeline/pipeline.go +++ b/router/middleware/pipeline/pipeline.go @@ -31,14 +31,14 @@ func Establish() gin.HandlerFunc { u := user.Retrieve(c) if r == nil { - retErr := fmt.Errorf("repo %s/%s not found", c.Param("org"), c.Param("repo")) + retErr := fmt.Errorf("repo %s/%s not found", util.PathParameter(c, "org"), util.PathParameter(c, "repo")) util.HandleError(c, http.StatusNotFound, retErr) return } - p := c.Param("pipeline") + p := util.PathParameter(c, "pipeline") if len(p) == 0 { retErr := fmt.Errorf("no pipeline parameter provided") diff --git a/router/middleware/repo/repo.go b/router/middleware/repo/repo.go index 68b0cc24c..94d85a4c3 100644 --- a/router/middleware/repo/repo.go +++ b/router/middleware/repo/repo.go @@ -5,18 +5,16 @@ package repo import ( - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/util" - "fmt" "net/http" "github.com/gin-gonic/gin" + "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/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" ) // Retrieve gets the repo in the given context. @@ -30,7 +28,7 @@ func Establish() gin.HandlerFunc { o := org.Retrieve(c) u := user.Retrieve(c) - rParam := c.Param("repo") + rParam := util.PathParameter(c, "repo") if len(rParam) == 0 { retErr := fmt.Errorf("no repo parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/router/middleware/service/service.go b/router/middleware/service/service.go index 66adaa082..be36fb7b6 100644 --- a/router/middleware/service/service.go +++ b/router/middleware/service/service.go @@ -9,16 +9,14 @@ import ( "net/http" "strconv" - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" + "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" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -37,20 +35,20 @@ func Establish() gin.HandlerFunc { u := user.Retrieve(c) if r == nil { - retErr := fmt.Errorf("repo %s/%s not found", o, c.Param("repo")) + retErr := fmt.Errorf("repo %s/%s not found", o, util.PathParameter(c, "repo")) util.HandleError(c, http.StatusNotFound, retErr) return } if b == nil { - retErr := fmt.Errorf("build %s not found for repo %s", c.Param("build"), r.GetFullName()) + retErr := fmt.Errorf("build %s not found for repo %s", util.PathParameter(c, "build"), r.GetFullName()) util.HandleError(c, http.StatusNotFound, retErr) return } - sParam := c.Param("service") + sParam := util.PathParameter(c, "service") if len(sParam) == 0 { retErr := fmt.Errorf("no service parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/router/middleware/step/step.go b/router/middleware/step/step.go index 1413cbf35..7dbd2d6c5 100644 --- a/router/middleware/step/step.go +++ b/router/middleware/step/step.go @@ -9,16 +9,14 @@ import ( "net/http" "strconv" - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" + "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" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -37,20 +35,20 @@ func Establish() gin.HandlerFunc { u := user.Retrieve(c) if r == nil { - retErr := fmt.Errorf("repo %s/%s not found", o, c.Param("repo")) + retErr := fmt.Errorf("repo %s/%s not found", o, util.PathParameter(c, "repo")) util.HandleError(c, http.StatusNotFound, retErr) return } if b == nil { - retErr := fmt.Errorf("build %s not found for repo %s", c.Param("build"), r.GetFullName()) + retErr := fmt.Errorf("build %s not found for repo %s", util.PathParameter(c, "build"), r.GetFullName()) util.HandleError(c, http.StatusNotFound, retErr) return } - sParam := c.Param("step") + sParam := util.PathParameter(c, "step") if len(sParam) == 0 { retErr := fmt.Errorf("no step parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/router/middleware/worker/worker.go b/router/middleware/worker/worker.go index f4fc5e524..2f68b811f 100644 --- a/router/middleware/worker/worker.go +++ b/router/middleware/worker/worker.go @@ -5,15 +5,13 @@ package worker import ( - "github.com/go-vela/server/database" - "github.com/go-vela/types/library" - - "github.com/go-vela/server/util" - "fmt" "net/http" "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) @@ -25,7 +23,7 @@ func Retrieve(c *gin.Context) *library.Worker { // Establish sets the worker in the given context. func Establish() gin.HandlerFunc { return func(c *gin.Context) { - wParam := c.Param("worker") + wParam := util.PathParameter(c, "worker") if len(wParam) == 0 { retErr := fmt.Errorf("no worker parameter provided") util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/util/util.go b/util/util.go index 6e7813807..24ac89b67 100644 --- a/util/util.go +++ b/util/util.go @@ -5,8 +5,10 @@ package util import ( - "github.com/gin-gonic/gin" + "html" + "strings" + "github.com/gin-gonic/gin" "github.com/go-vela/types" ) @@ -41,3 +43,30 @@ func MinInt(a, b int) int { return b } + +// FormParameter safely captures a form parameter from the context +// by removing any new lines and HTML escaping the value. +func FormParameter(c *gin.Context, parameter string) string { + return EscapeValue(c.Request.FormValue(parameter)) +} + +// QueryParameter safely captures a query parameter from the context +// by removing any new lines and HTML escaping the value. +func QueryParameter(c *gin.Context, parameter, value string) string { + return EscapeValue(c.DefaultQuery(parameter, value)) +} + +// PathParameter safely captures a path parameter from the context +// by removing any new lines and HTML escaping the value. +func PathParameter(c *gin.Context, parameter string) string { + return EscapeValue(c.Param(parameter)) +} + +// EscapeValue safely escapes any string by removing any new lines and HTML escaping it. +func EscapeValue(value string) string { + // replace all new lines in the value + escaped := strings.Replace(strings.Replace(value, "\n", "", -1), "\r", "", -1) + + // HTML escape the new line escaped value + return html.EscapeString(escaped) +} From 68ad2a14dead80273c8d2ab6aa1837c02acf5b85 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 24 May 2022 20:56:44 -0500 Subject: [PATCH 061/298] fix(api): always set Strict-Transport-Security header (#644) --- router/middleware/header.go | 7 ++----- router/middleware/header_test.go | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/router/middleware/header.go b/router/middleware/header.go index ef3798b0c..39ae9b68c 100644 --- a/router/middleware/header.go +++ b/router/middleware/header.go @@ -51,12 +51,9 @@ func Secure(c *gin.Context) { c.Header("X-Frame-Options", "DENY") c.Header("X-Content-Type-Options", "nosniff") c.Header("X-XSS-Protection", "1; mode=block") - - // Also consider adding Content-Security-Policy headers + // TODO: consider adding Content-Security-Policy headers // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") - if c.Request.TLS != nil { - c.Header("Strict-Transport-Security", "max-age=31536000") - } + c.Header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload") } // Cors is a middleware function that appends headers for diff --git a/router/middleware/header_test.go b/router/middleware/header_test.go index e17e24c18..86f79d41a 100644 --- a/router/middleware/header_test.go +++ b/router/middleware/header_test.go @@ -267,7 +267,7 @@ func TestMiddleware_Secure_TLS(t *testing.T) { wantFrameOptions := "DENY" wantContentTypeOptions := "nosniff" wantProtection := "1; mode=block" - wantSecurity := "max-age=31536000" + wantSecurity := "max-age=63072000; includeSubDomains; preload" // setup context gin.SetMode(gin.TestMode) From 5a7342b0d41be8d64886d744991280fbff4c292e Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 27 May 2022 10:58:20 -0600 Subject: [PATCH 062/298] fix(hook/webhook)!: clean up rename repo code with EventAction and shift defer func (#641) --- api/webhook.go | 90 +++++++++++++++++++++++------ database/postgres/ddl/hook.go | 27 ++++----- database/postgres/hook_list_test.go | 12 ++-- database/postgres/hook_test.go | 43 +++++++------- database/sqlite/ddl/hook.go | 27 ++++----- database/sqlite/hook_test.go | 27 ++++----- go.mod | 2 +- go.sum | 4 +- scm/github/webhook.go | 6 +- scm/github/webhook_test.go | 6 +- 10 files changed, 150 insertions(+), 94 deletions(-) diff --git a/api/webhook.go b/api/webhook.go index 83f14ec37..2822f8871 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -131,16 +131,12 @@ func PostWebhook(c *gin.Context) { h, r, b := webhook.Hook, webhook.Repo, webhook.Build - defer func() { - // send API call to update the webhook - err = database.FromContext(c).UpdateHook(h) - if err != nil { - logrus.Errorf("unable to update webhook %s/%s: %v", r.GetFullName(), h.GetSourceID(), err) - } - }() - - // check if build was parsed from webhook - if b == nil && h.GetEvent() != constants.EventRepositoryRename { + // check if build was parsed from webhook. + // build will be nil on repository events, but + // for renaming, we want to continue. + if b == nil && + h.GetEvent() != constants.EventRepository && + h.GetEventAction() != constants.ActionRenamed { // typically, this should only happen on a webhook // "ping" which gets sent when the webhook is created c.JSON(http.StatusOK, "no build to process") @@ -153,20 +149,23 @@ func PostWebhook(c *gin.Context) { retErr := fmt.Errorf("%s: failed to parse repo from webhook", baseErr) util.HandleError(c, http.StatusBadRequest, retErr) - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - return } - if h.GetEvent() == constants.EventRepositoryRename { - err = renameRepository(h, r, c) + defer func() { + // send API call to update the webhook + err = database.FromContext(c).UpdateHook(h) + if err != nil { + logrus.Errorf("unable to update webhook %s/%s: %v", r.GetFullName(), h.GetSourceID(), err) + } + }() + + if h.GetEvent() == constants.EventRepository { + err = renameRepository(h, r, c, m) if err != nil { util.HandleError(c, http.StatusBadRequest, err) h.SetStatus(constants.StatusFailure) h.SetError(err.Error()) - - return } return @@ -672,7 +671,7 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, // queries the database for the repo that matches that name and org, and updates // that repo to its new name in order to preserve it. It also updates the secrets // associated with that repo. -func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { +func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) error { // get the old name of the repo previousName := r.GetPreviousName() // get the repo from the database that matches the old name @@ -706,8 +705,29 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { return retErr } - // get total number of secrets associated with repository + // update hook object which will be added to DB upon reaching deferred function in PostWebhook + h.SetRepoID(r.GetID()) + + // send API call to capture the last hook for the repo + lastHook, err := database.FromContext(c).GetLastHook(dbR) + if err != nil { + retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return retErr + } + // set the Number field + if lastHook != nil { + h.SetNumber( + lastHook.GetNumber() + 1, + ) + } + + // get total number of secrets associated with repository t, err := database.FromContext(c).GetTypeSecretCount(constants.SecretRepo, r.GetOrg(), previousName, []string{}) if err != nil { return fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) @@ -737,6 +757,38 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context) error { } } + // get total number of builds associated with repository + t, err = database.FromContext(c).GetRepoBuildCount(dbR, nil) + if err != nil { + return fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) + } + + builds := []*library.Build{} + page = 1 + // capture all builds belonging to repo in database + for build := int64(0); build < t; build += 100 { + b, _, err := database.FromContext(c).GetRepoBuildList(dbR, nil, time.Now().Unix(), 0, page, 100) + if err != nil { + return fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err) + } + + builds = append(builds, b...) + + page++ + } + + // update build link to route to proper repo name + for _, build := range builds { + build.SetLink( + fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, dbR.GetFullName(), build.GetNumber()), + ) + + err = database.FromContext(c).UpdateBuild(build) + if err != nil { + return fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err) + } + } + c.JSON(http.StatusOK, r) return nil diff --git a/database/postgres/ddl/hook.go b/database/postgres/ddl/hook.go index 3f6f9333b..e0c67a38e 100644 --- a/database/postgres/ddl/hook.go +++ b/database/postgres/ddl/hook.go @@ -11,19 +11,20 @@ const ( CREATE TABLE IF NOT EXISTS hooks ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id VARCHAR(250), - created INTEGER, - host VARCHAR(250), - event VARCHAR(250), - branch VARCHAR(500), - error VARCHAR(500), - status VARCHAR(250), - link VARCHAR(1000), - webhook_id INTEGER, + id SERIAL PRIMARY KEY, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id VARCHAR(250), + created INTEGER, + host VARCHAR(250), + event VARCHAR(250), + event_action VARCHAR(250), + branch VARCHAR(500), + error VARCHAR(500), + status VARCHAR(250), + link VARCHAR(1000), + webhook_id INTEGER, UNIQUE(repo_id, number) ); ` diff --git a/database/postgres/hook_list_test.go b/database/postgres/hook_list_test.go index 1266c73b9..a48b73cdd 100644 --- a/database/postgres/hook_list_test.go +++ b/database/postgres/hook_list_test.go @@ -49,9 +49,9 @@ func TestPostgres_Client_GetHookList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -129,9 +129,9 @@ func TestPostgres_Client_GetRepoHookList(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) // ensure the mock expects the query _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) diff --git a/database/postgres/hook_test.go b/database/postgres/hook_test.go index 380a32fab..3d7098953 100644 --- a/database/postgres/hook_test.go +++ b/database/postgres/hook_test.go @@ -48,8 +48,8 @@ func TestPostgres_Client_GetHook(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -125,8 +125,8 @@ func TestPostgres_Client_GetLastHook(t *testing.T) { // create expected return in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", 1) + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) // ensure the mock expects the query for test case 1 _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) @@ -192,8 +192,8 @@ func TestPostgres_Client_CreateHook(t *testing.T) { _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "hooks" ("repo_id","build_id","number","source_id","created","host","event","branch","error","status","link","webhook_id","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING "id"`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1, 1). + _mock.ExpectQuery(`INSERT INTO "hooks" ("repo_id","build_id","number","source_id","created","host","event","event_action","branch","error","status","link","webhook_id","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). WillReturnRows(_rows) // setup tests @@ -242,8 +242,8 @@ func TestPostgres_Client_UpdateHook(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "hooks" SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"branch"=$8,"error"=$9,"status"=$10,"link"=$11,"webhook_id"=$12 WHERE "id" = $13`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, 1, 1). + _mock.ExpectExec(`UPDATE "hooks" SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"event_action"=$8,"branch"=$9,"error"=$10,"status"=$11,"link"=$12,"webhook_id"=$13 WHERE "id" = $14`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). WillReturnResult(sqlmock.NewResult(1, 1)) // setup tests @@ -327,18 +327,19 @@ func testHook() *library.Hook { str := "" return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, - WebhookID: &i64, + ID: &i64, + RepoID: &i64, + BuildID: &i64, + Number: &i, + SourceID: &str, + Created: &i64, + Host: &str, + Event: &str, + EventAction: &str, + Branch: &str, + Error: &str, + Status: &str, + Link: &str, + WebhookID: &i64, } } diff --git a/database/sqlite/ddl/hook.go b/database/sqlite/ddl/hook.go index 9d350c2fe..4e320132e 100644 --- a/database/sqlite/ddl/hook.go +++ b/database/sqlite/ddl/hook.go @@ -11,19 +11,20 @@ const ( CREATE TABLE IF NOT EXISTS hooks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id TEXT, - created INTEGER, - host TEXT, - event TEXT, - branch TEXT, - error TEXT, - status TEXT, - link TEXT, - webhook_id INTEGER, + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id TEXT, + created INTEGER, + host TEXT, + event TEXT, + event_action TEXT, + branch TEXT, + error TEXT, + status TEXT, + link TEXT, + webhook_id INTEGER, UNIQUE(repo_id, build_id) ); ` diff --git a/database/sqlite/hook_test.go b/database/sqlite/hook_test.go index 03d27b9ac..a577db4f1 100644 --- a/database/sqlite/hook_test.go +++ b/database/sqlite/hook_test.go @@ -322,18 +322,19 @@ func testHook() *library.Hook { str := "" return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, - WebhookID: &i64, + ID: &i64, + RepoID: &i64, + BuildID: &i64, + Number: &i, + SourceID: &str, + Created: &i64, + Host: &str, + Event: &str, + EventAction: &str, + Branch: &str, + Error: &str, + Status: &str, + Link: &str, + WebhookID: &i64, } } diff --git a/go.mod b/go.mod index 696096d2a..ba762ea50 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.7.7 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.14.0-rc1 + github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.0.0 diff --git a/go.sum b/go.sum index 39b1db29c..715a46853 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.14.0-rc1 h1:zckr7Cywbw97IfYu/F/e1yscIW72HL0VhhNtp1NV5kQ= -github.com/go-vela/types v0.14.0-rc1/go.mod h1:g2C+XdTuq2hzrsEUt+jVLLqmhgogoXryQEok3EK3HkE= +github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 h1:AQoqAPwpVzP23G2sk7OUM7cRFEi1Rl5FIEcshJ6tzTI= +github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74/go.mod h1:g2C+XdTuq2hzrsEUt+jVLLqmhgogoXryQEok3EK3HkE= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 6e063b65a..5b4c42096 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -446,12 +446,10 @@ func (c *client) processRepositoryEvent(h *library.Hook, payload *github.Reposit // if action is renamed, then get the previous name from payload if payload.GetAction() == "renamed" { r.SetPreviousName(payload.GetChanges().GetRepo().GetName().GetFrom()) - // update hook object event type - h.SetEvent(constants.EventRepositoryRename) - } else { - h.SetEvent(constants.EventRepository) } + h.SetEvent(constants.EventRepository) + h.SetEventAction(payload.GetAction()) h.SetBranch(r.GetBranch()) h.SetLink( fmt.Sprintf("https://%s/%s/settings/hooks", h.GetHost(), r.GetFullName()), diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index f82d2d2a1..9d902d6ff 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -960,7 +960,8 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") - wantHook.SetEvent("repositoryRename") + wantHook.SetEvent(constants.EventRepository) + wantHook.SetEventAction(constants.ActionRenamed) wantHook.SetBranch("master") wantHook.SetStatus(constants.StatusSuccess) wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") @@ -1022,7 +1023,8 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { wantHook.SetWebhookID(123456) wantHook.SetCreated(time.Now().UTC().Unix()) wantHook.SetHost("github.com") - wantHook.SetEvent("repository") + wantHook.SetEvent(constants.EventRepository) + wantHook.SetEventAction("publicized") wantHook.SetBranch("master") wantHook.SetStatus(constants.StatusSuccess) wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") From 7512f644c1e6842ac785551a2a57cfcc5a8c8cc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 May 2022 13:58:12 -0500 Subject: [PATCH 063/298] fix(deps): update module github.com/urfave/cli/v2 to v2.8.1 (#643) --- go.mod | 3 ++- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ba762ea50..1c7d603b9 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.12.2 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.8.2 - github.com/urfave/cli/v2 v2.6.0 + github.com/urfave/cli/v2 v2.8.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 gopkg.in/square/go-jose.v2 v2.6.0 @@ -121,6 +121,7 @@ require ( github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/ugorji/go/codec v1.1.11 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect diff --git a/go.sum b/go.sum index 715a46853..244ed32ed 100644 --- a/go.sum +++ b/go.sum @@ -593,8 +593,10 @@ github.com/ugorji/go v1.1.11/go.mod h1:kbRrdMyHY64ADdazOwkrQP9btxt35Z26OJueD3Tq0 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.11 h1:GaQDxjNe1J3vCZvlVaDjUIHIbFuUByFXY7rMqnhB5ck= github.com/ugorji/go/codec v1.1.11/go.mod h1:svMFxxx5FVQJPnJ9vbpAgscNufuiXDyldvzApI86qQo= -github.com/urfave/cli/v2 v2.6.0 h1:yj2Drkflh8X/zUrkWlWlUjZYHyWN7WMmpVxyxXIUyv8= -github.com/urfave/cli/v2 v2.6.0/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= +github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= +github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 0bc21af27bfaa8756b04b00accd0b6fdf49850f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 May 2022 14:05:19 -0500 Subject: [PATCH 064/298] fix(deps): update module github.com/google/go-github/v44 to v44.1.0 (#639) --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 1c7d603b9..9c5bb3225 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 - github.com/google/go-github/v44 v44.0.0 + github.com/google/go-github/v44 v44.1.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.1 github.com/hashicorp/go-cleanhttp v0.5.2 diff --git a/go.sum b/go.sum index 244ed32ed..4705f3827 100644 --- a/go.sum +++ b/go.sum @@ -236,11 +236,10 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v44 v44.0.0 h1:1Lfk2mhM7pTWqwGC6Ft16S3c2LBw8DLcw9TOhYoQ9zE= -github.com/google/go-github/v44 v44.0.0/go.mod h1:CqZYQRxOcb81M+ufZB7duWNS0lFfas/r7cEAKpLBYww= +github.com/google/go-github/v44 v44.1.0 h1:shWPaufgdhr+Ad4eo/pZv9ORTxFpsxPEPEuuXAKIQGA= +github.com/google/go-github/v44 v44.1.0/go.mod h1:iWn00mWcP6PRWHhXm0zuFJ8wbEjE5AGO5D5HXYM4zgw= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From b529e39e0952a95c5122a0aabd4bf48a93e43d56 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 May 2022 14:46:51 -0500 Subject: [PATCH 065/298] fix(deps): update module github.com/hashicorp/vault/api to v1.6.0 (#647) --- go.mod | 10 +++++----- go.sum | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 9c5bb3225..85cbdb7cb 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/hashicorp/vault/api v1.5.0 + github.com/hashicorp/vault/api v1.6.0 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2 @@ -73,14 +73,14 @@ require ( github.com/hashicorp/go-plugin v1.4.3 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.4.1 // indirect + github.com/hashicorp/vault/sdk v0.5.0 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect @@ -107,7 +107,7 @@ require ( github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/go.sum b/go.sum index 4705f3827..e3d7dad2b 100644 --- a/go.sum +++ b/go.sum @@ -304,11 +304,13 @@ github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR3 github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5 h1:MBgwAFPUbfuI0+tmDU/aeM1MARvdbqWmiieXIalKqDE= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= @@ -323,10 +325,10 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.5.0 h1:Bp6yc2bn7CWkOrVIzFT/Qurzx528bdavF3nz590eu28= -github.com/hashicorp/vault/api v1.5.0/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM= -github.com/hashicorp/vault/sdk v0.4.1 h1:3SaHOJY687jY1fnB61PtL0cOkKItphrbLmux7T92HBo= -github.com/hashicorp/vault/sdk v0.4.1/go.mod h1:aZ3fNuL5VNydQk8GcLJ2TV8YCRVvyaakYkhZRoVuhj0= +github.com/hashicorp/vault/api v1.6.0 h1:B8UUYod1y1OoiGHq9GtpiqSnGOUEWHaA26AY8RQEDY4= +github.com/hashicorp/vault/api v1.6.0/go.mod h1:h1K70EO2DgnBaTz5IsL6D5ERsNt5Pce93ueVS2+t0Xc= +github.com/hashicorp/vault/sdk v0.5.0 h1:EED7p0OCU3OY5SAqJwSANofY1YKMytm+jDHDQ2EzGVQ= +github.com/hashicorp/vault/sdk v0.5.0/go.mod h1:UJZHlfwj7qUJG8g22CuxUgkdJouFrBNvBHCyx8XAPdo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -471,8 +473,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= From df86a439a53c5fd750d0dda65f79cfc8d8b32770 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 27 May 2022 20:46:12 +0000 Subject: [PATCH 066/298] fix(db): add source index to builds (#648) --- database/postgres/ddl/build.go | 9 +++++++++ database/postgres/postgres.go | 6 ++++++ database/postgres/postgres_test.go | 2 ++ database/sqlite/ddl/build.go | 9 +++++++++ database/sqlite/sqlite.go | 6 ++++++ 5 files changed, 32 insertions(+) diff --git a/database/postgres/ddl/build.go b/database/postgres/ddl/build.go index fd4d77db7..58eacf15b 100644 --- a/database/postgres/ddl/build.go +++ b/database/postgres/ddl/build.go @@ -72,5 +72,14 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS builds_created ON builds (created); +` + + // CreateBuildSourceIndex represents a query to create an + // index on the builds table for the source column. + CreateBuildSourceIndex = ` +CREATE INDEX CONCURRENTLY +IF NOT EXISTS +builds_source +ON builds (source); ` ) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index c25048f1b..c45b954a2 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -300,6 +300,12 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) } + // create the builds_source index for the builds table + err = c.Postgres.Exec(ddl.CreateBuildSourceIndex).Error + if err != nil { + return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) + } + // create the hooks_repo_id index for the hooks table err = c.Postgres.Exec(ddl.CreateHookRepoIDIndex).Error if err != nil { diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 5188b5c93..fd614af9a 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -87,6 +87,7 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateRepoOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -207,6 +208,7 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateRepoOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/sqlite/ddl/build.go b/database/sqlite/ddl/build.go index db9f5d5cc..e4a713fdd 100644 --- a/database/sqlite/ddl/build.go +++ b/database/sqlite/ddl/build.go @@ -72,5 +72,14 @@ CREATE INDEX IF NOT EXISTS builds_created ON builds (created); +` + + // CreateBuildSourceIndex represents a query to create an + // index on the builds table for the source column. + CreateBuildSourceIndex = ` +CREATE INDEX +IF NOT EXISTS +builds_source +ON builds (source); ` ) diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 5702c76cd..61935ff56 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -296,6 +296,12 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) } + // create the builds_source index for the builds table + err = c.Sqlite.Exec(ddl.CreateBuildSourceIndex).Error + if err != nil { + return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) + } + // create the hooks_repo_id index for the hooks table err = c.Sqlite.Exec(ddl.CreateHookRepoIDIndex).Error if err != nil { From 1f691b863d3724781757e84d550389c3b27ffba4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 31 May 2022 11:07:38 -0500 Subject: [PATCH 067/298] fix(deps): update module github.com/gin-gonic/gin to v1.8.0 (#649) --- go.mod | 19 ++++++++++--------- go.sum | 53 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 85cbdb7cb..99b983506 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/aws/aws-sdk-go v1.44.17 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 - github.com/gin-gonic/gin v1.7.7 + github.com/gin-gonic/gin v1.8.0 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 @@ -57,9 +57,10 @@ require ( github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.0 // indirect - github.com/go-playground/locales v0.13.0 // indirect - github.com/go-playground/universal-translator v0.17.0 // indirect - github.com/go-playground/validator/v10 v10.4.1 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.10.0 // indirect + github.com/goccy/go-json v0.9.7 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -96,11 +97,10 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kr/pretty v0.3.0 // indirect - github.com/leodido/go-urn v1.2.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.5 // indirect github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/microcosm-cc/bluemonday v1.0.18 // indirect @@ -112,6 +112,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -120,7 +121,7 @@ require ( github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.3.1 // indirect - github.com/ugorji/go/codec v1.1.11 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect @@ -132,7 +133,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect google.golang.org/grpc v1.41.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.60.1 // indirect ) diff --git a/go.sum b/go.sum index e3d7dad2b..eda43bcdd 100644 --- a/go.sum +++ b/go.sum @@ -146,8 +146,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= -github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/gin-gonic/gin v1.8.0 h1:4WFH5yycBMA3za5Hnl425yd9ymdw1XPm4666oab+hv4= +github.com/gin-gonic/gin v1.8.0/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -169,12 +169,12 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -183,6 +183,8 @@ github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 h1:AQoqAPwpVzP23G2sk7OUM7cRFEi1Rl5FIEcshJ6tzTI= github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74/go.mod h1:g2C+XdTuq2hzrsEUt+jVLLqmhgogoXryQEok3EK3HkE= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -430,8 +432,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -453,8 +455,9 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -490,7 +493,6 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -513,8 +515,11 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -550,8 +555,9 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -585,15 +591,15 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.1.11 h1:O5AKWOf+CnfWi6L1WtdBtZpA+YNjoQd2YfbtkowsMrs= -github.com/ugorji/go v1.1.11/go.mod h1:kbRrdMyHY64ADdazOwkrQP9btxt35Z26OJueD3Tq0/4= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.1.11 h1:GaQDxjNe1J3vCZvlVaDjUIHIbFuUByFXY7rMqnhB5ck= -github.com/ugorji/go/codec v1.1.11/go.mod h1:svMFxxx5FVQJPnJ9vbpAgscNufuiXDyldvzApI86qQo= +github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= @@ -808,6 +814,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= @@ -993,14 +1000,16 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= From 05f8b42c4303b7bad285c9cab5391d459a4af673 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 10:46:40 -0500 Subject: [PATCH 068/298] fix(deps): update deps (patch) (#652) Co-authored-by: Renovate Bot --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 99b983506..64878edb0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.21.0 - github.com/aws/aws-sdk-go v1.44.17 + github.com/aws/aws-sdk-go v1.44.25 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.0 @@ -34,10 +34,10 @@ require ( golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.5 + gorm.io/driver/postgres v1.3.7 gorm.io/driver/sqlite v1.3.2 gorm.io/gorm v1.23.5 - k8s.io/apimachinery v0.24.0 + k8s.io/apimachinery v0.24.1 ) require ( @@ -86,13 +86,13 @@ require ( github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.12.0 // indirect + github.com/jackc/pgconn v1.12.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/pgtype v1.11.0 // indirect - github.com/jackc/pgx/v4 v4.16.0 // indirect + github.com/jackc/pgx/v4 v4.16.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum index eda43bcdd..d53e5bba5 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.17 h1:of8MirZuVDat3BJgRbSwDO/GM/cgXh5Znf2tyEAv/vE= -github.com/aws/aws-sdk-go v1.44.17/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.25 h1:cJZ4gtEpWAD/StO9GGOAyv6AaAoZ9OJUhu96gF9qaio= +github.com/aws/aws-sdk-go v1.44.25/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -352,8 +352,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.0 h1:/RvQ24k3TnNdfBSW0ou9EOi5jx2cX7zfE8n2nLKuiP0= -github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= +github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -384,8 +384,8 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.0 h1:4k1tROTJctHotannFYzu77dY3bgtMRymQP7tXQjqpPk= -github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= +github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= +github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -1034,8 +1034,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.5 h1:oVLmefGqBTlgeEVG6LKnH6krOlo4TZ3Q/jIK21KUMlw= -gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= +gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= +gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg= gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= @@ -1048,8 +1048,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ= -k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I= +k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= From a7d8962b7f3b552d53166dbbd66ee59753587911 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 1 Jun 2022 12:16:12 -0500 Subject: [PATCH 069/298] fix: lookup of pipelines for older builds (#650) --- router/middleware/pipeline/pipeline.go | 38 ++++++++-- router/middleware/pipeline/pipeline_test.go | 77 +++++++++++++++++++- router/middleware/pipeline/testdata/yml.json | 18 +++++ 3 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 router/middleware/pipeline/testdata/yml.json diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go index c0b5e2790..ecf08767b 100644 --- a/router/middleware/pipeline/pipeline.go +++ b/router/middleware/pipeline/pipeline.go @@ -9,11 +9,14 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" "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/scm" "github.com/go-vela/server/util" + "github.com/go-vela/types" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) @@ -47,6 +50,8 @@ func Establish() gin.HandlerFunc { return } + entry := fmt.Sprintf("%s/%s", r.GetFullName(), p) + // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields @@ -55,15 +60,34 @@ func Establish() gin.HandlerFunc { "pipeline": p, "repo": r.GetName(), "user": u.GetName(), - }).Debugf("reading pipeline %s/%s", r.GetFullName(), p) + }).Debugf("reading pipeline %s", entry) pipeline, err := database.FromContext(c).GetPipelineForRepo(p, r) - if err != nil { - retErr := fmt.Errorf("unable to read pipeline %s/%s: %w", r.GetFullName(), p, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return + if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) + // send API call to capture the pipeline configuration file + config, err := scm.FromContext(c).ConfigBackoff(u, r, p) + if err != nil { + retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // parse and compile the pipeline configuration file + _, pipeline, err = compiler.FromContext(c). + Duplicate(). + WithMetadata(c.MustGet("metadata").(*types.Metadata)). + WithRepo(r). + WithUser(u). + Compile(config) + if err != nil { + retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } } ToContext(c, pipeline) diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index 1025cdb30..e8fff08ff 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -5,17 +5,28 @@ package pipeline import ( + "flag" + "fmt" "net/http" "net/http/httptest" "reflect" "testing" + "time" "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/compiler/native" "github.com/go-vela/server/database" "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/scm" + "github.com/go-vela/server/scm/github" + "github.com/go-vela/types" "github.com/go-vela/types/library" + "github.com/urfave/cli/v2" ) func TestPipeline_Retrieve(t *testing.T) { @@ -197,6 +208,8 @@ func TestPipeline_Establish_NoPipelineParameter(t *testing.T) { func TestPipeline_Establish_NoPipeline(t *testing.T) { // setup types + secret := "superSecret" + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -206,16 +219,55 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(true) + + m := &types.Metadata{ + Database: &types.Database{ + Driver: "foo", + Host: "foo", + }, + Queue: &types.Queue{ + Channel: "foo", + Driver: "foo", + Host: "foo", + }, + Source: &types.Source{ + Driver: "foo", + Host: "foo", + }, + Vela: &types.Vela{ + Address: "foo", + WebAddress: "foo", + }, + } + + tok, err := token.CreateAccessToken(u, time.Minute*15) + if err != nil { + t.Errorf("unable to create access token: %v", err) + } + + comp, err := native.New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) + if err != nil { + t.Errorf("unable to create compiler: %v", err) + } + // setup database db, _ := sqlite.NewTest() defer func() { db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from users;") _sql, _ := db.Sqlite.DB() _sql.Close() }() _ = db.CreateRepo(r) + _ = db.CreateUser(u) // setup context gin.SetMode(gin.TestMode) @@ -223,11 +275,30 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar/148afb5bdc41ad69bf22588491333f7cf71135163", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) - // setup mock server + // setup github mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/yml.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup client + client, _ := github.NewTest(s.URL) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("metadata", m) }) + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { compiler.WithGinContext(c, comp) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) engine.Use(org.Establish()) engine.Use(repo.Establish()) + engine.Use(user.Establish()) engine.Use(Establish()) engine.GET("/pipelines/:org/:repo/:pipeline", func(c *gin.Context) { c.Status(http.StatusOK) @@ -236,7 +307,7 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { // run test engine.ServeHTTP(context.Writer, context.Request) - if resp.Code != http.StatusNotFound { - t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusNotFound) + if resp.Code != http.StatusOK { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusOK) } } diff --git a/router/middleware/pipeline/testdata/yml.json b/router/middleware/pipeline/testdata/yml.json new file mode 100644 index 000000000..458ecaa44 --- /dev/null +++ b/router/middleware/pipeline/testdata/yml.json @@ -0,0 +1,18 @@ +{ + "type": "file", + "encoding": "base64", + "size": 5362, + "name": ".vela.yml", + "path": ".vela.yml", + "content": "LS0tCnZlcnNpb246ICIxIgoKbWV0YWRhdGE6CiAgb3M6IGxpbnV4CgpzdGVwczoKICAtIG5hbWU6IGJ1aWxkCiAgICBpbWFnZTogb3BlbmpkazpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGVudmlyb25tZW50OgogICAgICBHUkFETEVfVVNFUl9IT01FOiAuZ3JhZGxlCiAgICAgIEdSQURMRV9PUFRTOiAtRG9yZy5ncmFkbGUuZGFlbW9uPWZhbHNlIC1Eb3JnLmdyYWRsZS53b3JrZXJzLm1heD0xIC1Eb3JnLmdyYWRsZS5wYXJhbGxlbD1mYWxzZQogICAgY29tbWFuZHM6CiAgICAgIC0gLi9ncmFkbGV3IGJ1aWxkIGRpc3RUYXIK", + "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", + "url": "https://api.github.com/repos/octokit/octokit.rb/contents/.vela.yml", + "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "html_url": "https://github.com/octokit/octokit.rb/blob/master/.vela.yml", + "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/.vela.yml", + "_links": { + "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "self": "https://api.github.com/repos/octokit/octokit.rb/contents/.vela.yml", + "html": "https://github.com/octokit/octokit.rb/blob/master/.vela.yml" + } +} \ No newline at end of file From b61a977b0160ba8113a3f075a23633eb201ecb0f Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 1 Jun 2022 13:40:51 -0600 Subject: [PATCH 070/298] fix(api/hook): handle 202 error for webhook redelivery (#654) --- scm/github/webhook.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 5b4c42096..bfab64893 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -7,6 +7,7 @@ package github import ( "context" "encoding/json" + "errors" "fmt" "net/http" "strconv" @@ -105,6 +106,13 @@ func (c *client) RedeliverWebhook(ctx context.Context, u *library.User, r *libra _, _, err = client.Repositories.RedeliverHookDelivery(ctx, r.GetOrg(), r.GetName(), h.GetWebhookID(), deliveryID) if err != nil { + var acceptedError *github.AcceptedError + // Persist if the status received is a 202 Accepted. This + // means the job was added to the queue for GitHub. + if errors.As(err, &acceptedError) { + return nil + } + return err } From 0ad43b44050ed5ea88a20512dcbb874aaf5e219d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 03:40:22 +0000 Subject: [PATCH 071/298] fix(deps): update golang.org/x/oauth2 digest to 622c5d5 (#651) Co-authored-by: Renovate Bot --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 64878edb0..e044bef46 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.8.2 github.com/urfave/cli/v2 v2.8.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd - golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 + golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.7 diff --git a/go.sum b/go.sum index d53e5bba5..841af789a 100644 --- a/go.sum +++ b/go.sum @@ -741,8 +741,8 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw= +golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 953c670152293958a96917bb37faf5f2107a60da Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 2 Jun 2022 14:42:55 -0600 Subject: [PATCH 072/298] fix(api/repo): fix path for GetOrgRepos in swagger spec (#655) --- api/repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/repo.go b/api/repo.go index b0347a489..889bf0d50 100644 --- a/api/repo.go +++ b/api/repo.go @@ -393,7 +393,7 @@ func GetRepos(c *gin.Context) { c.JSON(http.StatusOK, r) } -// swagger:operation GET /api/v1/{org} repos GetOrgRepos +// swagger:operation GET /api/v1/repos/{org} repos GetOrgRepos // // Get all repos for the provided org in the configured backend // From 62ddf45fe50659438d1464f945278f35f73daec9 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 3 Jun 2022 15:45:52 +0000 Subject: [PATCH 073/298] chore(release): v0.14.0-rc2 (#656) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e044bef46..34b5ca3b1 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.0 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 + github.com/go-vela/types v0.14.0-rc2 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.1.0 @@ -98,7 +98,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.5 // indirect + github.com/lib/pq v1.10.6 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect diff --git a/go.sum b/go.sum index 841af789a..98d4f0ae6 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74 h1:AQoqAPwpVzP23G2sk7OUM7cRFEi1Rl5FIEcshJ6tzTI= -github.com/go-vela/types v0.14.0-rc1.0.20220518151947-0cf0e4753e74/go.mod h1:g2C+XdTuq2hzrsEUt+jVLLqmhgogoXryQEok3EK3HkE= +github.com/go-vela/types v0.14.0-rc2 h1:LrThnunJJHAyPyL8gc8CNxquIKQ8AjtVntSD0JHdRzY= +github.com/go-vela/types v0.14.0-rc2/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= @@ -438,8 +438,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= -github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= From cd5cfd8567ab6f19ac888c3caa61756ec6a28f06 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 17:49:52 -0500 Subject: [PATCH 074/298] fix(deps): update deps (patch) (#657) --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 34b5ca3b1..05b241fd3 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.21.0 - github.com/aws/aws-sdk-go v1.44.25 + github.com/aws/aws-sdk-go v1.44.30 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 - github.com/gin-gonic/gin v1.8.0 + github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.14.0-rc2 @@ -35,7 +35,7 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.7 - gorm.io/driver/sqlite v1.3.2 + gorm.io/driver/sqlite v1.3.4 gorm.io/gorm v1.23.5 k8s.io/apimachinery v0.24.1 ) diff --git a/go.sum b/go.sum index 98d4f0ae6..89379d4ea 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.25 h1:cJZ4gtEpWAD/StO9GGOAyv6AaAoZ9OJUhu96gF9qaio= -github.com/aws/aws-sdk-go v1.44.25/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.30 h1:w7sTp6jFWRaZCDg08fUx8X4IOU4sgbCR+e+1qSmf+bc= +github.com/aws/aws-sdk-go v1.44.30/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -146,8 +146,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.0 h1:4WFH5yycBMA3za5Hnl425yd9ymdw1XPm4666oab+hv4= -github.com/gin-gonic/gin v1.8.0/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -1036,8 +1036,8 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= -gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg= -gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= +gorm.io/driver/sqlite v1.3.4 h1:NnFOPVfzi4CPsJPH4wXr6rMkPb4ElHEqKMvrsx9c9Fk= +gorm.io/driver/sqlite v1.3.4/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= From 8c74c479df68abb79cc8a3d7ed86f037483c09e4 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 15 Jun 2022 13:54:35 -0500 Subject: [PATCH 075/298] fix: webhook race condition on pipeline creation (#659) --- api/webhook.go | 81 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/api/webhook.go b/api/webhook.go index 2822f8871..502151490 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -156,7 +156,7 @@ func PostWebhook(c *gin.Context) { // send API call to update the webhook err = database.FromContext(c).UpdateHook(h) if err != nil { - logrus.Errorf("unable to update webhook %s/%s: %v", r.GetFullName(), h.GetSourceID(), err) + logrus.Errorf("unable to update webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err) } }() @@ -376,31 +376,17 @@ func PostWebhook(c *gin.Context) { p *pipeline.Build // variable to store pipeline configuration pipeline *library.Pipeline - // variable to control number of times to retry compiling pipeline + // variable to control number of times to retry processing pipeline retryLimit = 3 // variable to store the pipeline type for the repository pipelineType = r.GetPipelineType() ) - // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) - if err != nil { // assume the pipeline doesn't exist in the database yet - // send API call to capture the pipeline configuration file - config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("%s: failed to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) - util.HandleError(c, http.StatusNotFound, retErr) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return - } - } else { - config = pipeline.GetData() - } - - // iterate through with a retryLimit + // implement a loop to process asynchronous operations with a retry limit + // + // Some operations taken during the webhook workflow can lead to race conditions + // failing to successfully process the request. This logic ensures we attempt our + // best efforts to handle these cases gracefully. for i := 0; i < retryLimit; i++ { // check if we're on the first iteration of the loop if i > 0 { @@ -408,10 +394,46 @@ func PostWebhook(c *gin.Context) { time.Sleep(time.Duration(i) * time.Second) } + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("%s: unable to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) + + // check if the retry limit has been exceeded + if i < retryLimit { + logrus.WithError(retErr).Warning("retrying") + + // continue to the next iteration of the loop + continue + } + + util.HandleError(c, http.StatusNotFound, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + } else { + config = pipeline.GetData() + } + // send API call to capture repo for the counter r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) if err != nil { - retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: unable to get repo %s: %w", baseErr, r.GetFullName(), err) + + // check if the retry limit has been exceeded + if i < retryLimit { + logrus.WithError(retErr).Warning("retrying") + + // continue to the next iteration of the loop + continue + } + util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -513,6 +535,15 @@ func PostWebhook(c *gin.Context) { err = database.FromContext(c).CreatePipeline(pipeline) if err != nil { retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, r.GetFullName(), err) + + // check if the retry limit has been exceeded + if i < retryLimit { + logrus.WithError(retErr).Warning("retrying") + + // continue to the next iteration of the loop + continue + } + util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -540,11 +571,12 @@ func PostWebhook(c *gin.Context) { // create the objects from the pipeline in the database err = planBuild(database.FromContext(c), p, b, r) if err != nil { - // log the error for traceability - logrus.Error(err.Error()) + retErr := fmt.Errorf("%s: %w", baseErr, err) // check if the retry limit has been exceeded if i < retryLimit { + logrus.WithError(retErr).Warning("retrying") + // reset fields set by cleanBuild for retry b.SetError("") b.SetStatus(constants.StatusPending) @@ -554,7 +586,6 @@ func PostWebhook(c *gin.Context) { continue } - retErr := fmt.Errorf("%s: %w", baseErr, err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) From 3d4fef230db633f8cc9bb22946e411ab7dfda344 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Jun 2022 14:39:44 -0500 Subject: [PATCH 076/298] fix(deps): update module github.com/hashicorp/vault/api to v1.7.2 (#658) --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 05b241fd3..057df12ff 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/hashicorp/vault/api v1.6.0 + github.com/hashicorp/vault/api v1.7.2 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2 @@ -74,14 +74,14 @@ require ( github.com/hashicorp/go-plugin v1.4.3 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.5.0 // indirect + github.com/hashicorp/vault/sdk v0.5.1 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect diff --git a/go.sum b/go.sum index 89379d4ea..4657cc820 100644 --- a/go.sum +++ b/go.sum @@ -307,8 +307,8 @@ github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PU github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5 h1:MBgwAFPUbfuI0+tmDU/aeM1MARvdbqWmiieXIalKqDE= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.5/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= @@ -327,10 +327,10 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.6.0 h1:B8UUYod1y1OoiGHq9GtpiqSnGOUEWHaA26AY8RQEDY4= -github.com/hashicorp/vault/api v1.6.0/go.mod h1:h1K70EO2DgnBaTz5IsL6D5ERsNt5Pce93ueVS2+t0Xc= -github.com/hashicorp/vault/sdk v0.5.0 h1:EED7p0OCU3OY5SAqJwSANofY1YKMytm+jDHDQ2EzGVQ= -github.com/hashicorp/vault/sdk v0.5.0/go.mod h1:UJZHlfwj7qUJG8g22CuxUgkdJouFrBNvBHCyx8XAPdo= +github.com/hashicorp/vault/api v1.7.2 h1:kawHE7s/4xwrdKbkmwQi0wYaIeUhk5ueek7ljuezCVQ= +github.com/hashicorp/vault/api v1.7.2/go.mod h1:xbfA+1AvxFseDzxxdWaL0uO99n1+tndus4GCrtouy0M= +github.com/hashicorp/vault/sdk v0.5.1 h1:zly/TmNgOXCGgWIRA8GojyXzG817POtVh3uzIwzZx+8= +github.com/hashicorp/vault/sdk v0.5.1/go.mod h1:DoGraE9kKGNcVgPmTuX357Fm6WAx1Okvde8Vp3dPDoU= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= From e56417b8f1b829711a65143cf9704e80bd1e73c4 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Wed, 15 Jun 2022 14:51:27 -0500 Subject: [PATCH 077/298] chore(release): v0.14.0-rc3 (#660) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 057df12ff..995125419 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.14.0-rc2 + github.com/go-vela/types v0.14.0-rc3 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 4657cc820..1db0bd8a4 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.14.0-rc2 h1:LrThnunJJHAyPyL8gc8CNxquIKQ8AjtVntSD0JHdRzY= -github.com/go-vela/types v0.14.0-rc2/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= +github.com/go-vela/types v0.14.0-rc3 h1:qvVgyOB/YjR/DEZE++ZYb/yQ2AhbtDuKY/i8SI7ORto= +github.com/go-vela/types v0.14.0-rc3/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From d6317bfbda882c94d03f0623d43594d9849fb655 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 09:44:09 -0500 Subject: [PATCH 078/298] fix(deps): update deps (patch) (#662) --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 995125419..806cb6c81 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.21.0 - github.com/aws/aws-sdk-go v1.44.30 + github.com/aws/aws-sdk-go v1.44.38 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -36,8 +36,8 @@ require ( gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.7 gorm.io/driver/sqlite v1.3.4 - gorm.io/gorm v1.23.5 - k8s.io/apimachinery v0.24.1 + gorm.io/gorm v1.23.6 + k8s.io/apimachinery v0.24.2 ) require ( diff --git a/go.sum b/go.sum index 1db0bd8a4..549d8327b 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.30 h1:w7sTp6jFWRaZCDg08fUx8X4IOU4sgbCR+e+1qSmf+bc= -github.com/aws/aws-sdk-go v1.44.30/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.38 h1:Mjsc6XXoAA1QHDqDZQ7vOWd+fUmM29coG+AzkSWmRxI= +github.com/aws/aws-sdk-go v1.44.38/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -1039,8 +1039,8 @@ gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigB gorm.io/driver/sqlite v1.3.4 h1:NnFOPVfzi4CPsJPH4wXr6rMkPb4ElHEqKMvrsx9c9Fk= gorm.io/driver/sqlite v1.3.4/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= -gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.6 h1:KFLdNgri4ExFFGTRGGFWON2P1ZN28+9SJRN8voOoYe0= +gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1048,8 +1048,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I= -k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= +k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= From 22fc514afcdae11ef574741972c4150e5c9f7457 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Wed, 22 Jun 2022 10:07:42 -0600 Subject: [PATCH 079/298] fix: check for nil source repos (#661) --- scm/github/repo.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scm/github/repo.go b/scm/github/repo.go index 40a6c2bd4..f841f055b 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -346,6 +346,12 @@ func (c *client) ListUserRepos(u *library.User) ([]*library.Repo, error) { // iterate through each repo for the user for _, repo := range r { + // skip if the repo is void + // fixes an issue with GitHub replication being out of sync + if repo == nil { + continue + } + // skip if the repo is archived or disabled if repo.GetArchived() || repo.GetDisabled() { continue From 7dbbc8621cde0b0c70001009a2ad55a461705779 Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Wed, 22 Jun 2022 11:14:19 -0500 Subject: [PATCH 080/298] chore(release): dependency updates for v0.14.0 (#664) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 806cb6c81..9935cdf40 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.14.0-rc3 + github.com/go-vela/types v0.14.0 github.com/golang-jwt/jwt/v4 v4.4.1 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 549d8327b..fb4312ac9 100644 --- a/go.sum +++ b/go.sum @@ -181,8 +181,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-vela/types v0.14.0-rc3 h1:qvVgyOB/YjR/DEZE++ZYb/yQ2AhbtDuKY/i8SI7ORto= -github.com/go-vela/types v0.14.0-rc3/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= +github.com/go-vela/types v0.14.0 h1:m75BdRfQm9PC4l/oHSgeplt8mqgau3JmqD3DN+KdePk= +github.com/go-vela/types v0.14.0/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 46bd5708f3ab701f35cf4098fd7c9b693ecf4540 Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Fri, 24 Jun 2022 11:48:21 -0500 Subject: [PATCH 081/298] refactor: update substitute tests to use table syntax (#653) --- compiler/native/substitute_test.go | 323 ++++++++++++++++++----------- 1 file changed, 198 insertions(+), 125 deletions(-) diff --git a/compiler/native/substitute_test.go b/compiler/native/substitute_test.go index feff0cf4f..da27378ac 100644 --- a/compiler/native/substitute_test.go +++ b/compiler/native/substitute_test.go @@ -6,62 +6,175 @@ package native import ( "flag" - "reflect" "testing" - "github.com/go-vela/types/yaml" - "github.com/urfave/cli/v2" + + "github.com/go-vela/types/yaml" + "github.com/google/go-cmp/cmp" ) -func TestNative_SubstituteStages(t *testing.T) { +func Test_client_SubstituteStages(t *testing.T) { + type args struct { + stages yaml.StageSlice + } + // setup types set := flag.NewFlagSet("test", 0) c := cli.NewContext(nil, set, nil) - s := yaml.StageSlice{ + tests := []struct { + name string + args args + want yaml.StageSlice + wantErr bool + }{ { - Name: "simple", - Steps: yaml.StepSlice{ - { - Commands: []string{"echo ${FOO}", "echo $${BAR}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "simple", - Pull: "always", + name: "normal", + args: args{ + stages: yaml.StageSlice{ + { + Name: "simple", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo ${FOO}", "echo $${BAR}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "simple", + Pull: "always", + }, + }, + }, + { + Name: "advanced", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo ${COMPLEX}"}, + Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, + Image: "alpine:latest", + Name: "advanced", + Pull: "always", + }, + }, + }, + { + Name: "not_found", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo $${NOT_FOUND}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "not_found", + Pull: "always", + }, + }, + }, }, }, - }, - { - Name: "advanced", - Steps: yaml.StepSlice{ + want: yaml.StageSlice{ { - Commands: []string{"echo ${COMPLEX}"}, - Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, - Image: "alpine:latest", - Name: "advanced", - Pull: "always", + Name: "simple", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo baz", "echo ${BAR}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "simple", + Pull: "always", + }, + }, }, - }, - }, - { - Name: "not_found", - Steps: yaml.StepSlice{ { - Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo $${NOT_FOUND}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "not_found", - Pull: "always", + Name: "advanced", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo \"{\\\"hello\\\":\\n \\\"world\\\"}\""}, + Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, + Image: "alpine:latest", + Name: "advanced", + Pull: "always", + }, + }, + }, + { + Name: "not_found", + Steps: yaml.StepSlice{ + { + Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo ${NOT_FOUND}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "not_found", + Pull: "always", + }, + }, }, }, + wantErr: false, }, } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } + + got, err := compiler.SubstituteStages(tt.args.stages) + if (err != nil) != tt.wantErr { + t.Errorf("SubstituteStages() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("SubstituteStages() mismatch (-want +got):\n%s", diff) + } + }) + } +} - want := yaml.StageSlice{ +func Test_client_SubstituteSteps(t *testing.T) { + type args struct { + steps yaml.StepSlice + } + + // setup types + set := flag.NewFlagSet("test", 0) + c := cli.NewContext(nil, set, nil) + + tests := []struct { + name string + args args + want yaml.StepSlice + wantErr bool + }{ { - Name: "simple", - Steps: yaml.StepSlice{ + name: "steps", + args: args{ + steps: yaml.StepSlice{ + { + Commands: []string{"echo ${FOO}", "echo $${BAR}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "simple", + Pull: "always", + }, + { + Commands: []string{"echo ${COMPLEX}"}, + Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, + Image: "alpine:latest", + Name: "advanced", + Pull: "always", + }, + { + Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo $${NOT_FOUND}"}, + Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, + Image: "alpine:latest", + Name: "not_found", + Pull: "always", + }, + }, + }, + want: yaml.StepSlice{ { Commands: []string{"echo baz", "echo ${BAR}"}, Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, @@ -69,11 +182,6 @@ func TestNative_SubstituteStages(t *testing.T) { Name: "simple", Pull: "always", }, - }, - }, - { - Name: "advanced", - Steps: yaml.StepSlice{ { Commands: []string{"echo \"{\\\"hello\\\":\\n \\\"world\\\"}\""}, Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, @@ -81,11 +189,6 @@ func TestNative_SubstituteStages(t *testing.T) { Name: "advanced", Pull: "always", }, - }, - }, - { - Name: "not_found", - Steps: yaml.StepSlice{ { Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo ${NOT_FOUND}"}, Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, @@ -94,91 +197,61 @@ func TestNative_SubstituteStages(t *testing.T) { Pull: "always", }, }, + wantErr: false, }, - } - - // run test - compiler, err := New(c) - if err != nil { - t.Errorf("Creating compiler returned err: %v", err) - } - - got, err := compiler.SubstituteStages(s) - - if err != nil { - t.Errorf("SubstituteStages returned err: %v", err) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("SubstituteStages is %v, want %v", got, want) - } -} - -func TestNative_SubstituteSteps(t *testing.T) { - // setup types - set := flag.NewFlagSet("test", 0) - c := cli.NewContext(nil, set, nil) - - p := yaml.StepSlice{ { - Commands: []string{"echo ${FOO}", "echo $${BAR}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "simple", - Pull: "always", - }, - { - Commands: []string{"echo ${COMPLEX}"}, - Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, - Image: "alpine:latest", - Name: "advanced", - Pull: "always", - }, - { - Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo $${NOT_FOUND}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "not_found", - Pull: "always", - }, - } - - want := yaml.StepSlice{ - { - Commands: []string{"echo baz", "echo ${BAR}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "simple", - Pull: "always", - }, - { - Commands: []string{"echo \"{\\\"hello\\\":\\n \\\"world\\\"}\""}, - Environment: map[string]string{"COMPLEX": "{\"hello\":\n \"world\"}"}, - Image: "alpine:latest", - Name: "advanced", - Pull: "always", - }, - { - Commands: []string{"echo $NOT_FOUND", "echo ${NOT_FOUND}", "echo ${NOT_FOUND}"}, - Environment: map[string]string{"FOO": "baz", "BAR": "baz"}, - Image: "alpine:latest", - Name: "not_found", - Pull: "always", + name: "template", + args: args{ + steps: yaml.StepSlice{ + { + Name: "sample", + Template: yaml.StepTemplate{ + Name: "go", + Variables: map[string]interface{}{ + "build_author": "${BUILD_AUTHOR}", + "unknown": "${DEPLOYMENT_PARAMETER_API_IMAGE}", + }, + }, + Environment: map[string]string{ + "BUILD_AUTHOR": "testauthor", + }, + }, + }, + }, + want: yaml.StepSlice{ + { + Name: "sample", + Template: yaml.StepTemplate{ + Name: "go", + Variables: map[string]interface{}{ + "build_author": "testauthor", + "unknown": "${DEPLOYMENT_PARAMETER_API_IMAGE}", + }, + }, + Environment: map[string]string{ + "BUILD_AUTHOR": "testauthor", + }, + }, + }, + wantErr: false, }, } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } - // run test - compiler, err := New(c) - if err != nil { - t.Errorf("Creating compiler returned err: %v", err) - } - - got, err := compiler.SubstituteSteps(p) - if err != nil { - t.Errorf("SubstituteSteps returned err: %v", err) - } + got, err := compiler.SubstituteSteps(tt.args.steps) + if (err != nil) != tt.wantErr { + t.Errorf("SubstituteSteps() error = %v, wantErr %v", err, tt.wantErr) + return + } - if !reflect.DeepEqual(got, want) { - t.Errorf("SubstituteSteps is %v, want %v", got, want) + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("SubstituteSteps() mismatch (-want +got):\n%s", diff) + } + }) } } From a831efd32dccfb2b5e64cc5875043017aa9b918c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Jul 2022 08:54:43 -0500 Subject: [PATCH 082/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.22.0 (#666) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9935cdf40..d32f5ed99 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.21.0 + github.com/alicebob/miniredis/v2 v2.22.0 github.com/aws/aws-sdk-go v1.44.38 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 diff --git a/go.sum b/go.sum index fb4312ac9..69081d4de 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.21.0 h1:CdmwIlKUWFBDS+4464GtQiQ0R1vpzOgu4Vnd74rBL7M= -github.com/alicebob/miniredis/v2 v2.21.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= +github.com/alicebob/miniredis/v2 v2.22.0 h1:lIHHiSkEyS1MkKHCHzN+0mWrA4YdbGdimE5iZ2sHSzo= +github.com/alicebob/miniredis/v2 v2.22.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= From d475046e188446d3960c97890da9baae8b2027b7 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 15 Jul 2022 13:59:20 -0500 Subject: [PATCH 083/298] fix(webhook): avoid panics (#671) --- api/build.go | 17 +++++++++++++++- api/webhook.go | 53 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/api/build.go b/api/build.go index 3f3d290ec..c508d2bef 100644 --- a/api/build.go +++ b/api/build.go @@ -1455,21 +1455,36 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { // planBuild is a helper function to plan the build for // execution. This creates all resources, like steps // and services, for the build in the configured backend. +// TODO: +// - return build and error func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) // send API call to create the build + // TODO: return created build and error instead of just error err := database.CreateBuild(b) if err != nil { // clean up the objects from the pipeline in the database + // TODO: + // - return build in CreateBuild + // - even if it was created, we need to get the new build id + // otherwise it will be 0, which attempts to INSERT instead + // of UPDATE-ing the existing build - which results in + // a constraint error (repo_id, number) + // - do we want to update the build or just delete it? cleanBuild(database, b, nil, nil) return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) } // send API call to capture the created build - b, _ = database.GetBuild(b.GetNumber(), r) + // TODO: this can be dropped once we return + // the created build above + b, err = database.GetBuild(b.GetNumber(), r) + if err != nil { + return fmt.Errorf("unable to get new build for %s: %w", r.GetFullName(), err) + } // plan all services for the build services, err := planServices(database, p, b) diff --git a/api/webhook.go b/api/webhook.go index 502151490..7376e754f 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -402,14 +402,6 @@ func PostWebhook(c *gin.Context) { if err != nil { retErr := fmt.Errorf("%s: unable to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) - // check if the retry limit has been exceeded - if i < retryLimit { - logrus.WithError(retErr).Warning("retrying") - - // continue to the next iteration of the loop - continue - } - util.HandleError(c, http.StatusNotFound, retErr) h.SetStatus(constants.StatusFailure) @@ -427,8 +419,8 @@ func PostWebhook(c *gin.Context) { retErr := fmt.Errorf("%s: unable to get repo %s: %w", baseErr, r.GetFullName(), err) // check if the retry limit has been exceeded - if i < retryLimit { - logrus.WithError(retErr).Warning("retrying") + if i < retryLimit-1 { + logrus.WithError(retErr).Warningf("retrying #%d", i+1) // continue to the next iteration of the loop continue @@ -499,6 +491,7 @@ func PostWebhook(c *gin.Context) { return } + // reset the pipeline type for the repo // // The pipeline type for a repo can change at any time which can break compiling @@ -537,8 +530,8 @@ func PostWebhook(c *gin.Context) { retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, r.GetFullName(), err) // check if the retry limit has been exceeded - if i < retryLimit { - logrus.WithError(retErr).Warning("retrying") + if i < retryLimit-1 { + logrus.WithError(retErr).Warningf("retrying #%d", i+1) // continue to the next iteration of the loop continue @@ -569,13 +562,19 @@ func PostWebhook(c *gin.Context) { b.SetPipelineID(pipeline.GetID()) // create the objects from the pipeline in the database + // TODO: + // - if a build gets created and something else fails midway, + // the next loop will attempt to create the same build, + // using the same Number and thus create a constraint + // conflict; consider deleting the partially created + // build object in the database err = planBuild(database.FromContext(c), p, b, r) if err != nil { retErr := fmt.Errorf("%s: %w", baseErr, err) // check if the retry limit has been exceeded - if i < retryLimit { - logrus.WithError(retErr).Warning("retrying") + if i < retryLimit-1 { + logrus.WithError(retErr).Warningf("retrying #%d", i+1) // reset fields set by cleanBuild for retry b.SetError("") @@ -596,7 +595,7 @@ func PostWebhook(c *gin.Context) { // break the loop because everything was successful break - } + } // end of retry loop // send API call to update repo for ensuring counter is incremented err = database.FromContext(c).UpdateRepo(r) @@ -610,6 +609,28 @@ func PostWebhook(c *gin.Context) { return } + // return error if pipeline didn't get populated + if p == nil { + retErr := fmt.Errorf("%s: failed to set pipeline for %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusBadRequest, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + + // return error if build didn't get populated + if b == nil { + retErr := fmt.Errorf("%s: failed to set build for %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusBadRequest, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + // send API call to capture the triggered build b, err = database.FromContext(c).GetBuild(b.GetNumber(), r) if err != nil { @@ -618,6 +639,8 @@ func PostWebhook(c *gin.Context) { h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) + + return } // set the BuildID field From 9b27b07a247f2d7d544f56ecf17cebe4c970723e Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 18 Jul 2022 10:49:50 -0600 Subject: [PATCH 084/298] enhance(router/pipeline): change expand, validate, and compile to MustRead (#674) * refactor(router/pipeline): change expand to MustRead * adding validate to the mustread party * adding compile to mustread party --- router/pipeline.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/router/pipeline.go b/router/pipeline.go index dfcf5aa2c..b523f9495 100644 --- a/router/pipeline.go +++ b/router/pipeline.go @@ -38,9 +38,9 @@ func PipelineHandlers(base *gin.RouterGroup) { _pipeline.PUT("", perm.MustWrite(), pipeline.UpdatePipeline) _pipeline.DELETE("", perm.MustPlatformAdmin(), pipeline.DeletePipeline) _pipeline.GET("/templates", perm.MustRead(), pipeline.GetTemplates) - _pipeline.POST("/compile", perm.MustWrite(), pipeline.CompilePipeline) - _pipeline.POST("/expand", perm.MustWrite(), pipeline.ExpandPipeline) - _pipeline.POST("/validate", perm.MustWrite(), pipeline.ValidatePipeline) + _pipeline.POST("/compile", perm.MustRead(), pipeline.CompilePipeline) + _pipeline.POST("/expand", perm.MustRead(), pipeline.ExpandPipeline) + _pipeline.POST("/validate", perm.MustRead(), pipeline.ValidatePipeline) } // end of pipeline endpoints } // end of pipelines endpoints } From 0740ca5b5c68423cd68f516492370e4e03a5fa82 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:19:59 -0600 Subject: [PATCH 085/298] fix(scm/webhook): temporarily turn off pr:edited events (#677) --- scm/github/webhook.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index bfab64893..4d48778b8 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -215,10 +215,9 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven return &types.Webhook{Hook: h}, nil } - // skip if the pull request action is not opened, synchronize, or edited + // skip if the pull request action is not opened, synchronize if !strings.EqualFold(payload.GetAction(), "opened") && - !strings.EqualFold(payload.GetAction(), "synchronize") && - !strings.EqualFold(payload.GetAction(), "edited") { + !strings.EqualFold(payload.GetAction(), "synchronize") { return &types.Webhook{Hook: h}, nil } From 52762640b60e21105aa7d43f537731e92920376d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 21 Jul 2022 14:01:09 -0600 Subject: [PATCH 086/298] fix(build/ruleset): handle legacy PR ruleset for restarted build (#678) --- api/build.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/build.go b/api/build.go index c508d2bef..075a80c36 100644 --- a/api/build.go +++ b/api/build.go @@ -990,6 +990,15 @@ func RestartBuild(c *gin.Context) { b.SetRuntime("") b.SetDistribution("") + // update the PR event action if action was never set + // for backwards compatibility with pre-0.14 releases. + if b.GetEvent() == constants.EventPull && b.GetEventAction() == "" { + // technically, the action could have been opened or synchronize. + // will not affect behavior of the pipeline since we did not + // support actions for builds where this would be the case. + b.SetEventAction(constants.ActionOpened) + } + // set the parent equal to the restarted build number b.SetParent(b.GetNumber()) // update the build numbers based off repo counter From db15cf1d125f5b279b85edf6e70f7cbba57b3627 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:36:15 -0500 Subject: [PATCH 087/298] fix(deps): update module github.com/sirupsen/logrus to v1.9.0 (#675) --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index d32f5ed99..63a1db551 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2 - github.com/sirupsen/logrus v1.8.1 + github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.8.2 github.com/urfave/cli/v2 v2.8.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd @@ -127,7 +127,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 69081d4de..152eb8e95 100644 --- a/go.sum +++ b/go.sum @@ -574,8 +574,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= @@ -817,8 +817,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From b966e6eb2871e296ca75469fb5fae027dbc1c969 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:43:28 -0500 Subject: [PATCH 088/298] fix(deps): update module github.com/urfave/cli/v2 to v2.11.1 (#670) --- go.mod | 4 ++-- go.sum | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 63a1db551..f7a645406 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.12.2 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.8.2 - github.com/urfave/cli/v2 v2.8.1 + github.com/urfave/cli/v2 v2.11.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 gopkg.in/square/go-jose.v2 v2.6.0 @@ -51,7 +51,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect diff --git a/go.sum b/go.sum index 152eb8e95..0bafb4760 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -600,8 +600,8 @@ github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= -github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY= +github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE= +github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1033,8 +1033,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= gorm.io/driver/sqlite v1.3.4 h1:NnFOPVfzi4CPsJPH4wXr6rMkPb4ElHEqKMvrsx9c9Fk= From 66ef7d75000d03c51b4ca23689dfdc07979cddcc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 15:58:44 -0500 Subject: [PATCH 089/298] fix(deps): update module github.com/spf13/afero to v1.9.2 (#673) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f7a645406..fc4564a2d 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2 github.com/sirupsen/logrus v1.9.0 - github.com/spf13/afero v1.8.2 + github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.11.1 go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 diff --git a/go.sum b/go.sum index 0bafb4760..bdac3e793 100644 --- a/go.sum +++ b/go.sum @@ -577,8 +577,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= From 37d66c7439703d3dcf828facf8680a08e6f82cc4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 13:15:26 -0500 Subject: [PATCH 090/298] fix(deps): update go.starlark.net digest to 4cadf0a (#672) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fc4564a2d..687b71378 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.11.1 - go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd + go.starlark.net v0.0.0-20220714194419-4cadf0a12139 golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index bdac3e793..50b68a6ac 100644 --- a/go.sum +++ b/go.sum @@ -621,8 +621,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM= -go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220714194419-4cadf0a12139 h1:zMemyQYZSyEdPaUFixYICrXf/0Rfnil7+jiQRf5IBZ0= +go.starlark.net v0.0.0-20220714194419-4cadf0a12139/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From 30933c7189ad5f7f3fcb33cec7ea5820d6e496c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 18:21:32 -0500 Subject: [PATCH 091/298] fix(deps): update deps (patch) (#668) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 27 ++++++++++++++------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 687b71378..037a8ab66 100644 --- a/go.mod +++ b/go.mod @@ -8,18 +8,18 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.22.0 - github.com/aws/aws-sdk-go v1.44.38 + github.com/aws/aws-sdk-go v1.44.70 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.0.1 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.14.0 - github.com/golang-jwt/jwt/v4 v4.4.1 + github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.8 github.com/google/go-github/v44 v44.1.0 github.com/google/uuid v1.3.0 - github.com/goware/urlx v0.3.1 + github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 @@ -34,10 +34,10 @@ require ( golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.7 - gorm.io/driver/sqlite v1.3.4 - gorm.io/gorm v1.23.6 - k8s.io/apimachinery v0.24.2 + gorm.io/driver/postgres v1.3.8 + gorm.io/driver/sqlite v1.3.6 + gorm.io/gorm v1.23.8 + k8s.io/apimachinery v0.24.3 ) require ( diff --git a/go.sum b/go.sum index 50b68a6ac..1f7e83cf4 100644 --- a/go.sum +++ b/go.sum @@ -76,8 +76,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.38 h1:Mjsc6XXoAA1QHDqDZQ7vOWd+fUmM29coG+AzkSWmRxI= -github.com/aws/aws-sdk-go v1.44.38/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.70 h1:wrwAbqJqf+ncEK1F/bXTYpgO6zXIgQXi/2ppBgmYI9g= +github.com/aws/aws-sdk-go v1.44.70/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -190,8 +190,8 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= -github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -274,8 +274,8 @@ 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/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/goware/urlx v0.3.1 h1:BbvKl8oiXtJAzOzMqAQ0GfIhf96fKeNEZfm9ocNSUBI= -github.com/goware/urlx v0.3.1/go.mod h1:h8uwbJy68o+tQXCGZNa9D73WN8n0r9OBae5bUnLcgjw= +github.com/goware/urlx v0.3.2 h1:gdoo4kBHlkqZNaf6XlQ12LGtQOmpKJrR04Rc3RnpJEo= +github.com/goware/urlx v0.3.2/go.mod h1:h8uwbJy68o+tQXCGZNa9D73WN8n0r9OBae5bUnLcgjw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -1036,13 +1036,14 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= -gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= -gorm.io/driver/sqlite v1.3.4 h1:NnFOPVfzi4CPsJPH4wXr6rMkPb4ElHEqKMvrsx9c9Fk= -gorm.io/driver/sqlite v1.3.4/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= +gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= +gorm.io/driver/postgres v1.3.8/go.mod h1:qB98Aj6AhRO/oyu/jmZsi/YM9g6UzVCjMxO/6frFvcA= +gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= +gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.6 h1:KFLdNgri4ExFFGTRGGFWON2P1ZN28+9SJRN8voOoYe0= gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1050,8 +1051,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= -k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= +k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= From 4c3147febd9667a2fdfdee54606841cd9e98aa84 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Aug 2022 14:26:20 -0500 Subject: [PATCH 092/298] fix(deps): update module github.com/prometheus/client_golang to v1.13.0 (#681) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 037a8ab66..94c16995f 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/hashicorp/vault/api v1.7.2 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.2 + github.com/prometheus/client_golang v1.13.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.11.1 @@ -115,8 +115,8 @@ require ( github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect @@ -126,14 +126,14 @@ require ( github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect google.golang.org/grpc v1.41.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.60.1 // indirect ) diff --git a/go.sum b/go.sum index 1f7e83cf4..ae7162e9e 100644 --- a/go.sum +++ b/go.sum @@ -155,10 +155,12 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= @@ -533,8 +535,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -544,15 +547,17 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -729,8 +734,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -741,6 +747,7 @@ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw= golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -754,6 +761,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -818,6 +826,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1002,8 +1011,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From a08413fa68ac0813078576f5c2cac5811b6f90e2 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Thu, 11 Aug 2022 17:20:10 -0500 Subject: [PATCH 093/298] refactor(database): move user logic into separate package (#663) * feat(database): add user engine * chore(database): remove old user logic * refactor(database): restructure DDL functions * chore: updates for database user engine * chore: address linter feedback * chore: address review feedback Co-authored-by: Jacob Floyd Co-authored-by: Jacob Floyd Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/admin/user.go | 2 +- api/authenticate.go | 4 +- api/metrics.go | 2 +- api/user.go | 26 +- database/pipeline/index.go | 4 +- database/pipeline/index_test.go | 8 +- database/pipeline/pipeline.go | 4 +- database/pipeline/service.go | 8 +- database/pipeline/table.go | 4 +- database/pipeline/table_test.go | 8 +- database/postgres/ddl/user.go | 34 --- database/postgres/dml/user.go | 68 ----- database/postgres/postgres.go | 34 ++- database/postgres/postgres_test.go | 7 +- database/postgres/user.go | 173 ------------ database/postgres/user_count.go | 26 -- database/postgres/user_count_test.go | 82 ------ database/postgres/user_list.go | 86 ------ database/postgres/user_list_test.go | 150 ----------- database/postgres/user_test.go | 250 ------------------ database/service.go | 32 +-- database/sqlite/ddl/user.go | 34 --- database/sqlite/dml/user.go | 68 ----- database/sqlite/sqlite.go | 30 ++- database/sqlite/sqlite_test.go | 38 ++- database/sqlite/user.go | 173 ------------ database/sqlite/user_count_test.go | 97 ------- database/sqlite/user_list.go | 86 ------ database/sqlite/user_list_test.go | 166 ------------ database/sqlite/user_test.go | 248 ----------------- .../{sqlite/user_count.go => user/count.go} | 15 +- database/user/count_test.go | 93 +++++++ database/user/create.go | 49 ++++ database/user/create_test.go | 73 +++++ database/user/delete.go | 30 +++ database/user/delete_test.go | 73 +++++ database/user/get.go | 48 ++++ database/user/get_name.go | 51 ++++ database/user/get_name_test.go | 86 ++++++ database/user/get_test.go | 86 ++++++ database/user/index.go | 24 ++ database/user/index_test.go | 59 +++++ database/user/list.go | 67 +++++ database/user/list_lite.go | 61 +++++ database/user/list_lite_test.go | 116 ++++++++ database/user/list_test.go | 105 ++++++++ database/user/opts.go | 54 ++++ database/user/opts_test.go | 210 +++++++++++++++ database/user/service.go | 45 ++++ database/user/table.go | 62 +++++ database/user/table_test.go | 59 +++++ database/user/update.go | 49 ++++ database/user/update_test.go | 75 ++++++ database/user/user.go | 82 ++++++ database/user/user_test.go | 200 ++++++++++++++ router/middleware/token/token.go | 2 +- 56 files changed, 1979 insertions(+), 1847 deletions(-) delete mode 100644 database/postgres/ddl/user.go delete mode 100644 database/postgres/dml/user.go delete mode 100644 database/postgres/user.go delete mode 100644 database/postgres/user_count.go delete mode 100644 database/postgres/user_count_test.go delete mode 100644 database/postgres/user_list.go delete mode 100644 database/postgres/user_list_test.go delete mode 100644 database/postgres/user_test.go delete mode 100644 database/sqlite/ddl/user.go delete mode 100644 database/sqlite/dml/user.go delete mode 100644 database/sqlite/user.go delete mode 100644 database/sqlite/user_count_test.go delete mode 100644 database/sqlite/user_list.go delete mode 100644 database/sqlite/user_list_test.go delete mode 100644 database/sqlite/user_test.go rename database/{sqlite/user_count.go => user/count.go} (53%) create mode 100644 database/user/count_test.go create mode 100644 database/user/create.go create mode 100644 database/user/create_test.go create mode 100644 database/user/delete.go create mode 100644 database/user/delete_test.go create mode 100644 database/user/get.go create mode 100644 database/user/get_name.go create mode 100644 database/user/get_name_test.go create mode 100644 database/user/get_test.go create mode 100644 database/user/index.go create mode 100644 database/user/index_test.go create mode 100644 database/user/list.go create mode 100644 database/user/list_lite.go create mode 100644 database/user/list_lite_test.go create mode 100644 database/user/list_test.go create mode 100644 database/user/opts.go create mode 100644 database/user/opts_test.go create mode 100644 database/user/service.go create mode 100644 database/user/table.go create mode 100644 database/user/table_test.go create mode 100644 database/user/update.go create mode 100644 database/user/update_test.go create mode 100644 database/user/user.go create mode 100644 database/user/user_test.go diff --git a/api/admin/user.go b/api/admin/user.go index e8729b628..324e8912e 100644 --- a/api/admin/user.go +++ b/api/admin/user.go @@ -45,7 +45,7 @@ func AllUsers(c *gin.Context) { logrus.Info("Admin: reading all users") // send API call to capture all users - u, err := database.FromContext(c).GetUserList() + u, err := database.FromContext(c).ListUsers() if err != nil { retErr := fmt.Errorf("unable to capture all users: %w", err) diff --git a/api/authenticate.go b/api/authenticate.go index 4f14465b0..0a518b697 100644 --- a/api/authenticate.go +++ b/api/authenticate.go @@ -99,7 +99,7 @@ func Authenticate(c *gin.Context) { } // send API call to capture the user logging in - u, err := database.FromContext(c).GetUserName(newUser.GetName()) + u, err := database.FromContext(c).GetUserForName(newUser.GetName()) // create a new user account if len(u.GetName()) == 0 || err != nil { // create unique id for the user @@ -314,7 +314,7 @@ func AuthenticateToken(c *gin.Context) { } // check if the user exists - u, err = database.FromContext(c).GetUserName(u.GetName()) + u, err = database.FromContext(c).GetUserForName(u.GetName()) if err != nil { retErr := fmt.Errorf("user %s not found", u.GetName()) diff --git a/api/metrics.go b/api/metrics.go index 4c94cb4c4..90d499b75 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -74,7 +74,7 @@ func CustomMetrics(c *gin.Context) { // helper function to get the totals of resource types. func recordGauges(c *gin.Context) { // send API call to capture the total number of users - u, err := database.FromContext(c).GetUserCount() + u, err := database.FromContext(c).CountUsers() if err != nil { logrus.Errorf("unable to get count of all users: %v", err) } diff --git a/api/user.go b/api/user.go index 87e0922f1..f22108c58 100644 --- a/api/user.go +++ b/api/user.go @@ -87,7 +87,7 @@ func CreateUser(c *gin.Context) { } // send API call to capture the created user - user, _ := database.FromContext(c).GetUserName(input.GetName()) + user, _ := database.FromContext(c).GetUserForName(input.GetName()) c.JSON(http.StatusCreated, user) } @@ -172,18 +172,8 @@ func GetUsers(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) - // send API call to capture the total number of users - t, err := database.FromContext(c).GetUserCount() - if err != nil { - retErr := fmt.Errorf("unable to get users count: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // send API call to capture the list of users - users, err := database.FromContext(c).GetUserLiteList(page, perPage) + users, t, err := database.FromContext(c).ListLiteUsers(page, perPage) if err != nil { retErr := fmt.Errorf("unable to get users: %w", err) @@ -311,7 +301,7 @@ func UpdateCurrentUser(c *gin.Context) { } // send API call to capture the updated user - u, err = database.FromContext(c).GetUserName(u.GetName()) + u, err = database.FromContext(c).GetUserForName(u.GetName()) if err != nil { retErr := fmt.Errorf("unable to get updated user %s: %w", u.GetName(), err) @@ -363,7 +353,7 @@ func GetUser(c *gin.Context) { }).Infof("reading user %s", user) // send API call to capture the user - u, err := database.FromContext(c).GetUserName(user) + u, err := database.FromContext(c).GetUserForName(user) if err != nil { retErr := fmt.Errorf("unable to get user %s: %w", user, err) @@ -548,7 +538,7 @@ func UpdateUser(c *gin.Context) { } // send API call to capture the user - u, err = database.FromContext(c).GetUserName(user) + u, err = database.FromContext(c).GetUserForName(user) if err != nil { retErr := fmt.Errorf("unable to get user %s: %w", user, err) @@ -584,7 +574,7 @@ func UpdateUser(c *gin.Context) { } // send API call to capture the updated user - u, _ = database.FromContext(c).GetUserName(user) + u, _ = database.FromContext(c).GetUserForName(user) c.JSON(http.StatusOK, u) } @@ -633,7 +623,7 @@ func DeleteUser(c *gin.Context) { }).Infof("deleting user %s", user) // send API call to capture the user - u, err := database.FromContext(c).GetUserName(user) + u, err := database.FromContext(c).GetUserForName(user) if err != nil { retErr := fmt.Errorf("unable to get user %s: %w", user, err) @@ -643,7 +633,7 @@ func DeleteUser(c *gin.Context) { } // send API call to remove the user - err = database.FromContext(c).DeleteUser(u.GetID()) + err = database.FromContext(c).DeleteUser(u) if err != nil { retErr := fmt.Errorf("unable to delete user %s: %w", u.GetName(), err) diff --git a/database/pipeline/index.go b/database/pipeline/index.go index ef8bb4f20..506fddfa8 100644 --- a/database/pipeline/index.go +++ b/database/pipeline/index.go @@ -15,8 +15,8 @@ ON pipelines (repo_id); ` ) -// CreateIndexes creates the indexes for the pipelines table in the database. -func (e *engine) CreateIndexes() error { +// CreatePipelineIndexes creates the indexes for the pipelines table in the database. +func (e *engine) CreatePipelineIndexes() error { e.logger.Tracef("creating indexes for pipelines table in the database") // create the repo_id column index for the pipelines table diff --git a/database/pipeline/index_test.go b/database/pipeline/index_test.go index 75e54f90e..1fa77b7b0 100644 --- a/database/pipeline/index_test.go +++ b/database/pipeline/index_test.go @@ -10,7 +10,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" ) -func TestPipeline_Engine_CreateIndexes(t *testing.T) { +func TestPipeline_Engine_CreatePipelineIndexes(t *testing.T) { // setup types _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -41,18 +41,18 @@ func TestPipeline_Engine_CreateIndexes(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateIndexes() + err := test.database.CreatePipelineIndexes() if test.failure { if err == nil { - t.Errorf("CreateIndexes for %s should have returned err", test.name) + t.Errorf("CreatePipelineIndexes for %s should have returned err", test.name) } return } if err != nil { - t.Errorf("CreateIndexes for %s returned err: %v", test.name, err) + t.Errorf("CreatePipelineIndexes for %s returned err: %v", test.name, err) } }) } diff --git a/database/pipeline/pipeline.go b/database/pipeline/pipeline.go index d6978fad0..2a305d8e4 100644 --- a/database/pipeline/pipeline.go +++ b/database/pipeline/pipeline.go @@ -67,13 +67,13 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the pipelines table - err := e.CreateTable(e.client.Config.Dialector.Name()) + err := e.CreatePipelineTable(e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TablePipeline, err) } // create the indexes for the pipelines table - err = e.CreateIndexes() + err = e.CreatePipelineIndexes() if err != nil { return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TablePipeline, err) } diff --git a/database/pipeline/service.go b/database/pipeline/service.go index a34e75a28..8ff5ec8d5 100644 --- a/database/pipeline/service.go +++ b/database/pipeline/service.go @@ -17,10 +17,10 @@ type PipelineService interface { // // https://en.wikipedia.org/wiki/Data_definition_language - // CreateIndexes creates the indexes for the pipelines table. - CreateIndexes() error - // CreateTable defines a function that creates the pipelines table. - CreateTable(string) error + // CreatePipelineIndexes defines a function that creates the indexes for the pipelines table. + CreatePipelineIndexes() error + // CreatePipelineTable defines a function that creates the pipelines table. + CreatePipelineTable(string) error // Pipeline Data Manipulation Language Functions // diff --git a/database/pipeline/table.go b/database/pipeline/table.go index b4c222e7b..bc463da68 100644 --- a/database/pipeline/table.go +++ b/database/pipeline/table.go @@ -56,8 +56,8 @@ pipelines ( ` ) -// CreateTable creates the pipelines table in the database. -func (e *engine) CreateTable(driver string) error { +// CreatePipelineTable creates the pipelines table in the database. +func (e *engine) CreatePipelineTable(driver string) error { e.logger.Tracef("creating pipelines table in the database") // handle the driver provided to create the table diff --git a/database/pipeline/table_test.go b/database/pipeline/table_test.go index c199f98b5..5b05e4313 100644 --- a/database/pipeline/table_test.go +++ b/database/pipeline/table_test.go @@ -10,7 +10,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" ) -func TestPipeline_Engine_CreateTable(t *testing.T) { +func TestPipeline_Engine_CreatePipelineTable(t *testing.T) { // setup types _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -41,18 +41,18 @@ func TestPipeline_Engine_CreateTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateTable(test.name) + err := test.database.CreatePipelineTable(test.name) if test.failure { if err == nil { - t.Errorf("CreateTable for %s should have returned err", test.name) + t.Errorf("CreatePipelineTable for %s should have returned err", test.name) } return } if err != nil { - t.Errorf("CreateTable for %s returned err: %v", test.name, err) + t.Errorf("CreatePipelineTable for %s returned err: %v", test.name, err) } }) } diff --git a/database/postgres/ddl/user.go b/database/postgres/ddl/user.go deleted file mode 100644 index b6fec0794..000000000 --- a/database/postgres/ddl/user.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateUserTable represents a query to - // create the users table for Vela. - CreateUserTable = ` -CREATE TABLE -IF NOT EXISTS -users ( - id SERIAL PRIMARY KEY, - name VARCHAR(250), - refresh_token VARCHAR(500), - token VARCHAR(500), - hash VARCHAR(500), - favorites VARCHAR(5000), - active BOOLEAN, - admin BOOLEAN, - UNIQUE(name) -); -` - - // CreateUserRefreshIndex represents a query to create an - // index on the users table for the refresh_token column. - CreateUserRefreshIndex = ` -CREATE INDEX -IF NOT EXISTS -users_refresh -ON users (refresh_token); -` -) diff --git a/database/postgres/dml/user.go b/database/postgres/dml/user.go deleted file mode 100644 index 9febce658..000000000 --- a/database/postgres/dml/user.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListUsers represents a query to - // list all users in the database. - ListUsers = ` -SELECT * -FROM users; -` - - // ListLiteUsers represents a query to - // list all lite users in the database. - ListLiteUsers = ` -SELECT id, name -FROM users -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectUser represents a query to select - // a user for an id in the database. - SelectUser = ` -SELECT * -FROM users -WHERE id = ? -LIMIT 1; -` - - // SelectUserName represents a query to select - // a user for a name in the database. - SelectUserName = ` -SELECT * -FROM users -WHERE name = ? -LIMIT 1; -` - - // SelectUsersCount represents a query to select - // the count of users in the database. - SelectUsersCount = ` -SELECT count(*) as count -FROM users; -` - - // SelectRefreshToken represents a query to select - // a user for a refresh_token in the database. - // - // nolint: gosec // ignore false positive - SelectRefreshToken = ` -SELECT * -FROM users -WHERE refresh_token = ? -LIMIT 1; -` - - // DeleteUser represents a query to - // remove a user from the database. - DeleteUser = ` -DELETE -FROM users -WHERE id = ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index c45b954a2..cedb34c49 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -11,6 +11,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" + "github.com/go-vela/server/database/user" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -37,11 +38,15 @@ type ( } client struct { - config *config + config *config + // https://pkg.go.dev/gorm.io/gorm#DB Postgres *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService + // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService + user.UserService } ) @@ -140,6 +145,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // create the new mock Postgres database client // @@ -262,12 +269,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } - // create the users table - err = c.Postgres.Exec(ddl.CreateUserTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableUser, err) - } - // create the workers table err = c.Postgres.Exec(ddl.CreateWorkerTable).Error if err != nil { @@ -342,12 +343,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } - // create the users_refresh index for the users table - err = c.Postgres.Exec(ddl.CreateUserRefreshIndex).Error - if err != nil { - return fmt.Errorf("unable to create users_refresh index for the %s table: %w", constants.TableUser, err) - } - // create the workers_hostname_address index for the workers table err = c.Postgres.Exec(ddl.CreateWorkerHostnameAddressIndex).Error if err != nil { @@ -374,5 +369,18 @@ func createServices(c *client) error { return err } + // create the database agnostic user service + // + // https://pkg.go.dev/github.com/go-vela/server/database/user#New + c.UserService, err = user.New( + user.WithClient(c.Postgres), + user.WithEncryptionKey(c.config.EncryptionKey), + user.WithLogger(c.Logger), + user.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + return nil } diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index fd614af9a..e66919618 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -12,6 +12,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" + "github.com/go-vela/server/database/user" ) func TestPostgres_New(t *testing.T) { @@ -80,7 +81,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateUserTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the index queries @@ -94,7 +94,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -165,7 +164,6 @@ func TestPostgres_createTables(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateUserTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerTable).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { @@ -215,7 +213,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { @@ -257,6 +254,8 @@ func TestPostgres_createServices(t *testing.T) { // ensure the mock expects the index queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool diff --git a/database/postgres/user.go b/database/postgres/user.go deleted file mode 100644 index ca36ae49c..000000000 --- a/database/postgres/user.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - "fmt" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetUser gets a user by unique ID from the database. -func (c *client) GetUser(id int64) (*library.User, error) { - c.Logger.Tracef("getting user %d from the database", id) - - // variable to store query results - u := new(database.User) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableUser). - Raw(dml.SelectUser, id). - Scan(u) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err := u.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %d: %v", id, err) - - // return the unencrypted user - return u.ToLibrary(), result.Error - } - - // return the decrypted user - return u.ToLibrary(), result.Error -} - -// GetUserName gets a user by name from the database. -func (c *client) GetUserName(name string) (*library.User, error) { - c.Logger.WithFields(logrus.Fields{ - "user": name, - }).Tracef("getting user %s from the database", name) - - // variable to store query results - u := new(database.User) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableUser). - Raw(dml.SelectUserName, name). - Scan(u) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err := u.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %s: %v", name, err) - - // return the unencrypted user - return u.ToLibrary(), result.Error - } - - // return the decrypted user - return u.ToLibrary(), result.Error -} - -// CreateUser creates a new user in the database. -// -// nolint: dupl // ignore similar code with update -func (c *client) CreateUser(u *library.User) error { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("creating user %s in the database", u.GetName()) - - // cast to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary - user := database.UserFromLibrary(u) - - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate - err := user.Validate() - if err != nil { - return err - } - - // encrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt - err = user.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableUser). - Create(user).Error -} - -// UpdateUser updates a user in the database. -// -// nolint: dupl // ignore similar code with create -func (c *client) UpdateUser(u *library.User) error { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("updating user %s in the database", u.GetName()) - - // cast to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary - user := database.UserFromLibrary(u) - - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate - err := user.Validate() - if err != nil { - return err - } - - // encrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt - err = user.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableUser). - Save(user).Error -} - -// DeleteUser deletes a user by unique ID from the database. -func (c *client) DeleteUser(id int64) error { - c.Logger.Tracef("deleting user %d from the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableUser). - Exec(dml.DeleteUser, id).Error -} diff --git a/database/postgres/user_count.go b/database/postgres/user_count.go deleted file mode 100644 index 9b41092ab..000000000 --- a/database/postgres/user_count.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" -) - -// GetUserCount gets a count of all users from the database. -func (c *client) GetUserCount() (int64, error) { - c.Logger.Trace("getting count of users from the database") - - // variable to store query results - var u int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableUser). - Raw(dml.SelectUsersCount). - Pluck("count", &u).Error - - return u, err -} diff --git a/database/postgres/user_count_test.go b/database/postgres/user_count_test.go deleted file mode 100644 index 55a0bbaf4..000000000 --- a/database/postgres/user_count_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetUserCount(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - _userOne.SetToken("bar") - _userOne.SetHash("baz") - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - _userTwo.SetToken("foo") - _userTwo.SetHash("baz") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectUsersCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUserCount() - - if test.failure { - if err == nil { - t.Errorf("GetUserCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/user_list.go b/database/postgres/user_list.go deleted file mode 100644 index 0dfb227f4..000000000 --- a/database/postgres/user_list.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" -) - -// GetUserList gets a list of all users from the database. -// -// nolint: dupl // ignore false positive of duplicate code -func (c *client) GetUserList() ([]*library.User, error) { - c.Logger.Trace("listing users from the database") - - // variable to store query results - u := new([]database.User) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableUser). - Raw(dml.ListUsers). - Scan(u).Error - if err != nil { - return nil, err - } - - // variable we want to return - users := []*library.User{} - // iterate through all query results - for _, user := range *u { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := user - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary - users = append(users, tmp.ToLibrary()) - } - - return users, nil -} - -// GetUserLiteList gets a lite list of all users from the database. -func (c *client) GetUserLiteList(page, perPage int) ([]*library.User, error) { - c.Logger.Trace("listing lite users from the database") - - // variable to store query results - u := new([]database.User) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableUser). - Raw(dml.ListLiteUsers, perPage, offset). - Scan(u).Error - - // variable we want to return - users := []*library.User{} - // iterate through all query results - for _, user := range *u { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := user - - // convert query result to library type - users = append(users, tmp.ToLibrary()) - } - - return users, err -} diff --git a/database/postgres/user_list_test.go b/database/postgres/user_list_test.go deleted file mode 100644 index d83b835b2..000000000 --- a/database/postgres/user_list_test.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetUserList(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - _userOne.SetToken("bar") - _userOne.SetHash("baz") - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - _userTwo.SetToken("foo") - _userTwo.SetHash("baz") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListUsers).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "name", "refresh_token", "token", "hash", "favorites", "active", "admin"}, - ).AddRow(1, "foo", "", "bar", "baz", "{}", false, false). - AddRow(2, "bar", "", "foo", "baz", "{}", false, false) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.User - }{ - { - failure: false, - want: []*library.User{_userOne, _userTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUserList() - - if test.failure { - if err == nil { - t.Errorf("GetUserList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetUserLiteList(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - _userOne.SetFavorites(nil) - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - _userTwo.SetFavorites(nil) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListLiteUsers, 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id", "name"}).AddRow(1, "foo").AddRow(2, "bar") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.User - }{ - { - failure: false, - want: []*library.User{_userOne, _userTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUserLiteList(1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetUserLiteList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserLiteList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserLiteList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/user_test.go b/database/postgres/user_test.go deleted file mode 100644 index f17aed522..000000000 --- a/database/postgres/user_test.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectUser, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "name", "refresh_token", "token", "hash", "favorites", "active", "admin"}, - ).AddRow(1, "foo", "", "bar", "baz", "{}", false, false) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.User - }{ - { - failure: false, - want: _user, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUser(1) - - if test.failure { - if err == nil { - t.Errorf("GetUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUser returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUser is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "users" ("name","refresh_token","token","hash","favorites","active","admin","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"`). - WithArgs("foo", AnyArgument{}, AnyArgument{}, AnyArgument{}, "{}", false, false, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateUser(_user) - - if test.failure { - if err == nil { - t.Errorf("CreateUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateUser returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "users" SET "name"=$1,"refresh_token"=$2,"token"=$3,"hash"=$4,"favorites"=$5,"active"=$6,"admin"=$7 WHERE "id" = $8`). - WithArgs("foo", AnyArgument{}, AnyArgument{}, AnyArgument{}, "{}", false, false, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateUser(_user) - - if test.failure { - if err == nil { - t.Errorf("UpdateUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateUser returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteUser(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteUser, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteUser(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteUser returned err: %v", err) - } - } -} - -// testUser is a test helper function to create a -// library User type with all fields set to their -// zero values. -func testUser() *library.User { - i64 := int64(0) - str := "" - arr := []string{} - b := false - - return &library.User{ - ID: &i64, - Name: &str, - RefreshToken: &str, - Token: &str, - Hash: &str, - Favorites: &arr, - Active: &b, - Admin: &b, - } -} diff --git a/database/service.go b/database/service.go index 2c4f880cd..785f65742 100644 --- a/database/service.go +++ b/database/service.go @@ -6,6 +6,7 @@ package database import ( "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/user" "github.com/go-vela/types/library" ) @@ -239,39 +240,16 @@ type Service interface { // deletes a step by unique ID. DeleteService(int64) error - // User Database Interface Functions - - // GetUser defines a function that - // gets a user by unique ID. - GetUser(int64) (*library.User, error) - // GetUserName defines a function that - // gets a user by name. - GetUserName(string) (*library.User, error) - // GetUserList defines a function that - // gets a list of all users. - GetUserList() ([]*library.User, error) - // GetUserCount defines a function that - // gets the count of users. - GetUserCount() (int64, error) - // GetUserLiteList defines a function - // that gets a lite list of users. - GetUserLiteList(int, int) ([]*library.User, error) - // CreateUser defines a function that - // creates a new user. - CreateUser(*library.User) error - // UpdateUser defines a function that - // updates a user. - UpdateUser(*library.User) error - // DeleteUser defines a function that - // deletes a user by unique ID. - DeleteUser(int64) error + // UserService provides the interface for functionality + // related to users stored in the database. + user.UserService // Worker Database Interface Functions // GetWorker defines a function that // gets a worker by hostname. GetWorker(string) (*library.Worker, error) - // GetWorkerAddress defines a function that + // GetWorkerByAddress defines a function that // gets a worker by address. GetWorkerByAddress(string) (*library.Worker, error) // GetWorkerList defines a function that diff --git a/database/sqlite/ddl/user.go b/database/sqlite/ddl/user.go deleted file mode 100644 index 3f8d77e90..000000000 --- a/database/sqlite/ddl/user.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateUserTable represents a query to - // create the users table for Vela. - CreateUserTable = ` -CREATE TABLE -IF NOT EXISTS -users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT, - refresh_token TEXT, - token TEXT, - hash TEXT, - favorites TEXT, - active BOOLEAN, - admin BOOLEAN, - UNIQUE(name) -); -` - - // CreateUserRefreshIndex represents a query to create an - // index on the users table for the refresh_token column. - CreateUserRefreshIndex = ` -CREATE INDEX -IF NOT EXISTS -users_refresh -ON users (refresh_token); -` -) diff --git a/database/sqlite/dml/user.go b/database/sqlite/dml/user.go deleted file mode 100644 index 9febce658..000000000 --- a/database/sqlite/dml/user.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListUsers represents a query to - // list all users in the database. - ListUsers = ` -SELECT * -FROM users; -` - - // ListLiteUsers represents a query to - // list all lite users in the database. - ListLiteUsers = ` -SELECT id, name -FROM users -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectUser represents a query to select - // a user for an id in the database. - SelectUser = ` -SELECT * -FROM users -WHERE id = ? -LIMIT 1; -` - - // SelectUserName represents a query to select - // a user for a name in the database. - SelectUserName = ` -SELECT * -FROM users -WHERE name = ? -LIMIT 1; -` - - // SelectUsersCount represents a query to select - // the count of users in the database. - SelectUsersCount = ` -SELECT count(*) as count -FROM users; -` - - // SelectRefreshToken represents a query to select - // a user for a refresh_token in the database. - // - // nolint: gosec // ignore false positive - SelectRefreshToken = ` -SELECT * -FROM users -WHERE refresh_token = ? -LIMIT 1; -` - - // DeleteUser represents a query to - // remove a user from the database. - DeleteUser = ` -DELETE -FROM users -WHERE id = ?; -` -) diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 61935ff56..32f476f16 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -10,6 +10,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/sqlite/ddl" + "github.com/go-vela/server/database/user" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -37,10 +38,14 @@ type ( client struct { config *config + // https://pkg.go.dev/gorm.io/gorm#DB Sqlite *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService + // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService + user.UserService } ) @@ -258,12 +263,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } - // create the users table - err = c.Sqlite.Exec(ddl.CreateUserTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableUser, err) - } - // create the workers table err = c.Sqlite.Exec(ddl.CreateWorkerTable).Error if err != nil { @@ -338,12 +337,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } - // create the users_refresh index for the users table - err = c.Sqlite.Exec(ddl.CreateUserRefreshIndex).Error - if err != nil { - return fmt.Errorf("unable to create users_refresh index for the %s table: %w", constants.TableUser, err) - } - // create the workers_hostname_address index for the workers table err = c.Sqlite.Exec(ddl.CreateWorkerHostnameAddressIndex).Error if err != nil { @@ -370,5 +363,18 @@ func createServices(c *client) error { return err } + // create the database agnostic user service + // + // https://pkg.go.dev/github.com/go-vela/server/database/user#New + c.UserService, err = user.New( + user.WithClient(c.Sqlite), + user.WithEncryptionKey(c.config.EncryptionKey), + user.WithLogger(c.Logger), + user.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + return nil } diff --git a/database/sqlite/sqlite_test.go b/database/sqlite/sqlite_test.go index 713ce897d..6b31f874a 100644 --- a/database/sqlite/sqlite_test.go +++ b/database/sqlite/sqlite_test.go @@ -145,7 +145,7 @@ func TestSqlite_createTables(t *testing.T) { } } -func TestPostgres_createIndexes(t *testing.T) { +func TestSqlite_createIndexes(t *testing.T) { // setup types // setup the test database client _database, err := NewTest() @@ -180,3 +180,39 @@ func TestPostgres_createIndexes(t *testing.T) { } } } + +func TestSqlite_createServices(t *testing.T) { + // setup types + // setup the test database client + _database, err := NewTest() + if err != nil { + t.Errorf("unable to create new sqlite test database: %v", err) + } + + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + + tests := []struct { + failure bool + }{ + { + failure: false, + }, + } + + // run tests + for _, test := range tests { + err := createServices(_database) + + if test.failure { + if err == nil { + t.Errorf("createServices should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("createServices returned err: %v", err) + } + } +} diff --git a/database/sqlite/user.go b/database/sqlite/user.go deleted file mode 100644 index 033291854..000000000 --- a/database/sqlite/user.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - "fmt" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetUser gets a user by unique ID from the database. -func (c *client) GetUser(id int64) (*library.User, error) { - c.Logger.Tracef("getting user %d from the database", id) - - // variable to store query results - u := new(database.User) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableUser). - Raw(dml.SelectUser, id). - Scan(u) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err := u.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %d: %v", id, err) - - // return the unencrypted user - return u.ToLibrary(), result.Error - } - - // return the decrypted user - return u.ToLibrary(), result.Error -} - -// GetUserName gets a user by name from the database. -func (c *client) GetUserName(name string) (*library.User, error) { - c.Logger.WithFields(logrus.Fields{ - "user": name, - }).Tracef("getting user %s from the database", name) - - // variable to store query results - u := new(database.User) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableUser). - Raw(dml.SelectUserName, name). - Scan(u) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err := u.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %s: %v", name, err) - - // return the unencrypted user - return u.ToLibrary(), result.Error - } - - // return the decrypted user - return u.ToLibrary(), result.Error -} - -// CreateUser creates a new user in the database. -// -// nolint: dupl // ignore similar code with update -func (c *client) CreateUser(u *library.User) error { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("creating user %s in the database", u.GetName()) - - // cast to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary - user := database.UserFromLibrary(u) - - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate - err := user.Validate() - if err != nil { - return err - } - - // encrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt - err = user.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableUser). - Create(user).Error -} - -// UpdateUser updates a user in the database. -// -// nolint: dupl // ignore similar code with create -func (c *client) UpdateUser(u *library.User) error { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("updating user %s in the database", u.GetName()) - - // cast to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary - user := database.UserFromLibrary(u) - - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate - err := user.Validate() - if err != nil { - return err - } - - // encrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt - err = user.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableUser). - Save(user).Error -} - -// DeleteUser deletes a user by unique ID from the database. -func (c *client) DeleteUser(id int64) error { - c.Logger.Tracef("deleting user %d from the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableUser). - Exec(dml.DeleteUser, id).Error -} diff --git a/database/sqlite/user_count_test.go b/database/sqlite/user_count_test.go deleted file mode 100644 index a991f7f8b..000000000 --- a/database/sqlite/user_count_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the user table - err = _database.Sqlite.Exec(ddl.CreateUserTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableUser, err) - } -} - -func TestSqlite_Client_GetUserCount(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - _userOne.SetToken("bar") - _userOne.SetHash("baz") - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - _userTwo.SetToken("foo") - _userTwo.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - // create the users in the database - err := _database.CreateUser(_userOne) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - - err = _database.CreateUser(_userTwo) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - - got, err := _database.GetUserCount() - - if test.failure { - if err == nil { - t.Errorf("GetUserCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/user_list.go b/database/sqlite/user_list.go deleted file mode 100644 index d90863d6b..000000000 --- a/database/sqlite/user_list.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" -) - -// GetUserList gets a list of all users from the database. -// -// nolint: dupl // ignore false positive of duplicate code -func (c *client) GetUserList() ([]*library.User, error) { - c.Logger.Trace("listing users from the database") - - // variable to store query results - u := new([]database.User) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableUser). - Raw(dml.ListUsers). - Scan(u).Error - if err != nil { - return nil, err - } - - // variable we want to return - users := []*library.User{} - // iterate through all query results - for _, user := range *u { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := user - - // decrypt the fields for the user - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted users - c.Logger.Errorf("unable to decrypt user %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary - users = append(users, tmp.ToLibrary()) - } - - return users, nil -} - -// GetUserLiteList gets a lite list of all users from the database. -func (c *client) GetUserLiteList(page, perPage int) ([]*library.User, error) { - c.Logger.Trace("listing lite users from the database") - - // variable to store query results - u := new([]database.User) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableUser). - Raw(dml.ListLiteUsers, perPage, offset). - Scan(u).Error - - // variable we want to return - users := []*library.User{} - // iterate through all query results - for _, user := range *u { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := user - - // convert query result to library type - users = append(users, tmp.ToLibrary()) - } - - return users, err -} diff --git a/database/sqlite/user_list_test.go b/database/sqlite/user_list_test.go deleted file mode 100644 index 4a626f988..000000000 --- a/database/sqlite/user_list_test.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the user table - err = _database.Sqlite.Exec(ddl.CreateUserTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableUser, err) - } -} - -func TestSqlite_Client_GetUserList(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - _userOne.SetToken("bar") - _userOne.SetHash("baz") - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - _userTwo.SetToken("foo") - _userTwo.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.User - }{ - { - failure: false, - want: []*library.User{_userOne, _userTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - for _, user := range test.want { - // create the user in the database - err := _database.CreateUser(user) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - } - - got, err := _database.GetUserList() - - if test.failure { - if err == nil { - t.Errorf("GetUserList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetUserLiteList(t *testing.T) { - // setup types - _userOne := testUser() - _userOne.SetID(1) - _userOne.SetName("foo") - - _userTwo := testUser() - _userTwo.SetID(2) - _userTwo.SetName("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.User - }{ - { - failure: false, - want: []*library.User{_userTwo, _userOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - for _, user := range test.want { - // set the required fields for the user - user.SetToken("baz") - user.SetHash("foob") - - // create the user in the database - err := _database.CreateUser(user) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - - // clear the required fields for the user - // so we get back the expected data - user.SetToken("") - user.SetHash("") - } - - got, err := _database.GetUserLiteList(1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetUserLiteList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserLiteList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserLiteList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/user_test.go b/database/sqlite/user_test.go deleted file mode 100644 index 21f6d9543..000000000 --- a/database/sqlite/user_test.go +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.User - }{ - { - failure: false, - want: _user, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the user in the database - err := _database.CreateUser(test.want) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - } - - got, err := _database.GetUser(1) - - // cleanup the users table - _ = _database.Sqlite.Exec("DELETE FROM users;") - - if test.failure { - if err == nil { - t.Errorf("GetUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUser returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUser is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - err := _database.CreateUser(_user) - - if test.failure { - if err == nil { - t.Errorf("CreateUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateUser returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - // create the user in the database - err := _database.CreateUser(_user) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - - err = _database.UpdateUser(_user) - - if test.failure { - if err == nil { - t.Errorf("UpdateUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateUser returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteUser(t *testing.T) { - // setup types - _user := testUser() - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - _user.SetHash("baz") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the users table - defer _database.Sqlite.Exec("delete from users;") - - // create the user in the database - err := _database.CreateUser(_user) - if err != nil { - t.Errorf("unable to create test user: %v", err) - } - - err = _database.DeleteUser(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteUser should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteUser returned err: %v", err) - } - } -} - -// testUser is a test helper function to create a -// library User type with all fields set to their -// zero values. -func testUser() *library.User { - i64 := int64(0) - str := "" - b := false - - var arr []string - - return &library.User{ - ID: &i64, - Name: &str, - RefreshToken: &str, - Token: &str, - Hash: &str, - Favorites: &arr, - Active: &b, - Admin: &b, - } -} diff --git a/database/sqlite/user_count.go b/database/user/count.go similarity index 53% rename from database/sqlite/user_count.go rename to database/user/count.go index 72b70b003..074a5ef66 100644 --- a/database/sqlite/user_count.go +++ b/database/user/count.go @@ -2,25 +2,24 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package sqlite +package user import ( - "github.com/go-vela/server/database/sqlite/dml" "github.com/go-vela/types/constants" ) -// GetUserCount gets a count of all users from the database. -func (c *client) GetUserCount() (int64, error) { - c.Logger.Trace("getting count of users from the database") +// CountUsers gets the count of all users from the database. +func (e *engine) CountUsers() (int64, error) { + e.logger.Tracef("getting count of all users from the database") // variable to store query results var u int64 // send query to the database and store result in variable - err := c.Sqlite. + err := e.client. Table(constants.TableUser). - Raw(dml.SelectUsersCount). - Pluck("count", &u).Error + Count(&u). + Error return u, err } diff --git a/database/user/count_test.go b/database/user/count_test.go new file mode 100644 index 000000000..be7cb6437 --- /dev/null +++ b/database/user/count_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_CountUsers(t *testing.T) { + // setup types + _userOne := testUser() + _userOne.SetID(1) + _userOne.SetName("foo") + _userOne.SetToken("bar") + _userOne.SetHash("baz") + + _userTwo := testUser() + _userTwo.SetID(2) + _userTwo.SetName("baz") + _userTwo.SetToken("bar") + _userTwo.SetHash("foo") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "users"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_userOne) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.CreateUser(_userTwo) + 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 int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountUsers() + + if test.failure { + if err == nil { + t.Errorf("CountUsers for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountUsers for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountUsers for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/user/create.go b/database/user/create.go new file mode 100644 index 000000000..51c960e79 --- /dev/null +++ b/database/user/create.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore similar code in update.go +package user + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateUser creates a new user in the database. +func (e *engine) CreateUser(u *library.User) error { + e.logger.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Tracef("creating user %s in the database", u.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary + user := database.UserFromLibrary(u) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate + err := user.Validate() + if err != nil { + return err + } + + // encrypt the fields for the user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt + err = user.Encrypt(e.config.EncryptionKey) + if err != nil { + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) + } + + // send query to the database + return e.client. + Table(constants.TableUser). + Create(user). + Error +} diff --git a/database/user/create_test.go b/database/user/create_test.go new file mode 100644 index 000000000..12de80f96 --- /dev/null +++ b/database/user/create_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_CreateUser(t *testing.T) { + // setup types + _user := testUser() + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + _user.SetHash("baz") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "users" +("name","refresh_token","token","hash","favorites","active","admin","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"`). + WithArgs("foo", AnyArgument{}, AnyArgument{}, AnyArgument{}, nil, false, false, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateUser(_user) + + if test.failure { + if err == nil { + t.Errorf("CreateUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateUser for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/user/delete.go b/database/user/delete.go new file mode 100644 index 000000000..95b77ff64 --- /dev/null +++ b/database/user/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteUser deletes an existing user from the database. +func (e *engine) DeleteUser(u *library.User) error { + e.logger.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Tracef("deleting user %s from the database", u.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary + user := database.UserFromLibrary(u) + + // send query to the database + return e.client. + Table(constants.TableUser). + Delete(user). + Error +} diff --git a/database/user/delete_test.go b/database/user/delete_test.go new file mode 100644 index 000000000..0dec0a6b2 --- /dev/null +++ b/database/user/delete_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_DeleteUser(t *testing.T) { + // setup types + _user := testUser() + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + _user.SetHash("baz") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "users" WHERE "users"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_user) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteUser(_user) + + if test.failure { + if err == nil { + t.Errorf("DeleteUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteUser for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/user/get.go b/database/user/get.go new file mode 100644 index 000000000..da8b1a0e7 --- /dev/null +++ b/database/user/get.go @@ -0,0 +1,48 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetUser gets a user by ID from the database. +func (e *engine) GetUser(id int64) (*library.User, error) { + e.logger.Tracef("getting user %d from the database", id) + + // variable to store query results + u := new(database.User) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableUser). + Where("id = ?", id). + Limit(1). + Scan(u). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt + err = u.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted users + e.logger.Errorf("unable to decrypt user %d: %v", u.ID.Int64, err) + } + + // return the decrypted user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary + return u.ToLibrary(), nil +} diff --git a/database/user/get_name.go b/database/user/get_name.go new file mode 100644 index 000000000..2244bfb86 --- /dev/null +++ b/database/user/get_name.go @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetUserForName gets a user by name from the database. +func (e *engine) GetUserForName(name string) (*library.User, error) { + e.logger.WithFields(logrus.Fields{ + "user": name, + }).Tracef("getting user %s from the database", name) + + // variable to store query results + u := new(database.User) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableUser). + Where("name = ?", name). + Limit(1). + Scan(u). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt + err = u.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted users + e.logger.Errorf("unable to decrypt user %d: %v", u.ID.Int64, err) + } + + // return the decrypted user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary + return u.ToLibrary(), nil +} diff --git a/database/user/get_name_test.go b/database/user/get_name_test.go new file mode 100644 index 000000000..4b0a6446b --- /dev/null +++ b/database/user/get_name_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestUser_Engine_GetUserForName(t *testing.T) { + // setup types + _user := testUser() + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + _user.SetHash("baz") + _user.SetFavorites([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "name", "refresh_token", "token", "hash", "favorites", "active", "admin"}). + AddRow(1, "foo", "", "bar", "baz", "{}", false, false) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "users" WHERE name = $1 LIMIT 1`).WithArgs("foo").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_user) + 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.User + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _user, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _user, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetUserForName("foo") + + if test.failure { + if err == nil { + t.Errorf("GetUserForName for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetUserForName for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetUserForName for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/user/get_test.go b/database/user/get_test.go new file mode 100644 index 000000000..4593ce48f --- /dev/null +++ b/database/user/get_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestUser_Engine_GetUser(t *testing.T) { + // setup types + _user := testUser() + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + _user.SetHash("baz") + _user.SetFavorites([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "name", "refresh_token", "token", "hash", "favorites", "active", "admin"}). + AddRow(1, "foo", "", "bar", "baz", "{}", false, false) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "users" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_user) + 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.User + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _user, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _user, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetUser(1) + + if test.failure { + if err == nil { + t.Errorf("GetUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetUser for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetUser for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/user/index.go b/database/user/index.go new file mode 100644 index 000000000..5445e963e --- /dev/null +++ b/database/user/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +const ( + // CreateUserRefreshIndex represents a query to create an + // index on the users table for the refresh_token column. + CreateUserRefreshIndex = ` +CREATE INDEX +IF NOT EXISTS +users_refresh +ON users (refresh_token); +` +) + +// CreateUserIndexes creates the indexes for the users table in the database. +func (e *engine) CreateUserIndexes() error { + e.logger.Tracef("creating indexes for users table in the database") + + // create the refresh_token column index for the users table + return e.client.Exec(CreateUserRefreshIndex).Error +} diff --git a/database/user/index_test.go b/database/user/index_test.go new file mode 100644 index 000000000..55728b77a --- /dev/null +++ b/database/user/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_CreateUserIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateUserIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateUserIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateUserIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/user/list.go b/database/user/list.go new file mode 100644 index 000000000..4bc730f27 --- /dev/null +++ b/database/user/list.go @@ -0,0 +1,67 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListUsers gets a list of all users from the database. +func (e *engine) ListUsers() ([]*library.User, error) { + e.logger.Trace("listing all users from the database") + + // variables to store query results and return value + count := int64(0) + u := new([]database.User) + users := []*library.User{} + + // count the results + count, err := e.CountUsers() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return users, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableUser). + Find(&u). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, user := range *u { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := user + + // decrypt the fields for the user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted users + e.logger.Errorf("unable to decrypt user %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary + users = append(users, tmp.ToLibrary()) + } + + return users, nil +} diff --git a/database/user/list_lite.go b/database/user/list_lite.go new file mode 100644 index 000000000..50957e5f5 --- /dev/null +++ b/database/user/list_lite.go @@ -0,0 +1,61 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListLiteUsers gets a lite (only: id, name) list of users from the database. +// +// nolint: lll // ignore long line length due to variable names +func (e *engine) ListLiteUsers(page, perPage int) ([]*library.User, int64, error) { + e.logger.Trace("listing lite users from the database") + + // variables to store query results and return values + count := int64(0) + u := new([]database.User) + users := []*library.User{} + + // count the results + count, err := e.CountUsers() + if err != nil { + return users, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return users, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + err = e.client. + Table(constants.TableUser). + Select("id", "name"). + Limit(perPage). + Offset(offset). + Find(&u). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, user := range *u { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := user + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.ToLibrary + users = append(users, tmp.ToLibrary()) + } + + return users, count, nil +} diff --git a/database/user/list_lite_test.go b/database/user/list_lite_test.go new file mode 100644 index 000000000..4c44bc20b --- /dev/null +++ b/database/user/list_lite_test.go @@ -0,0 +1,116 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestUser_Engine_ListLiteUsers(t *testing.T) { + // setup types + _userOne := testUser() + _userOne.SetID(1) + _userOne.SetName("foo") + _userOne.SetToken("bar") + _userOne.SetHash("baz") + _userOne.SetFavorites([]string{}) + + _userTwo := testUser() + _userTwo.SetID(2) + _userTwo.SetName("baz") + _userTwo.SetToken("bar") + _userTwo.SetHash("foo") + _userTwo.SetFavorites([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "users"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "name"}). + AddRow(1, "foo"). + AddRow(2, "baz") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT "id","name" FROM "users" LIMIT 10`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_userOne) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.CreateUser(_userTwo) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + // empty fields not returned by query + _userOne.RefreshToken = new(string) + _userOne.Token = new(string) + _userOne.Hash = new(string) + _userOne.Favorites = new([]string) + + _userTwo.RefreshToken = new(string) + _userTwo.Token = new(string) + _userTwo.Hash = new(string) + _userTwo.Favorites = new([]string) + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.User + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.User{_userOne, _userTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.User{_userTwo, _userOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListLiteUsers(1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListLiteUsers for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListLiteUsers for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListLiteUsers for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/user/list_test.go b/database/user/list_test.go new file mode 100644 index 000000000..61293d44c --- /dev/null +++ b/database/user/list_test.go @@ -0,0 +1,105 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestUser_Engine_ListUsers(t *testing.T) { + // setup types + _userOne := testUser() + _userOne.SetID(1) + _userOne.SetName("foo") + _userOne.SetToken("bar") + _userOne.SetHash("baz") + _userOne.SetFavorites([]string{}) + + _userTwo := testUser() + _userTwo.SetID(2) + _userTwo.SetName("baz") + _userTwo.SetToken("bar") + _userTwo.SetHash("foo") + _userTwo.SetFavorites([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "users"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "name", "refresh_token", "token", "hash", "favorites", "active", "admin"}). + AddRow(1, "foo", "", "bar", "baz", "{}", false, false). + AddRow(2, "baz", "", "bar", "foo", "{}", false, false) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "users"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_userOne) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.CreateUser(_userTwo) + 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.User + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.User{_userOne, _userTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.User{_userOne, _userTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListUsers() + + if test.failure { + if err == nil { + t.Errorf("ListUsers for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListUsers for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListUsers for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/user/opts.go b/database/user/opts.go new file mode 100644 index 000000000..58780c317 --- /dev/null +++ b/database/user/opts.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Users. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Users. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the user engine + e.client = client + + return nil + } +} + +// WithEncryptionKey sets the encryption key in the database engine for Users. +func WithEncryptionKey(key string) EngineOpt { + return func(e *engine) error { + // set the encryption key in the user engine + e.config.EncryptionKey = key + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Users. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the user engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Users. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the user engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/user/opts_test.go b/database/user/opts_test.go new file mode 100644 index 000000000..77fb9ae23 --- /dev/null +++ b/database/user/opts_test.go @@ -0,0 +1,210 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestUser_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestUser_EngineOpt_WithEncryptionKey(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + key string + want string + }{ + { + failure: false, + name: "encryption key set", + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + }, + { + failure: false, + name: "encryption key not set", + key: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithEncryptionKey(test.key)(e) + + if test.failure { + if err == nil { + t.Errorf("WithEncryptionKey for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithEncryptionKey returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.EncryptionKey, test.want) { + t.Errorf("WithEncryptionKey is %v, want %v", e.config.EncryptionKey, test.want) + } + }) + } +} + +func TestUser_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestUser_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/user/service.go b/database/user/service.go new file mode 100644 index 000000000..096cea933 --- /dev/null +++ b/database/user/service.go @@ -0,0 +1,45 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/library" +) + +// UserService represents the Vela interface for user +// functions with the supported Database backends. +// +// nolint: revive // ignore name stutter +type UserService interface { + // User Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateUserIndexes defines a function that creates the indexes for the users table. + CreateUserIndexes() error + // CreateUserTable defines a function that creates the users table. + CreateUserTable(string) error + + // User Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountUsers defines a function that gets the count of all users. + CountUsers() (int64, error) + // CreateUser defines a function that creates a new user. + CreateUser(*library.User) error + // DeleteUser defines a function that deletes an existing user. + DeleteUser(*library.User) error + // GetUser defines a function that gets a user by ID. + GetUser(int64) (*library.User, error) + // GetUserForName defines a function that gets a user by name. + GetUserForName(string) (*library.User, error) + // ListUsers defines a function that gets a list of all users. + ListUsers() ([]*library.User, error) + // ListLiteUsers defines a function that gets a lite list of users. + ListLiteUsers(int, int) ([]*library.User, int64, error) + // UpdateUser defines a function that updates an existing user. + UpdateUser(*library.User) error +} diff --git a/database/user/table.go b/database/user/table.go new file mode 100644 index 000000000..456853770 --- /dev/null +++ b/database/user/table.go @@ -0,0 +1,62 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres users table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +users ( + id SERIAL PRIMARY KEY, + name VARCHAR(250), + refresh_token VARCHAR(500), + token VARCHAR(500), + hash VARCHAR(500), + favorites VARCHAR(5000), + active BOOLEAN, + admin BOOLEAN, + UNIQUE(name) +); +` + + // CreateSqliteTable represents a query to create the Sqlite users table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + refresh_token TEXT, + token TEXT, + hash TEXT, + favorites TEXT, + active BOOLEAN, + admin BOOLEAN, + UNIQUE(name) +); +` +) + +// CreateUserTable creates the users table in the database. +func (e *engine) CreateUserTable(driver string) error { + e.logger.Tracef("creating users table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the users table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the users table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/user/table_test.go b/database/user/table_test.go new file mode 100644 index 000000000..95a2d4c00 --- /dev/null +++ b/database/user/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_CreateUserTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateUserTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateUserTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateUserTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/user/update.go b/database/user/update.go new file mode 100644 index 000000000..f41d80a30 --- /dev/null +++ b/database/user/update.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore similar code in create.go +package user + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateUser updates an existing user in the database. +func (e *engine) UpdateUser(u *library.User) error { + e.logger.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Tracef("updating user %s in the database", u.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#UserFromLibrary + user := database.UserFromLibrary(u) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Validate + err := user.Validate() + if err != nil { + return err + } + + // encrypt the fields for the user + // + // https://pkg.go.dev/github.com/go-vela/types/database#User.Encrypt + err = user.Encrypt(e.config.EncryptionKey) + if err != nil { + return fmt.Errorf("unable to encrypt user %s: %w", u.GetName(), err) + } + + // send query to the database + return e.client. + Table(constants.TableUser). + Save(user). + Error +} diff --git a/database/user/update_test.go b/database/user/update_test.go new file mode 100644 index 000000000..4253ac435 --- /dev/null +++ b/database/user/update_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestUser_Engine_UpdateUser(t *testing.T) { + // setup types + _user := testUser() + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + _user.SetHash("baz") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "users" +SET "name"=$1,"refresh_token"=$2,"token"=$3,"hash"=$4,"favorites"=$5,"active"=$6,"admin"=$7 +WHERE "id" = $8`). + WithArgs("foo", AnyArgument{}, AnyArgument{}, AnyArgument{}, nil, false, false, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateUser(_user) + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateUser(_user) + + if test.failure { + if err == nil { + t.Errorf("UpdateUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateUser for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/user/user.go b/database/user/user.go new file mode 100644 index 000000000..e37b18644 --- /dev/null +++ b/database/user/user.go @@ -0,0 +1,82 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the UserService interface. + config struct { + // specifies the encryption key to use for the User engine + EncryptionKey string + // specifies to skip creating tables and indexes for the User engine + SkipCreation bool + } + + // engine represents the user functionality that implements the UserService interface. + engine struct { + // engine configuration settings used in user functions + config *config + + // gorm.io/gorm database client used in user functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in user functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with users in the database. +// +// nolint: revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new User engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating user database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of users table and indexes in the database") + + return e, nil + } + + // create the users table + err := e.CreateUserTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableUser, err) + } + + // create the indexes for the users table + err = e.CreateUserIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableUser, err) + } + + return e, nil +} diff --git a/database/user/user_test.go b/database/user/user_test.go new file mode 100644 index 000000000..1586103a7 --- /dev/null +++ b/database/user/user_test.go @@ -0,0 +1,200 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestUser_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithEncryptionKey(test.key), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres user engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite user engine: %v", err) + } + + return _engine +} + +// testUser is a test helper function to create a library +// User type with all fields set to their zero values. +func testUser() *library.User { + return &library.User{ + ID: new(int64), + Name: new(string), + RefreshToken: new(string), + Token: new(string), + Hash: new(string), + Favorites: new([]string), + Active: new(bool), + Admin: 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(v driver.Value) bool { + return true +} diff --git a/router/middleware/token/token.go b/router/middleware/token/token.go index cf40b882a..68c53aa99 100644 --- a/router/middleware/token/token.go +++ b/router/middleware/token/token.go @@ -113,7 +113,7 @@ func Parse(t string, db database.Service) (*library.User, error) { // lookup the user in the database logrus.WithField("user", name).Debugf("reading user %s", name) - u, err = db.GetUserName(name) + u, err = db.GetUserForName(name) return []byte(u.GetHash()), err }) From 048364c219128ed2fdaffc44a0acfd12e8c92fa8 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 15 Aug 2022 10:43:52 -0500 Subject: [PATCH 094/298] feat(compiler): support deployment parameters in templates (#665) --- .golangci.yml | 1 + compiler/template/native/convert.go | 34 +++++-- compiler/template/native/convert_test.go | 63 ++++++++++-- compiler/template/starlark/convert.go | 68 ++++++++----- compiler/template/starlark/convert_test.go | 109 +++++++++++++++++---- 5 files changed, 222 insertions(+), 53 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 97b6d15a3..00c50154f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -157,3 +157,4 @@ issues: - funlen - goconst - gocyclo + - wsl diff --git a/compiler/template/native/convert.go b/compiler/template/native/convert.go index 7a773b83b..68385c6cb 100644 --- a/compiler/template/native/convert.go +++ b/compiler/template/native/convert.go @@ -18,9 +18,22 @@ import ( func convertPlatformVars(slice raw.StringSliceMap, name string) raw.StringSliceMap { envs := make(map[string]string) + // iterate through the list of key/value pairs provided for key, value := range slice { + // lowercase the key key = strings.ToLower(key) + + // check if the key has a 'deployment_parameter_*' prefix + if strings.HasPrefix(key, "deployment_parameter_") { + // add the key/value pair with the 'deployment_parameter_` prefix + // + // this is used to ensure we prevent conflicts with `vela_*` prefixed variables + envs[key] = value + } + + // check if the key has a 'vela_*' prefix if strings.HasPrefix(key, "vela_") { + // add the key/value pair without the 'vela_` prefix envs[strings.TrimPrefix(key, "vela_")] = value } } @@ -54,14 +67,21 @@ type funcHandler struct { // returnPlatformVar returns the value of the platform // variable if it exists within the environment map. -func (h funcHandler) returnPlatformVar(input string) string { - input = strings.ToLower(input) - input = strings.TrimPrefix(input, "vela_") - // check if key exists within map - if _, ok := h.envs[input]; ok { - // return value if exists - return h.envs[input] +func (h funcHandler) returnPlatformVar(key string) string { + // lowercase the key + key = strings.ToLower(key) + + // iterate through the list of possible prefixes to look for + for _, prefix := range []string{"deployment_parameter_", "vela_"} { + // trim the prefix from the input key + trimmed := strings.TrimPrefix(key, prefix) + // check if the key exists within map + if _, ok := h.envs[trimmed]; ok { + // return the non-prefixed value if exists + return h.envs[trimmed] + } } + // return empty string if not exists return "" } diff --git a/compiler/template/native/convert_test.go b/compiler/template/native/convert_test.go index 9e350a2fe..db0b42a8f 100644 --- a/compiler/template/native/convert_test.go +++ b/compiler/template/native/convert_test.go @@ -18,6 +18,14 @@ func Test_convertPlatformVars(t *testing.T) { templateName string want raw.StringSliceMap }{ + { + name: "with all deployment parameter prefixed vars", + slice: raw.StringSliceMap{ + "DEPLOYMENT_PARAMETER_IMAGE": "alpine:3.14", + }, + templateName: "foo", + want: raw.StringSliceMap{"deployment_parameter_image": "alpine:3.14", "template_name": "foo"}, + }, { name: "with all vela prefixed vars", slice: raw.StringSliceMap{ @@ -30,15 +38,18 @@ func Test_convertPlatformVars(t *testing.T) { want: raw.StringSliceMap{"build_author": "octocat", "repo_full_name": "go-vela/hello-world", "user_admin": "true", "workspace": "/vela/src/github.com/go-vela/hello-world", "template_name": "foo"}, }, { - name: "with combination of vela and user vars", + name: "with combination of deployment parameter, vela, and user vars", slice: raw.StringSliceMap{ - "VELA_BUILD_AUTHOR": "octocat", - "VELA_REPO_FULL_NAME": "go-vela/hello-world", - "FOO_VAR1": "test1", - "BAR_VAR1": "test2", + "DEPLOYMENT_PARAMETER_IMAGE": "alpine:3.14", + "VELA_BUILD_AUTHOR": "octocat", + "VELA_REPO_FULL_NAME": "go-vela/hello-world", + "VELA_USER_ADMIN": "true", + "VELA_WORKSPACE": "/vela/src/github.com/go-vela/hello-world", + "FOO_VAR1": "test1", + "BAR_VAR1": "test2", }, templateName: "foo", - want: raw.StringSliceMap{"build_author": "octocat", "repo_full_name": "go-vela/hello-world", "template_name": "foo"}, + want: raw.StringSliceMap{"deployment_parameter_image": "alpine:3.14", "build_author": "octocat", "repo_full_name": "go-vela/hello-world", "user_admin": "true", "workspace": "/vela/src/github.com/go-vela/hello-world", "template_name": "foo"}, }, } @@ -66,6 +77,46 @@ func Test_funcHandler_returnPlatformVar(t *testing.T) { args args want string }{ + { + name: "existing deployment parameter without prefix (lowercase)", + fields: fields{ + envs: raw.StringSliceMap{ + "image": "alpine", + }, + }, + args: args{input: "image"}, + want: "alpine", + }, + { + name: "existing deployment parameter without prefix (uppercase)", + fields: fields{ + envs: raw.StringSliceMap{ + "image": "alpine", + }, + }, + args: args{input: "IMAGE"}, + want: "alpine", + }, + { + name: "existing deployment parameter with prefix (lowercase)", + fields: fields{ + envs: raw.StringSliceMap{ + "image": "alpine", + }, + }, + args: args{input: "deployment_parameter_image"}, + want: "alpine", + }, + { + name: "existing deployment parameter with prefix (uppercase)", + fields: fields{ + envs: raw.StringSliceMap{ + "image": "alpine", + }, + }, + args: args{input: "DEPLOYMENT_PARAMETER_IMAGE"}, + want: "alpine", + }, { name: "existing platform var without prefix (lowercase)", fields: fields{ diff --git a/compiler/template/starlark/convert.go b/compiler/template/starlark/convert.go index 9ec0d4ee5..474086316 100644 --- a/compiler/template/starlark/convert.go +++ b/compiler/template/starlark/convert.go @@ -47,6 +47,7 @@ func convertTemplateVars(m map[string]interface{}) (*starlark.Dict, error) { // https://pkg.go.dev/go.starlark.net/starlark#StringDict func convertPlatformVars(slice raw.StringSliceMap, name string) (*starlark.Dict, error) { build := starlark.NewDict(0) + deployment := starlark.NewDict(0) repo := starlark.NewDict(0) user := starlark.NewDict(0) system := starlark.NewDict(0) @@ -57,6 +58,11 @@ func convertPlatformVars(slice raw.StringSliceMap, name string) (*starlark.Dict, return nil, err } + err = dict.SetKey(starlark.String("deployment"), deployment) + if err != nil { + return nil, err + } + err = dict.SetKey(starlark.String("repo"), repo) if err != nil { return nil, err @@ -77,31 +83,47 @@ func convertPlatformVars(slice raw.StringSliceMap, name string) (*starlark.Dict, return nil, err } + // iterate through the list of key/value pairs provided for key, value := range slice { + // lowercase the key key = strings.ToLower(key) - if strings.HasPrefix(key, "vela_") { - key = strings.TrimPrefix(key, "vela_") - - switch { - case strings.HasPrefix(key, "build_"): - err := build.SetKey(starlark.String(strings.TrimPrefix(key, "build_")), starlark.String(value)) - if err != nil { - return nil, err - } - case strings.HasPrefix(key, "repo_"): - err := repo.SetKey(starlark.String(strings.TrimPrefix(key, "repo_")), starlark.String(value)) - if err != nil { - return nil, err - } - case strings.HasPrefix(key, "user_"): - err := user.SetKey(starlark.String(strings.TrimPrefix(key, "user_")), starlark.String(value)) - if err != nil { - return nil, err - } - default: - err := system.SetKey(starlark.String(key), starlark.String(value)) - if err != nil { - return nil, err + + // iterate through the list of possible prefixes to look for + for _, prefix := range []string{"deployment_parameter_", "vela_"} { + // check if the key has the prefix + if strings.HasPrefix(key, prefix) { + // trim the prefix from the input key + key = strings.TrimPrefix(key, prefix) + + // check if the prefix is from 'vela_*' + if strings.EqualFold(prefix, "vela_") { + switch { + case strings.HasPrefix(key, "build_"): + err := build.SetKey(starlark.String(strings.TrimPrefix(key, "build_")), starlark.String(value)) + if err != nil { + return nil, err + } + case strings.HasPrefix(key, "repo_"): + err := repo.SetKey(starlark.String(strings.TrimPrefix(key, "repo_")), starlark.String(value)) + if err != nil { + return nil, err + } + case strings.HasPrefix(key, "user_"): + err := user.SetKey(starlark.String(strings.TrimPrefix(key, "user_")), starlark.String(value)) + if err != nil { + return nil, err + } + default: + err := system.SetKey(starlark.String(key), starlark.String(value)) + if err != nil { + return nil, err + } + } + } else { // prefix is from 'deployment_parameter_*' + err := deployment.SetKey(starlark.String(key), starlark.String(value)) + if err != nil { + return nil, err + } } } } diff --git a/compiler/template/starlark/convert_test.go b/compiler/template/starlark/convert_test.go index cfaae4acb..b6eb03bf8 100644 --- a/compiler/template/starlark/convert_test.go +++ b/compiler/template/starlark/convert_test.go @@ -82,59 +82,112 @@ func TestStarlark_Render_convertTemplateVars(t *testing.T) { } } -func TestStarlark_Render_velaEnvironmentData(t *testing.T) { +func TestStarlark_Render_convertPlatformVars(t *testing.T) { // setup types - build := starlark.NewDict(1) - + build := starlark.NewDict(0) err := build.SetKey(starlark.String("author"), starlark.String("octocat")) if err != nil { t.Error(err) } - repo := starlark.NewDict(1) + deployment := starlark.NewDict(0) + err = deployment.SetKey(starlark.String("image"), starlark.String("alpine:3.14")) + if err != nil { + t.Error(err) + } + repo := starlark.NewDict(0) err = repo.SetKey(starlark.String("full_name"), starlark.String("go-vela/hello-world")) if err != nil { t.Error(err) } - user := starlark.NewDict(1) - + user := starlark.NewDict(0) err = user.SetKey(starlark.String("admin"), starlark.String("true")) if err != nil { t.Error(err) } - system := starlark.NewDict(2) - + system := starlark.NewDict(0) err = system.SetKey(starlark.String("template_name"), starlark.String("foo")) if err != nil { t.Error(err) } - err = system.SetKey(starlark.String("workspace"), starlark.String("/vela/src/github.com/go-vela/hello-world")) if err != nil { t.Error(err) } - withAllPre := starlark.NewDict(0) - - err = withAllPre.SetKey(starlark.String("build"), build) + // setup full dictionary + withAll := starlark.NewDict(0) + err = withAll.SetKey(starlark.String("build"), build) if err != nil { t.Error(err) } - - err = withAllPre.SetKey(starlark.String("repo"), repo) + err = withAll.SetKey(starlark.String("deployment"), deployment) + if err != nil { + t.Error(err) + } + err = withAll.SetKey(starlark.String("repo"), repo) + if err != nil { + t.Error(err) + } + err = withAll.SetKey(starlark.String("user"), user) + if err != nil { + t.Error(err) + } + err = withAll.SetKey(starlark.String("system"), system) if err != nil { t.Error(err) } - err = withAllPre.SetKey(starlark.String("user"), user) + // setup vela dictionary + withAllVela := starlark.NewDict(0) + err = withAllVela.SetKey(starlark.String("build"), build) + if err != nil { + t.Error(err) + } + err = withAllVela.SetKey(starlark.String("deployment"), starlark.NewDict(0)) + if err != nil { + t.Error(err) + } + err = withAllVela.SetKey(starlark.String("repo"), repo) + if err != nil { + t.Error(err) + } + err = withAllVela.SetKey(starlark.String("user"), user) + if err != nil { + t.Error(err) + } + err = withAllVela.SetKey(starlark.String("system"), system) if err != nil { t.Error(err) } - err = withAllPre.SetKey(starlark.String("system"), system) + // setup deployment dictionary + withAllDeployment := starlark.NewDict(0) + err = withAllDeployment.SetKey(starlark.String("build"), starlark.NewDict(0)) + if err != nil { + t.Error(err) + } + err = withAllDeployment.SetKey(starlark.String("deployment"), deployment) + if err != nil { + t.Error(err) + } + err = withAllDeployment.SetKey(starlark.String("repo"), starlark.NewDict(0)) + if err != nil { + t.Error(err) + } + err = withAllDeployment.SetKey(starlark.String("user"), starlark.NewDict(0)) + if err != nil { + t.Error(err) + } + system = starlark.NewDict(0) + err = system.SetKey(starlark.String("template_name"), starlark.String("foo")) + if err != nil { + t.Error(err) + } + err = withAllDeployment.SetKey(starlark.String("system"), system) if err != nil { t.Error(err) } @@ -146,6 +199,14 @@ func TestStarlark_Render_velaEnvironmentData(t *testing.T) { want *starlark.Dict wantErr bool }{ + { + name: "with all deployment parameter prefixed vars", + slice: raw.StringSliceMap{ + "DEPLOYMENT_PARAMETER_IMAGE": "alpine:3.14", + }, + templateName: "foo", + want: withAllDeployment, + }, { name: "with all vela prefixed var", slice: raw.StringSliceMap{ @@ -155,7 +216,21 @@ func TestStarlark_Render_velaEnvironmentData(t *testing.T) { "VELA_WORKSPACE": "/vela/src/github.com/go-vela/hello-world", }, templateName: "foo", - want: withAllPre, + want: withAllVela, + }, + { + name: "with combination of deployment parameter, vela, and user vars", + slice: raw.StringSliceMap{ + "DEPLOYMENT_PARAMETER_IMAGE": "alpine:3.14", + "VELA_BUILD_AUTHOR": "octocat", + "VELA_REPO_FULL_NAME": "go-vela/hello-world", + "VELA_USER_ADMIN": "true", + "VELA_WORKSPACE": "/vela/src/github.com/go-vela/hello-world", + "FOO_VAR1": "test1", + "BAR_VAR1": "test2", + }, + templateName: "foo", + want: withAll, }, } From 7d6c7d53f8b159f9ce53ac8d7e4d3dda25c7db0c Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Thu, 18 Aug 2022 16:00:50 -0500 Subject: [PATCH 095/298] enhance(metrics)!: query parameter support on metrics endpoint (#682) --- api/metrics.go | 384 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 285 insertions(+), 99 deletions(-) diff --git a/api/metrics.go b/api/metrics.go index 90d499b75..2a671e384 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -17,6 +17,45 @@ import ( "github.com/sirupsen/logrus" ) +// MetricsQueryParameters holds query parameter information pertaining to requested metrics. +type MetricsQueryParameters struct { + // UserCount represents total platform users + UserCount bool `form:"user_count"` + // RepoCount represents total platform repos + RepoCount bool `form:"repo_count"` + + // BuildCount represents total number of builds + BuildCount bool `form:"build_count"` + // RunningBuildCount represents total number of builds with status==running + RunningBuildCount bool `form:"running_build_count"` + // PendingBuildCount represents total number of builds with status==pending + PendingBuildCount bool `form:"pending_build_count"` + // FailureBuildCount represents total number of builds with status==failure + FailureBuildCount bool `form:"failure_build_count"` + // KilledBuildCount represents total number of builds with status==killed + KilledBuildCount bool `form:"killed_build_count"` + // SuccessBuildCount represents total number of builds with status==success + SuccessBuildCount bool `form:"success_build_count"` + // ErrorBuildCount represents total number of builds with status==error + ErrorBuildCount bool `form:"error_build_count"` + + // StepImageCount represents total number of step images + StepImageCount bool `form:"step_image_count"` + // StepStatusCount represents total number of step statuses + StepStatusCount bool `form:"step_status_count"` + // ServiceImageCount represents total number of service images + ServiceImageCount bool `form:"service_image_count"` + // ServiceStatusCount represents total number of service statuses + ServiceStatusCount bool `form:"service_status_count"` + + // WorkerBuildLimit represents total worker build limit + WorkerBuildLimit bool `form:"worker_build_limit"` + // ActiveWorkerCount represents total number of active workers + ActiveWorkerCount bool `form:"active_worker_count"` + // InactiveWorkerCount represents total number of inactive workers + InactiveWorkerCount bool `form:"inactive_worker_count"` +} + // predefine Prometheus metrics else they will be regenerated // each function call which will throw error: // "duplicate metrics collector registration attempted". @@ -54,6 +93,86 @@ var ( // produces: // - text/plain // parameters: +// - in: query +// name: user_count +// description: Indicates a request for user count +// type: boolean +// default: false +// - in: query +// name: repo_count +// description: Indicates a request for repo count +// type: boolean +// default: false +// - in: query +// name: build_count +// description: Indicates a request for build count +// type: boolean +// default: false +// - in: query +// name: running_build_count +// description: Indicates a request for running build count +// type: boolean +// default: false +// - in: query +// name: pending_build_count +// description: Indicates a request for pending build count +// type: boolean +// default: false +// - in: query +// name: failure_build_count +// description: Indicates a request for failure build count +// type: boolean +// default: false +// - in: query +// name: killed_build_count +// description: Indicates a request for killed build count +// type: boolean +// default: false +// - in: query +// name: success_build_count +// description: Indicates a request for success build count +// type: boolean +// default: false +// - in: query +// name: error_build_count +// description: Indicates a request for error build count +// type: boolean +// default: false +// - in: query +// name: step_image_count +// description: Indicates a request for step image count +// type: boolean +// default: false +// - in: query +// name: step_status_count +// description: Indicates a request for step status count +// type: boolean +// default: false +// - in: query +// name: service_image_count +// description: Indicates a request for service image count +// type: boolean +// default: false +// - in: query +// name: service_status_count +// description: Indicates a request for service status count +// type: boolean +// default: false +// - in: query +// name: worker_build_limit +// description: Indicates a request for total worker build limit +// type: boolean +// default: false +// - in: query +// name: active_worker_count +// description: Indicates a request for active worker count +// type: boolean +// default: false +// - in: query +// name: inactive_worker_count +// description: Indicates a request for inactive worker count +// type: boolean +// default: false // responses: // '200': // description: Successfully retrieved the Vela metrics @@ -72,144 +191,211 @@ func CustomMetrics(c *gin.Context) { } // helper function to get the totals of resource types. +// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity func recordGauges(c *gin.Context) { - // send API call to capture the total number of users - u, err := database.FromContext(c).CountUsers() - if err != nil { - logrus.Errorf("unable to get count of all users: %v", err) - } + // variable to store query parameters + q := MetricsQueryParameters{} - // send API call to capture the total number of repos - r, err := database.FromContext(c).GetRepoCount() + // take incoming request and bind query parameters + err := c.ShouldBindQuery(&q) if err != nil { - logrus.Errorf("unable to get count of all repos: %v", err) + logrus.Errorf("unable to get bind query parameters: %v", err) + } // continue execution with parameters defaulted to false + + // get each metric separately based on request query parameters + // user_count + if q.UserCount { + // send API call to capture the total number of users + u, err := database.FromContext(c).CountUsers() + if err != nil { + logrus.Errorf("unable to get count of all users: %v", err) + } + // add platform metrics + totals.WithLabelValues("platform", "count", "users").Set(float64(u)) } - // send API call to capture the total number of builds - b, err := database.FromContext(c).GetBuildCount() - if err != nil { - logrus.Errorf("unable to get count of all builds: %v", err) + // repo_count + if q.RepoCount { + // send API call to capture the total number of repos + r, err := database.FromContext(c).GetRepoCount() + if err != nil { + logrus.Errorf("unable to get count of all repos: %v", err) + } + // add platform metrics + totals.WithLabelValues("platform", "count", "repos").Set(float64(r)) } - // send API call to capture the total number of running builds - bRun, err := database.FromContext(c).GetBuildCountByStatus("running") - if err != nil { - logrus.Errorf("unable to get count of all running builds: %v", err) + // build_count + if q.BuildCount { + // send API call to capture the total number of builds + b, err := database.FromContext(c).GetBuildCount() + if err != nil { + logrus.Errorf("unable to get count of all builds: %v", err) + } + // add platform metrics + totals.WithLabelValues("platform", "count", "builds").Set(float64(b)) } - // send API call to capture the total number of pending builds - bPen, err := database.FromContext(c).GetBuildCountByStatus("pending") - if err != nil { - logrus.Errorf("unable to get count of all pending builds: %v", err) + // running_build_count + if q.RunningBuildCount { + // send API call to capture the total number of running builds + bRun, err := database.FromContext(c).GetBuildCountByStatus("running") + if err != nil { + logrus.Errorf("unable to get count of all running builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "running").Set(float64(bRun)) } - // send API call to capture the total number of failure builds - bFail, err := database.FromContext(c).GetBuildCountByStatus("failure") - if err != nil { - logrus.Errorf("unable to get count of all failure builds: %v", err) + // pending_build_count + if q.PendingBuildCount { + // send API call to capture the total number of pending builds + bPen, err := database.FromContext(c).GetBuildCountByStatus("pending") + if err != nil { + logrus.Errorf("unable to get count of all pending builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "pending").Set(float64(bPen)) } - // send API call to capture the total number of killed builds - bKill, err := database.FromContext(c).GetBuildCountByStatus("killed") - if err != nil { - logrus.Errorf("unable to get count of all killed builds: %v", err) + // failure_build_count + if q.FailureBuildCount { + // send API call to capture the total number of failure builds + bFail, err := database.FromContext(c).GetBuildCountByStatus("failure") + if err != nil { + logrus.Errorf("unable to get count of all failure builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "failed").Set(float64(bFail)) } - // send API call to capture the total number of success builds - bSucc, err := database.FromContext(c).GetBuildCountByStatus("success") - if err != nil { - logrus.Errorf("unable to get count of all success builds: %v", err) + // killed_build_count + if q.KilledBuildCount { + // send API call to capture the total number of killed builds + bKill, err := database.FromContext(c).GetBuildCountByStatus("killed") + if err != nil { + logrus.Errorf("unable to get count of all killed builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "killed").Set(float64(bKill)) } - // send API call to capture the total number of error builds - bErr, err := database.FromContext(c).GetBuildCountByStatus("error") - if err != nil { - logrus.Errorf("unable to get count of all error builds: %v", err) + // success_build_count + if q.SuccessBuildCount { + // send API call to capture the total number of success builds + bSucc, err := database.FromContext(c).GetBuildCountByStatus("success") + if err != nil { + logrus.Errorf("unable to get count of all success builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "success").Set(float64(bSucc)) } - // send API call to capture the total number of step images - stepImageMap, err := database.FromContext(c).GetStepImageCount() - if err != nil { - logrus.Errorf("unable to get count of all step images: %v", err) + // error_build_count + if q.ErrorBuildCount { + // send API call to capture the total number of error builds + bErr, err := database.FromContext(c).GetBuildCountByStatus("error") + if err != nil { + logrus.Errorf("unable to get count of all error builds: %v", err) + } + // add build metrics + totals.WithLabelValues("build", "status", "error").Set(float64(bErr)) } - // send API call to capture the total number of step statuses - stepStatusMap, err := database.FromContext(c).GetStepStatusCount() - if err != nil { - logrus.Errorf("unable to get count of all step statuses: %v", err) + // step_image_count + if q.StepImageCount { + // send API call to capture the total number of step images + stepImageMap, err := database.FromContext(c).GetStepImageCount() + if err != nil { + logrus.Errorf("unable to get count of all step images: %v", err) + } + // add step image metrics + for image, count := range stepImageMap { + stepImages.WithLabelValues(image).Set(count) + } } - // send API call to capture the total number of service images - serviceImageMap, err := database.FromContext(c).GetServiceImageCount() - if err != nil { - logrus.Errorf("unable to get count of all service images: %v", err) + // step_status_count + if q.StepStatusCount { + // send API call to capture the total number of step statuses + stepStatusMap, err := database.FromContext(c).GetStepStatusCount() + if err != nil { + logrus.Errorf("unable to get count of all step statuses: %v", err) + } + // add step status metrics + for status, count := range stepStatusMap { + totals.WithLabelValues("steps", "status", status).Set(count) + } } - // send API call to capture the total number of service statuses - serviceStatusMap, err := database.FromContext(c).GetServiceStatusCount() - if err != nil { - logrus.Errorf("unable to get count of all service statuses: %v", err) + // service_image_count + if q.ServiceImageCount { + // send API call to capture the total number of service images + serviceImageMap, err := database.FromContext(c).GetServiceImageCount() + if err != nil { + logrus.Errorf("unable to get count of all service images: %v", err) + } + // add service image metrics + for image, count := range serviceImageMap { + serviceImages.WithLabelValues(image).Set(count) + } } - // send API call to capture the workers - workers, err := database.FromContext(c).GetWorkerList() - if err != nil { - logrus.Errorf("unable to get workers: %v", err) + // service_status_count + if q.ServiceStatusCount { + // send API call to capture the total number of service statuses + serviceStatusMap, err := database.FromContext(c).GetServiceStatusCount() + if err != nil { + logrus.Errorf("unable to get count of all service statuses: %v", err) + } + // add service status metrics + for status, count := range serviceStatusMap { + totals.WithLabelValues("services", "status", status).Set(count) + } } - // Add platform metrics - totals.WithLabelValues("platform", "count", "users").Set(float64(u)) - totals.WithLabelValues("platform", "count", "repos").Set(float64(r)) - totals.WithLabelValues("platform", "count", "builds").Set(float64(b)) - - // Add build metrics - totals.WithLabelValues("build", "status", "running").Set(float64(bRun)) - totals.WithLabelValues("build", "status", "pending").Set(float64(bPen)) - totals.WithLabelValues("build", "status", "failed").Set(float64(bFail)) - totals.WithLabelValues("build", "status", "killed").Set(float64(bKill)) - totals.WithLabelValues("build", "status", "success").Set(float64(bSucc)) - totals.WithLabelValues("build", "status", "error").Set(float64(bErr)) - - // Add worker metrics + // add worker metrics var ( buildLimit int64 activeWorkers int64 inactiveWorkers int64 ) - // get the unix time from worker_active_interval ago - before := time.Now().UTC().Add(-c.Value("worker_active_interval").(time.Duration)).Unix() - for _, worker := range workers { - // check if the worker checked in within the last worker_active_interval - if worker.GetLastCheckedIn() >= before { - buildLimit += worker.GetBuildLimit() - activeWorkers++ - } else { - inactiveWorkers++ + // get worker metrics based on request query parameters + // worker_build_limit, active_worker_count, inactive_worker_count + if q.WorkerBuildLimit || q.ActiveWorkerCount || q.InactiveWorkerCount { + // send API call to capture the workers + workers, err := database.FromContext(c).GetWorkerList() + if err != nil { + logrus.Errorf("unable to get workers: %v", err) } - } - totals.WithLabelValues("worker", "sum", "build_limit").Set(float64(buildLimit)) - totals.WithLabelValues("worker", "count", "active").Set(float64(activeWorkers)) - totals.WithLabelValues("worker", "count", "inactive").Set(float64(inactiveWorkers)) - - // Add step status metrics - for status, count := range stepStatusMap { - totals.WithLabelValues("steps", "status", status).Set(count) - } + // get the unix time from worker_active_interval ago + before := time.Now().UTC().Add(-c.Value("worker_active_interval").(time.Duration)).Unix() + for _, worker := range workers { + // check if the worker checked in within the last worker_active_interval + if worker.GetLastCheckedIn() >= before { + buildLimit += worker.GetBuildLimit() + activeWorkers++ + } else { + inactiveWorkers++ + } + } - // Add service status metrics - for status, count := range serviceStatusMap { - totals.WithLabelValues("services", "status", status).Set(count) - } + // apply metrics based on request query parameters + // worker_build_limit + if q.WorkerBuildLimit { + totals.WithLabelValues("worker", "sum", "build_limit").Set(float64(buildLimit)) + } - // Add step image metrics - for image, count := range stepImageMap { - stepImages.WithLabelValues(image).Set(count) - } + // active_worker_count + if q.ActiveWorkerCount { + totals.WithLabelValues("worker", "count", "active").Set(float64(activeWorkers)) + } - // Add service image metrics - for image, count := range serviceImageMap { - serviceImages.WithLabelValues(image).Set(count) + // inactive_worker_count + if q.InactiveWorkerCount { + totals.WithLabelValues("worker", "count", "inactive").Set(float64(inactiveWorkers)) + } } } From 8672cbca96d3e04b997d0e73ffb4b862b7b57c8d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 18 Aug 2022 15:29:39 -0600 Subject: [PATCH 096/298] feat(logger): censor build author email for security compliance (#667) * chore(logger): censor build author email for security compliance * updating tests to utilize correct types * fix test to include normal stringlog Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- router/middleware/logger.go | 13 +++++++ router/middleware/logger_test.go | 66 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/router/middleware/logger.go b/router/middleware/logger.go index 2d49023c6..3cde2a61d 100644 --- a/router/middleware/logger.go +++ b/router/middleware/logger.go @@ -16,6 +16,7 @@ import ( "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/constants" "github.com/sirupsen/logrus" ) @@ -56,6 +57,7 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc body := c.Value("payload") if body != nil { + body = sanitize(body) fields["body"] = body } @@ -105,3 +107,14 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc } } } + +func sanitize(body interface{}) interface{} { + if m, ok := body.(map[string]interface{}); ok { + if _, ok = m["email"]; ok { + m["email"] = constants.SecretMask + body = m + } + } + + return body +} diff --git a/router/middleware/logger_test.go b/router/middleware/logger_test.go index c4ef3a1e3..87f4e267b 100644 --- a/router/middleware/logger_test.go +++ b/router/middleware/logger_test.go @@ -11,6 +11,7 @@ import ( "net/http" "net/http/httptest" "reflect" + "strings" "testing" "time" @@ -151,3 +152,68 @@ func TestMiddleware_Logger_Error(t *testing.T) { t.Errorf("Logger Message is %v, want %v", gotMessage, wantMessage) } } + +func TestMiddleware_Logger_Sanitize(t *testing.T) { + var logBody, logWant map[string]interface{} + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + logRepo, _ := json.Marshal(r) + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + b.SetEmail("octocat@github.com") + logBuild, _ := json.Marshal(b) + + sanitizeBuild := *b + sanitizeBuild.SetEmail("[secure]") + logSBuild, _ := json.Marshal(&sanitizeBuild) + + tests := []struct { + dataType string + body []byte + want []byte + }{ + { + dataType: "stringMap", + body: logRepo, + want: logRepo, + }, + { + dataType: "stringMap", + body: logBuild, + want: logSBuild, + }, + { + dataType: "string", + body: []byte("successfully updated step"), + want: []byte("successfully updated step"), + }, + } + + for _, test := range tests { + if strings.EqualFold(test.dataType, "stringMap") { + err := json.Unmarshal(test.body, &logBody) + if err != nil { + t.Errorf("unable to unmarshal log body data") + } + + err = json.Unmarshal(test.want, &logWant) + if err != nil { + t.Errorf("unable to unmarshal log want data") + } + } + + got := sanitize(logBody) + + if !reflect.DeepEqual(got, logWant) { + t.Errorf("Logger returned %v, want %v", got, logWant) + } + } +} From e2071f2d6f5b762c3c20ac6b9bcc57c1ac9039e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Aug 2022 11:27:46 +0000 Subject: [PATCH 097/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.23.0 (#684) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 94c16995f..0c0edd4cf 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.22.0 + github.com/alicebob/miniredis/v2 v2.23.0 github.com/aws/aws-sdk-go v1.44.70 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 diff --git a/go.sum b/go.sum index ae7162e9e..0dcddb20c 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.22.0 h1:lIHHiSkEyS1MkKHCHzN+0mWrA4YdbGdimE5iZ2sHSzo= -github.com/alicebob/miniredis/v2 v2.22.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= +github.com/alicebob/miniredis/v2 v2.23.0 h1:+lwAJYjvvdIVg6doFHuotFjueJ/7KY10xo/vm3X3Scw= +github.com/alicebob/miniredis/v2 v2.23.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= From 92ef5557cc7739da321a59d48feae38ff1a821f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Aug 2022 04:41:19 +0000 Subject: [PATCH 098/298] fix(deps): update go.starlark.net digest to f738f55 (#685) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 0c0edd4cf..4c8af30a4 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.11.1 - go.starlark.net v0.0.0-20220714194419-4cadf0a12139 + go.starlark.net v0.0.0-20220817180228-f738f5508c12 golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 @@ -127,7 +127,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 0dcddb20c..fc2c24279 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220714194419-4cadf0a12139 h1:zMemyQYZSyEdPaUFixYICrXf/0Rfnil7+jiQRf5IBZ0= -go.starlark.net v0.0.0-20220714194419-4cadf0a12139/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= +go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= +go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -827,8 +827,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= From c0abd524fa5119448a2e4dea1ce86ca2523fc91d Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Mon, 12 Sep 2022 13:42:26 -0500 Subject: [PATCH 099/298] chore: upgrade go 1.19 (#690) --- .github/workflows/build.yml | 10 ++++-- .github/workflows/prerelease.yml | 14 +++++--- .github/workflows/publish.yml | 14 +++++--- .github/workflows/reviewdog.yml | 12 +++++-- .github/workflows/spec.yml | 10 ++++-- .github/workflows/test.yml | 10 ++++-- .github/workflows/validate.yml | 12 +++++-- Makefile | 2 +- api/admin/doc.go | 2 +- api/doc.go | 2 +- compiler/doc.go | 2 +- compiler/native/compile_test.go | 18 +++++----- compiler/native/doc.go | 2 +- .../native/testdata/inline_with_golang.yml | 2 +- .../native/testdata/inline_with_stages.yml | 2 +- .../native/testdata/stage_inline_template.yml | 2 +- .../native/testdata/step_inline_template.yml | 2 +- compiler/registry/doc.go | 2 +- compiler/registry/github/doc.go | 2 +- compiler/template/doc.go | 2 +- compiler/template/native/doc.go | 2 +- database/doc.go | 2 +- database/postgres/ddl/doc.go | 2 +- database/postgres/dml/doc.go | 2 +- database/postgres/doc.go | 2 +- database/sqlite/ddl/doc.go | 2 +- database/sqlite/dml/doc.go | 2 +- database/sqlite/doc.go | 2 +- go.mod | 2 +- go.sum | 36 ------------------- queue/doc.go | 2 +- queue/redis/doc.go | 2 +- router/doc.go | 2 +- router/middleware/build/doc.go | 2 +- router/middleware/doc.go | 2 +- router/middleware/executors/doc.go | 2 +- router/middleware/logger.go | 4 +-- router/middleware/org/doc.go | 2 +- router/middleware/perm/doc.go | 2 +- router/middleware/pipeline/doc.go | 2 +- router/middleware/repo/doc.go | 2 +- router/middleware/service/doc.go | 2 +- router/middleware/step/doc.go | 2 +- router/middleware/token/doc.go | 2 +- router/middleware/user/doc.go | 2 +- router/middleware/worker/doc.go | 2 +- router/router.go | 36 +++++++++---------- scm/doc.go | 2 +- scm/github/doc.go | 2 +- secret/doc.go | 2 +- secret/native/doc.go | 2 +- secret/vault/doc.go | 2 +- 52 files changed, 132 insertions(+), 126 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1840ce8f3..ac9711453 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,12 +10,18 @@ on: jobs: build: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: build run: | make build diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 28646bc50..475429b48 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -11,8 +11,7 @@ on: jobs: prerelease: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 @@ -20,6 +19,13 @@ jobs: # ensures we fetch tag history for the repository fetch-depth: 0 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: setup run: | # setup git tag in Actions environment @@ -33,7 +39,7 @@ jobs: make build-static-ci - name: publish - uses: elgohr/Publish-Docker-Github-Action@master + uses: elgohr/Publish-Docker-Github-Action@v4 with: name: target/vela-server cache: true @@ -42,7 +48,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: publish-alpine - uses: elgohr/Publish-Docker-Github-Action@master + uses: elgohr/Publish-Docker-Github-Action@v4 with: name: target/vela-server cache: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 85a430292..71d077009 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,8 +10,7 @@ on: jobs: publish: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 @@ -19,6 +18,13 @@ jobs: # ensures we fetch tag history for the repository fetch-depth: 0 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: build env: GOOS: linux @@ -27,7 +33,7 @@ jobs: make build-static-ci - name: publish - uses: elgohr/Publish-Docker-Github-Action@master + uses: elgohr/Publish-Docker-Github-Action@v4 with: name: target/vela-server cache: true @@ -35,7 +41,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: publish-alpine - uses: elgohr/Publish-Docker-Github-Action@master + uses: elgohr/Publish-Docker-Github-Action@v4 with: name: target/vela-server cache: true diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 1e0515d0f..09ff67bb7 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -9,12 +9,18 @@ on: jobs: diff-review: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 with: @@ -27,7 +33,7 @@ jobs: full-review: runs-on: ubuntu-latest container: - image: golang:1.17 + image: golang:1.19 steps: - name: clone uses: actions/checkout@v3 diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index 9cc2d9cce..d5ea466ea 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -10,12 +10,18 @@ on: jobs: schema: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: tags run: | git fetch --tags diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 713423a15..3a5e6141e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,12 +10,18 @@ on: jobs: test: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: test run: | go test -race -covermode=atomic -coverprofile=coverage.out ./... diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 844bc7938..61ece7bed 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -10,12 +10,18 @@ on: jobs: validate: runs-on: ubuntu-latest - container: - image: golang:1.17 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: tags run: | git fetch --tags @@ -33,5 +39,5 @@ jobs: - name: validate spec run: | - make spec-install + sudo make spec-install make spec \ No newline at end of file diff --git a/Makefile b/Makefile index 9bb50b910..61dce5988 100644 --- a/Makefile +++ b/Makefile @@ -267,7 +267,7 @@ spec-install: @apt-get update @apt-get install -y jq moreutils @echo "### Downloading and installing go-swagger" - @curl -o /usr/local/bin/swagger -L "https://github.com/go-swagger/go-swagger/releases/download/v0.27.0/swagger_linux_amd64" + @curl -o /usr/local/bin/swagger -L "https://github.com/go-swagger/go-swagger/releases/download/v0.30.2/swagger_linux_amd64" @chmod +x /usr/local/bin/swagger # The `spec-gen` target is intended to create an api-spec diff --git a/api/admin/doc.go b/api/admin/doc.go index 414fca7e4..565520dbf 100644 --- a/api/admin/doc.go +++ b/api/admin/doc.go @@ -6,5 +6,5 @@ // // Usage: // -// import "github.com/go-vela/server/api/admin" +// import "github.com/go-vela/server/api/admin" package admin diff --git a/api/doc.go b/api/doc.go index e1fe11d97..4f9d47c48 100644 --- a/api/doc.go +++ b/api/doc.go @@ -6,5 +6,5 @@ // // Usage: // -// import "github.com/go-vela/server/api" +// import "github.com/go-vela/server/api" package api diff --git a/compiler/doc.go b/compiler/doc.go index d86fb589d..0e6e12e57 100644 --- a/compiler/doc.go +++ b/compiler/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/compiler" +// import "github.com/go-vela/server/compiler" package compiler diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index b8cea0052..780586ee8 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -2032,7 +2032,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from foo", m, ""), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_foo", Pull: "not_present", Number: 4, @@ -2050,7 +2050,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from bar", m, ""), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_bar", Pull: "not_present", Number: 5, @@ -2068,7 +2068,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from star", m, ""), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_star", Pull: "not_present", Number: 6, @@ -2547,7 +2547,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from foo", m, constants.PipelineTypeGo), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_foo", Pull: "not_present", Number: 6, @@ -2565,7 +2565,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from bar", m, constants.PipelineTypeGo), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_bar", Pull: "not_present", Number: 7, @@ -2583,7 +2583,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Entrypoint: []string{"/bin/sh", "-c"}, Environment: generateTestEnv("echo hello from star", m, constants.PipelineTypeGo), - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_star", Pull: "not_present", Number: 8, @@ -2768,7 +2768,7 @@ func Test_CompileLite(t *testing.T) { Steps: []*yaml.Step{ { Commands: raw.StringSlice{"echo hello from foo"}, - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_foo", Pull: "not_present", }, @@ -2780,7 +2780,7 @@ func Test_CompileLite(t *testing.T) { Steps: []*yaml.Step{ { Commands: raw.StringSlice{"echo hello from bar"}, - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_bar", Pull: "not_present", }, @@ -2792,7 +2792,7 @@ func Test_CompileLite(t *testing.T) { Steps: []*yaml.Step{ { Commands: raw.StringSlice{"echo hello from star"}, - Image: "golang:1.17", + Image: "golang:latest", Name: "golang_star", Pull: "not_present", }, diff --git a/compiler/native/doc.go b/compiler/native/doc.go index 3de2c7a3a..81877d3da 100644 --- a/compiler/native/doc.go +++ b/compiler/native/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/compiler/native" +// import "github.com/go-vela/server/compiler/native" package native diff --git a/compiler/native/testdata/inline_with_golang.yml b/compiler/native/testdata/inline_with_golang.yml index 4ad50e3d9..12767cfab 100644 --- a/compiler/native/testdata/inline_with_golang.yml +++ b/compiler/native/testdata/inline_with_golang.yml @@ -9,7 +9,7 @@ templates: format: golang type: github vars: - image: golang:1.17 + image: golang:latest - name: starlark source: github.example.com/github/octocat/starlark_inline_stages.star format: starlark diff --git a/compiler/native/testdata/inline_with_stages.yml b/compiler/native/testdata/inline_with_stages.yml index 6d808e95d..89d79b5e3 100644 --- a/compiler/native/testdata/inline_with_stages.yml +++ b/compiler/native/testdata/inline_with_stages.yml @@ -9,7 +9,7 @@ templates: format: golang type: github vars: - image: golang:1.17 + image: golang:latest - name: starlark source: github.example.com/github/octocat/starlark_inline_stages.star format: starlark diff --git a/compiler/native/testdata/stage_inline_template.yml b/compiler/native/testdata/stage_inline_template.yml index 1958bc5b8..7d25f4328 100644 --- a/compiler/native/testdata/stage_inline_template.yml +++ b/compiler/native/testdata/stage_inline_template.yml @@ -9,7 +9,7 @@ templates: format: golang type: github vars: - image: golang:1.17 + image: golang:latest stages: test: diff --git a/compiler/native/testdata/step_inline_template.yml b/compiler/native/testdata/step_inline_template.yml index 9df215300..6b29e2aa3 100644 --- a/compiler/native/testdata/step_inline_template.yml +++ b/compiler/native/testdata/step_inline_template.yml @@ -9,7 +9,7 @@ templates: format: golang type: github vars: - image: golang:1.17 + image: golang:latest steps: - name: golang diff --git a/compiler/registry/doc.go b/compiler/registry/doc.go index 70cb52e2b..2064281e4 100644 --- a/compiler/registry/doc.go +++ b/compiler/registry/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/compiler/registry" +// import "github.com/go-vela/server/compiler/registry" package registry diff --git a/compiler/registry/github/doc.go b/compiler/registry/github/doc.go index 87e9427a1..1bab3812e 100644 --- a/compiler/registry/github/doc.go +++ b/compiler/registry/github/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/compiler/registry/github" +// import "github.com/go-vela/server/compiler/registry/github" package github diff --git a/compiler/template/doc.go b/compiler/template/doc.go index 66c9d028b..f9e37fb29 100644 --- a/compiler/template/doc.go +++ b/compiler/template/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/template" +// import "github.com/go-vela/server/template" package template diff --git a/compiler/template/native/doc.go b/compiler/template/native/doc.go index 55af6bfcb..34c41a275 100644 --- a/compiler/template/native/doc.go +++ b/compiler/template/native/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/compiler/template/native" +// import "github.com/go-vela/server/compiler/template/native" package native diff --git a/database/doc.go b/database/doc.go index 42b459f39..42fe1feae 100644 --- a/database/doc.go +++ b/database/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/database" +// import "github.com/go-vela/server/database" package database diff --git a/database/postgres/ddl/doc.go b/database/postgres/ddl/doc.go index 6a21d9d02..3e21c882f 100644 --- a/database/postgres/ddl/doc.go +++ b/database/postgres/ddl/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/postgres/ddl" +// import "github.com/go-vela/server/database/postgres/ddl" package ddl diff --git a/database/postgres/dml/doc.go b/database/postgres/dml/doc.go index cdab7d21b..f7e517d36 100644 --- a/database/postgres/dml/doc.go +++ b/database/postgres/dml/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/postgres/dml" +// import "github.com/go-vela/server/database/postgres/dml" package dml diff --git a/database/postgres/doc.go b/database/postgres/doc.go index 13879fdbd..0fbbbd274 100644 --- a/database/postgres/doc.go +++ b/database/postgres/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/postgres" +// import "github.com/go-vela/server/database/postgres" package postgres diff --git a/database/sqlite/ddl/doc.go b/database/sqlite/ddl/doc.go index fb2942402..3e2bd5d2b 100644 --- a/database/sqlite/ddl/doc.go +++ b/database/sqlite/ddl/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/sqlite/ddl" +// import "github.com/go-vela/server/database/sqlite/ddl" package ddl diff --git a/database/sqlite/dml/doc.go b/database/sqlite/dml/doc.go index fb4a8ecba..151d8a9a5 100644 --- a/database/sqlite/dml/doc.go +++ b/database/sqlite/dml/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/sqlite/dml" +// import "github.com/go-vela/server/database/sqlite/dml" package dml diff --git a/database/sqlite/doc.go b/database/sqlite/doc.go index c0ceaf5aa..a27ddb46f 100644 --- a/database/sqlite/doc.go +++ b/database/sqlite/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/database/sqlite" +// import "github.com/go-vela/server/database/sqlite" package sqlite diff --git a/go.mod b/go.mod index 4c8af30a4..3cfd8874f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/go-vela/server -go 1.17 +go 1.19 require ( github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb diff --git a/go.sum b/go.sum index fc2c24279..e123b14ff 100644 --- a/go.sum +++ b/go.sum @@ -39,7 +39,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw= github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -129,15 +128,11 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= -github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -148,7 +143,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -156,7 +150,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -180,9 +173,7 @@ github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXS github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-vela/types v0.14.0 h1:m75BdRfQm9PC4l/oHSgeplt8mqgau3JmqD3DN+KdePk= github.com/go-vela/types v0.14.0/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= @@ -263,7 +254,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -293,29 +283,23 @@ github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= -github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= -github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= -github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -343,7 +327,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -364,7 +347,6 @@ github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5W github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= @@ -392,7 +374,6 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -498,23 +479,17 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= @@ -601,7 +576,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= @@ -654,7 +628,6 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -731,7 +704,6 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -761,7 +733,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -811,7 +782,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -826,7 +796,6 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -845,7 +814,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -899,7 +867,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1012,7 +979,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -1026,7 +992,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -1046,7 +1011,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= gorm.io/driver/postgres v1.3.8/go.mod h1:qB98Aj6AhRO/oyu/jmZsi/YM9g6UzVCjMxO/6frFvcA= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= diff --git a/queue/doc.go b/queue/doc.go index ca03c8c84..5c08b1b0d 100644 --- a/queue/doc.go +++ b/queue/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/queue" +// import "github.com/go-vela/server/queue" package queue diff --git a/queue/redis/doc.go b/queue/redis/doc.go index ad6afe54c..d75e65027 100644 --- a/queue/redis/doc.go +++ b/queue/redis/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/queue/redis" +// import "github.com/go-vela/server/queue/redis" package redis diff --git a/router/doc.go b/router/doc.go index 41ce9fb80..17052a2b5 100644 --- a/router/doc.go +++ b/router/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/router" +// import "github.com/go-vela/server/router" package router diff --git a/router/middleware/build/doc.go b/router/middleware/build/doc.go index 662549772..bbe90cf70 100644 --- a/router/middleware/build/doc.go +++ b/router/middleware/build/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/build" +// import "github.com/go-vela/server/router/middleware/build" package build diff --git a/router/middleware/doc.go b/router/middleware/doc.go index fc9e8ae67..36ab883b0 100644 --- a/router/middleware/doc.go +++ b/router/middleware/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware" +// import "github.com/go-vela/server/router/middleware" package middleware diff --git a/router/middleware/executors/doc.go b/router/middleware/executors/doc.go index faddc1d94..5a75b0cf3 100644 --- a/router/middleware/executors/doc.go +++ b/router/middleware/executors/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/executor" +// import "github.com/go-vela/server/router/middleware/executor" package executors diff --git a/router/middleware/logger.go b/router/middleware/logger.go index 3cde2a61d..9be222039 100644 --- a/router/middleware/logger.go +++ b/router/middleware/logger.go @@ -26,8 +26,8 @@ import ( // Requests without errors are logged using logrus.Info(). // // It receives: -// 1. A time package format string (e.g. time.RFC3339). -// 2. A boolean stating whether to use UTC time zone or local. +// 1. A time package format string (e.g. time.RFC3339). +// 2. A boolean stating whether to use UTC time zone or local. func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() diff --git a/router/middleware/org/doc.go b/router/middleware/org/doc.go index e3ddee377..32c3d410a 100644 --- a/router/middleware/org/doc.go +++ b/router/middleware/org/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/org" +// import "github.com/go-vela/server/router/middleware/org" package org diff --git a/router/middleware/perm/doc.go b/router/middleware/perm/doc.go index daf86955b..4cb5ad472 100644 --- a/router/middleware/perm/doc.go +++ b/router/middleware/perm/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/perm" +// import "github.com/go-vela/server/router/middleware/perm" package perm diff --git a/router/middleware/pipeline/doc.go b/router/middleware/pipeline/doc.go index 70c59a3a4..e6f19504d 100644 --- a/router/middleware/pipeline/doc.go +++ b/router/middleware/pipeline/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/pipeline" +// import "github.com/go-vela/server/router/middleware/pipeline" package pipeline diff --git a/router/middleware/repo/doc.go b/router/middleware/repo/doc.go index 6b6a33c97..028ebe70b 100644 --- a/router/middleware/repo/doc.go +++ b/router/middleware/repo/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/repo" +// import "github.com/go-vela/server/router/middleware/repo" package repo diff --git a/router/middleware/service/doc.go b/router/middleware/service/doc.go index 2d185d23e..698d41aaa 100644 --- a/router/middleware/service/doc.go +++ b/router/middleware/service/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/service" +// import "github.com/go-vela/server/router/middleware/service" package service diff --git a/router/middleware/step/doc.go b/router/middleware/step/doc.go index e1e0b26ba..45ddd7e61 100644 --- a/router/middleware/step/doc.go +++ b/router/middleware/step/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/step" +// import "github.com/go-vela/server/router/middleware/step" package step diff --git a/router/middleware/token/doc.go b/router/middleware/token/doc.go index e673c8f5e..b4c5a498d 100644 --- a/router/middleware/token/doc.go +++ b/router/middleware/token/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/token" +// import "github.com/go-vela/server/router/middleware/token" package token diff --git a/router/middleware/user/doc.go b/router/middleware/user/doc.go index d86024512..42181f07d 100644 --- a/router/middleware/user/doc.go +++ b/router/middleware/user/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/user" +// import "github.com/go-vela/server/router/middleware/user" package user diff --git a/router/middleware/worker/doc.go b/router/middleware/worker/doc.go index 1070cbd2b..44eaaa675 100644 --- a/router/middleware/worker/doc.go +++ b/router/middleware/worker/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/worker" +// import "github.com/go-vela/server/router/middleware/worker" package worker diff --git a/router/router.go b/router/router.go index 43870bb5d..402f4eb93 100644 --- a/router/router.go +++ b/router/router.go @@ -6,27 +6,27 @@ // // API for the Vela server // -// Version: 0.0.0-dev -// Schemes: http, https -// Host: localhost +// Version: 0.0.0-dev +// Schemes: http, https +// Host: localhost // -// Consumes: -// - application/json +// Consumes: +// - application/json // -// Produces: -// - application/json +// Produces: +// - application/json // -// SecurityDefinitions: -// ApiKeyAuth: -// description: Bearer token -// type: apiKey -// in: header -// name: Authorization -// CookieAuth: -// description: Refresh token sent as cookie (swagger 2.0 doesn't support cookie auth) -// type: apiKey -// in: header -// name: vela_refresh_token +// SecurityDefinitions: +// ApiKeyAuth: +// description: Bearer token +// type: apiKey +// in: header +// name: Authorization +// CookieAuth: +// description: Refresh token sent as cookie (swagger 2.0 doesn't support cookie auth) +// type: apiKey +// in: header +// name: vela_refresh_token // // swagger:meta package router diff --git a/scm/doc.go b/scm/doc.go index 1401e5a14..e30a7bcee 100644 --- a/scm/doc.go +++ b/scm/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/scm" +// import "github.com/go-vela/server/scm" package scm diff --git a/scm/github/doc.go b/scm/github/doc.go index 804a33b12..e47f97555 100644 --- a/scm/github/doc.go +++ b/scm/github/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/scm/github" +// import "github.com/go-vela/server/scm/github" package github diff --git a/secret/doc.go b/secret/doc.go index 555864d4e..b15a4b102 100644 --- a/secret/doc.go +++ b/secret/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/secret" +// import "github.com/go-vela/server/secret" package secret diff --git a/secret/native/doc.go b/secret/native/doc.go index ddf75d3de..7cd54caec 100644 --- a/secret/native/doc.go +++ b/secret/native/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/secret/native" +// import "github.com/go-vela/server/secret/native" package native diff --git a/secret/vault/doc.go b/secret/vault/doc.go index 1fe491a49..12b1d8332 100644 --- a/secret/vault/doc.go +++ b/secret/vault/doc.go @@ -7,5 +7,5 @@ // // Usage: // -// import "github.com/go-vela/server/secret/vault" +// import "github.com/go-vela/server/secret/vault" package vault From 7e9cfa2f6facfa970c35385dee7b035bd8d44e7a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Sep 2022 10:33:29 -0500 Subject: [PATCH 100/298] fix(deps): update module k8s.io/apimachinery to v0.25.0 (#686) --- go.mod | 8 +++--- go.sum | 88 ++++++---------------------------------------------------- 2 files changed, 12 insertions(+), 84 deletions(-) diff --git a/go.mod b/go.mod index 3cfd8874f..3c8b4852c 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( gorm.io/driver/postgres v1.3.8 gorm.io/driver/sqlite v1.3.6 gorm.io/gorm v1.23.8 - k8s.io/apimachinery v0.24.3 + k8s.io/apimachinery v0.25.0 ) require ( @@ -56,7 +56,7 @@ require ( github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.10.0 // indirect @@ -126,7 +126,7 @@ require ( github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect @@ -135,5 +135,5 @@ require ( google.golang.org/grpc v1.41.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/klog/v2 v2.70.1 // indirect ) diff --git a/go.sum b/go.sum index e123b14ff..06ea52028 100644 --- a/go.sum +++ b/go.sum @@ -51,7 +51,6 @@ github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030I github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -73,8 +72,6 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.44.70 h1:wrwAbqJqf+ncEK1F/bXTYpgO6zXIgQXi/2ppBgmYI9g= github.com/aws/aws-sdk-go v1.44.70/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -115,11 +112,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -127,16 +121,12 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -154,14 +144,9 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -220,7 +205,6 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -238,7 +222,6 @@ github.com/google/go-github/v44 v44.1.0/go.mod h1:iWn00mWcP6PRWHhXm0zuFJ8wbEjE5A github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -264,8 +247,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 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/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/goware/urlx v0.3.2 h1:gdoo4kBHlkqZNaf6XlQ12LGtQOmpKJrR04Rc3RnpJEo= github.com/goware/urlx v0.3.2/go.mod h1:h8uwbJy68o+tQXCGZNa9D73WN8n0r9OBae5bUnLcgjw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -319,7 +300,6 @@ github.com/hashicorp/vault/sdk v0.5.1 h1:zly/TmNgOXCGgWIRA8GojyXzG817POtVh3uzIwz github.com/hashicorp/vault/sdk v0.5.1/go.mod h1:DoGraE9kKGNcVgPmTuX357Fm6WAx1Okvde8Vp3dPDoU= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -406,7 +386,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -423,8 +402,6 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -457,14 +434,12 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go. github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -472,23 +447,12 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -556,13 +520,10 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -587,7 +548,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw= @@ -664,11 +624,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -682,7 +640,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -693,7 +650,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -703,12 +659,12 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -732,11 +688,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -751,12 +705,9 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -772,7 +723,6 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -785,17 +735,14 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -855,7 +802,6 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -871,7 +817,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -937,7 +882,6 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -978,24 +922,19 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1008,7 +947,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= @@ -1026,21 +964,11 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= -k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= +k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 56932446fdc545d44162da499f7318ad34994c77 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 14 Sep 2022 09:45:29 -0600 Subject: [PATCH 101/298] chore(linter): fix the golangci-lint errors (#693) * clean up linter * slow loris Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/admin/build.go | 2 +- api/admin/hook.go | 2 +- api/admin/repo.go | 2 +- api/admin/secret.go | 2 +- api/admin/service.go | 2 +- api/admin/step.go | 2 +- api/admin/user.go | 2 +- api/build.go | 28 ++++++++++-------- api/log.go | 8 +++--- api/metrics.go | 3 +- api/pagination.go | 2 +- api/pipeline/compile.go | 2 +- api/pipeline/expand.go | 2 +- api/pipeline/list.go | 6 ++-- api/repo.go | 5 ++-- api/service.go | 4 +-- api/step.go | 4 +-- api/stream.go | 6 ++-- api/webhook.go | 10 +++---- cmd/vela-server/main.go | 2 +- cmd/vela-server/metadata.go | 2 +- cmd/vela-server/server.go | 10 +++++-- compiler/context.go | 2 +- compiler/context_test.go | 6 ++-- compiler/native/compile.go | 12 ++++---- compiler/native/compile_test.go | 30 +++++++++---------- compiler/native/expand.go | 8 +++--- compiler/native/native.go | 2 +- compiler/native/parse.go | 5 ++-- compiler/native/parse_test.go | 35 +++++++++++------------ compiler/native/script.go | 4 +-- compiler/native/transform.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/template_test.go | 8 +++--- compiler/template/native/render_test.go | 12 ++++---- compiler/template/starlark/render.go | 2 +- compiler/template/starlark/render_test.go | 12 ++++---- compiler/template/starlark/starlark.go | 4 +-- database/database.go | 3 +- database/pipeline/list_repo.go | 2 +- database/pipeline/pipeline.go | 2 +- database/pipeline/service.go | 2 +- database/postgres/build.go | 2 +- database/postgres/ddl/secret.go | 6 ++-- database/postgres/dml/secret.go | 22 +++++++------- database/postgres/hook.go | 2 +- database/postgres/log.go | 8 +++--- database/postgres/postgres.go | 4 +-- database/postgres/repo.go | 4 +-- database/postgres/repo_list.go | 2 +- database/postgres/secret.go | 4 +-- database/postgres/secret_list.go | 2 +- database/sqlite/build.go | 2 +- database/sqlite/ddl/secret.go | 6 ++-- database/sqlite/dml/secret.go | 22 +++++++------- database/sqlite/hook.go | 2 +- database/sqlite/log.go | 8 +++--- database/sqlite/repo.go | 4 +-- database/sqlite/repo_list.go | 2 +- database/sqlite/secret.go | 4 +-- database/sqlite/secret_list.go | 2 +- database/sqlite/sqlite.go | 4 +-- database/user/create.go | 2 +- database/user/list_lite.go | 2 +- database/user/service.go | 2 +- database/user/update.go | 2 +- database/user/user.go | 2 +- mock/server/authentication.go | 2 +- mock/server/hook.go | 2 +- mock/server/secret.go | 4 +-- mock/server/server.go | 3 +- mock/server/service.go | 2 +- mock/server/step.go | 2 +- mock/server/user.go | 2 +- queue/context.go | 2 +- queue/context_test.go | 6 ++-- queue/queue.go | 3 +- queue/redis/redis.go | 4 +-- router/middleware/executors/executors.go | 4 +-- router/middleware/logger.go | 8 ++---- router/middleware/logger_test.go | 6 ++-- router/middleware/payload.go | 4 +-- router/middleware/perm/perm.go | 2 +- router/middleware/token/token.go | 6 ++-- router/middleware/token/token_test.go | 2 +- router/service.go | 2 +- router/step.go | 2 +- scm/github/access.go | 2 +- scm/github/github.go | 4 +-- scm/github/github_test.go | 4 +-- scm/github/repo.go | 2 +- scm/github/repo_test.go | 12 ++++---- scm/github/webhook.go | 5 ++-- scm/scm.go | 3 +- secret/native/native.go | 2 +- secret/secret.go | 3 +- secret/vault/count.go | 2 +- secret/vault/get.go | 2 +- secret/vault/list.go | 2 +- secret/vault/refresh.go | 4 +-- secret/vault/refresh_test.go | 6 ++-- secret/vault/vault.go | 4 +-- util/util.go | 2 +- 103 files changed, 259 insertions(+), 253 deletions(-) diff --git a/api/admin/build.go b/api/admin/build.go index e7680d66f..c04a8cacd 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/hook.go b/api/admin/hook.go index 55fa8ccad..d3ca8ade5 100644 --- a/api/admin/hook.go +++ b/api/admin/hook.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/repo.go b/api/admin/repo.go index 81916a05f..1905275d7 100644 --- a/api/admin/repo.go +++ b/api/admin/repo.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/secret.go b/api/admin/secret.go index 5ac5d57ca..8e613ea6a 100644 --- a/api/admin/secret.go +++ b/api/admin/secret.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/service.go b/api/admin/service.go index f44e7c6a3..240c346af 100644 --- a/api/admin/service.go +++ b/api/admin/service.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/step.go b/api/admin/step.go index fe097e2f0..816270c1d 100644 --- a/api/admin/step.go +++ b/api/admin/step.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/admin/user.go b/api/admin/user.go index 324e8912e..a176f30ed 100644 --- a/api/admin/user.go +++ b/api/admin/user.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code +//nolint:dupl // ignore similar code package admin import ( diff --git a/api/build.go b/api/build.go index 075a80c36..6abb48fee 100644 --- a/api/build.go +++ b/api/build.go @@ -8,7 +8,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strconv" "strings" @@ -85,7 +85,8 @@ import ( // "$ref": "#/definitions/Error" // CreateBuild represents the API handler to create a build in the configured backend. -// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity +// +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity func CreateBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) @@ -307,7 +308,7 @@ func CreateBuild(c *gin.Context) { // check if the pipeline did not already exist in the database // - // nolint: dupl // ignore duplicate code + //nolint:dupl // ignore duplicate code if pipeline == nil { pipeline = compiled pipeline.SetRepoID(r.GetID()) @@ -327,7 +328,7 @@ func CreateBuild(c *gin.Context) { // send API call to capture the created pipeline pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) if err != nil { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message retErr := fmt.Errorf("unable to create new build: failed to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -380,7 +381,8 @@ func CreateBuild(c *gin.Context) { // skipEmptyBuild checks if the build should be skipped due to it // not containing any steps besides init or clone. -// nolint: goconst // ignore init and clone constants +// +//nolint:goconst // ignore init and clone constants func skipEmptyBuild(p *pipeline.Build) string { if len(p.Stages) == 1 { if p.Stages[0].Name == "init" { @@ -792,7 +794,7 @@ func GetOrgBuilds(c *gin.Context) { } // Only show public repos to non-admins // - // nolint: goconst // ignore admin constant + //nolint:goconst // ignore admin constant if perm != "admin" { filters["visibility"] = constants.VisibilityPublic } @@ -922,7 +924,8 @@ func GetBuild(c *gin.Context) { // "$ref": "#/definitions/Error" // RestartBuild represents the API handler to restart an existing build in the configured backend. -// nolint: funlen // ignore statement count +// +//nolint:funlen // ignore statement count func RestartBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) @@ -1134,7 +1137,7 @@ func RestartBuild(c *gin.Context) { // check if the pipeline did not already exist in the database // - // nolint: dupl // ignore duplicate code + //nolint:dupl // ignore duplicate code if pipeline == nil { pipeline = compiled pipeline.SetRepoID(r.GetID()) @@ -1154,7 +1157,7 @@ func RestartBuild(c *gin.Context) { // send API call to capture the created pipeline pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) if err != nil { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message retErr := fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -1465,7 +1468,7 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { // execution. This creates all resources, like steps // and services, for the build in the configured backend. // TODO: -// - return build and error +// - return build and error. func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) @@ -1601,7 +1604,8 @@ func cleanBuild(database database.Service, b *library.Build, services []*library // "$ref": "#/definitions/Error" // CancelBuild represents the API handler to cancel a running build. -// nolint: funlen // ignore statement count +// +//nolint:funlen // ignore statement count func CancelBuild(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -1674,7 +1678,7 @@ func CancelBuild(c *gin.Context) { defer resp.Body.Close() // Read Response Body - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { retErr := fmt.Errorf("unable to read response from %s: %w", u, err) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/api/log.go b/api/log.go index 4327b296c..105ae1337 100644 --- a/api/log.go +++ b/api/log.go @@ -150,7 +150,7 @@ func GetBuildLogs(c *gin.Context) { // CreateServiceLog represents the API handler to create // the logs for a service in the configured backend. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func CreateServiceLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -445,7 +445,7 @@ func UpdateServiceLog(c *gin.Context) { // DeleteServiceLog represents the API handler to remove // the logs for a service from the configured backend. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func DeleteServiceLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -535,7 +535,7 @@ func DeleteServiceLog(c *gin.Context) { // CreateStepLog represents the API handler to create // the logs for a step in the configured backend. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func CreateStepLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -831,7 +831,7 @@ func UpdateStepLog(c *gin.Context) { // DeleteStepLog represents the API handler to remove // the logs for a step from the configured backend. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func DeleteStepLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) diff --git a/api/metrics.go b/api/metrics.go index 2a671e384..0b277d1a3 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -191,7 +191,8 @@ func CustomMetrics(c *gin.Context) { } // helper function to get the totals of resource types. -// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity +// +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity func recordGauges(c *gin.Context) { // variable to store query parameters q := MetricsQueryParameters{} diff --git a/api/pagination.go b/api/pagination.go index b9bb4c2cb..a63af8214 100644 --- a/api/pagination.go +++ b/api/pagination.go @@ -120,7 +120,7 @@ func (p *Pagination) TotalPages() int { // resolveScheme is a helper to determine the protocol scheme // c.Request.URL.Scheme does not seem to reliably provide this. // -// nolint: goconst // ignore making constant for https +//nolint:goconst // ignore making constant for https func resolveScheme(r *http.Request) string { switch { case r.Header.Get("X-Forwarded-Proto") == "https": diff --git a/api/pipeline/compile.go b/api/pipeline/compile.go index 2195b0144..6e05121bc 100644 --- a/api/pipeline/compile.go +++ b/api/pipeline/compile.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code with expand +//nolint:dupl // ignore similar code with expand package pipeline import ( diff --git a/api/pipeline/expand.go b/api/pipeline/expand.go index 0013776e0..9e0c44466 100644 --- a/api/pipeline/expand.go +++ b/api/pipeline/expand.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code with compile +//nolint:dupl // ignore similar code with compile package pipeline import ( diff --git a/api/pipeline/list.go b/api/pipeline/list.go index c6a443bd7..a2582eb08 100644 --- a/api/pipeline/list.go +++ b/api/pipeline/list.go @@ -93,7 +93,7 @@ func ListPipelines(c *gin.Context) { // capture page query parameter if present page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -104,7 +104,7 @@ func ListPipelines(c *gin.Context) { // capture per_page query parameter if present perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) if err != nil { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -114,7 +114,7 @@ func ListPipelines(c *gin.Context) { // ensure per_page isn't above or below allowed values // - // nolint: gomnd // ignore magic number + //nolint:gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) p, t, err := database.FromContext(c).ListPipelinesForRepo(r, page, perPage) diff --git a/api/repo.go b/api/repo.go index 889bf0d50..28393fd1f 100644 --- a/api/repo.go +++ b/api/repo.go @@ -69,7 +69,7 @@ import ( // CreateRepo represents the API handler to // create a repo in the configured backend. // -// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity func CreateRepo(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -634,7 +634,8 @@ func GetRepo(c *gin.Context) { // UpdateRepo represents the API handler to update // a repo in the configured backend. -// nolint: funlen // ignore line length +// +//nolint:funlen // ignore line length func UpdateRepo(c *gin.Context) { // capture middleware values o := org.Retrieve(c) diff --git a/api/service.go b/api/service.go index 3438036a1..a2136a96e 100644 --- a/api/service.go +++ b/api/service.go @@ -75,7 +75,7 @@ import ( // CreateService represents the API handler to create // a service for a build in the configured backend. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func CreateService(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -511,7 +511,7 @@ func UpdateService(c *gin.Context) { // DeleteService represents the API handler to remove // a service for a build from the configured backend. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func DeleteService(c *gin.Context) { // capture middleware values b := build.Retrieve(c) diff --git a/api/step.go b/api/step.go index a62182462..acde0f666 100644 --- a/api/step.go +++ b/api/step.go @@ -72,7 +72,7 @@ import ( // CreateStep represents the API handler to create // a step for a build in the configured backend. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func CreateStep(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -512,7 +512,7 @@ func UpdateStep(c *gin.Context) { // DeleteStep represents the API handler to remove // a step for a build from the configured backend. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func DeleteStep(c *gin.Context) { // capture middleware values b := build.Retrieve(c) diff --git a/api/stream.go b/api/stream.go index 6ffcc7989..c3425d517 100644 --- a/api/stream.go +++ b/api/stream.go @@ -81,7 +81,8 @@ const logUpdateInterval = 1 * time.Second // PostServiceStream represents the API handler that // streams service logs to the database. -// nolint: dupl // separate service/step functions for consistency with API +// +//nolint:dupl // separate service/step functions for consistency with API func PostServiceStream(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -235,7 +236,8 @@ func PostServiceStream(c *gin.Context) { // PostStepStream represents the API handler that // streams service logs to the database. -// nolint: dupl // separate service/step functions for consistency with API +// +//nolint:dupl // separate service/step functions for consistency with API func PostStepStream(c *gin.Context) { // capture middleware values b := build.Retrieve(c) diff --git a/api/webhook.go b/api/webhook.go index 7376e754f..76007bbe6 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -9,7 +9,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" "time" @@ -71,7 +71,7 @@ var baseErr = "unable to process webhook" // a webhook from a source control provider and // publish it to the configure queue. // -// nolint: funlen,gocyclo // ignore function length and cyclomatic complexity +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity func PostWebhook(c *gin.Context) { logrus.Info("webhook received") @@ -105,10 +105,10 @@ func PostWebhook(c *gin.Context) { } // add the request body to the original request - c.Request.Body = ioutil.NopCloser(&buf) + c.Request.Body = io.NopCloser(&buf) // add the request body to the duplicate request - dupRequest.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes())) + dupRequest.Body = io.NopCloser(bytes.NewReader(buf.Bytes())) // // -------------------- End of TODO: -------------------- @@ -548,7 +548,7 @@ func PostWebhook(c *gin.Context) { // send API call to capture the created pipeline pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) if err != nil { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message retErr := fmt.Errorf("%s: failed to get new pipeline %s/%s: %w", baseErr, r.GetFullName(), pipeline.GetCommit(), err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 60b89126e..f011261d4 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -23,7 +23,7 @@ import ( _ "github.com/joho/godotenv/autoload" ) -// nolint: funlen // ignore line length +//nolint:funlen // ignore line length func main() { // capture application version information v := version.New() diff --git a/cmd/vela-server/metadata.go b/cmd/vela-server/metadata.go index 93f821d0c..4ce86ea31 100644 --- a/cmd/vela-server/metadata.go +++ b/cmd/vela-server/metadata.go @@ -98,7 +98,7 @@ func metadataSource(c *cli.Context) (*types.Source, error) { // helper function to capture the Vela metadata from the CLI arguments. // -// nolint: unparam // ignore unparam for now +//nolint:unparam // ignore unparam for now func metadataVela(c *cli.Context) (*types.Vela, error) { logrus.Trace("Creating Vela metadata from CLI configuration") diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 80d68f313..114639501 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -86,7 +86,7 @@ func server(c *cli.Context) error { router := router.Load( middleware.Compiler(compiler), middleware.Database(database), - middleware.Logger(logrus.StandardLogger(), time.RFC3339, true), + middleware.Logger(logrus.StandardLogger(), time.RFC3339), middleware.Metadata(metadata), middleware.Queue(queue), middleware.RequestVersion, @@ -118,7 +118,11 @@ func server(c *cli.Context) error { } // gin expects the address to be ":" ie ":8080" - srv := &http.Server{Addr: fmt.Sprintf(":%s", port), Handler: router} + srv := &http.Server{ + Addr: fmt.Sprintf(":%s", port), + Handler: router, + ReadHeaderTimeout: 60 * time.Second, + } logrus.Infof("running server on %s", addr.Host) go func() { @@ -129,7 +133,7 @@ func server(c *cli.Context) error { } }() - // nolint: gosimple // ignore this for now + //nolint:gosimple // ignore this for now for { select { case <-tomb.Dying(): diff --git a/compiler/context.go b/compiler/context.go index 41196c22a..2a5622628 100644 --- a/compiler/context.go +++ b/compiler/context.go @@ -54,7 +54,7 @@ func FromGinContext(c *gin.Context) Engine { func WithContext(c context.Context, e Engine) context.Context { // set the compiler Engine in the context.Context // - // nolint: revive,staticcheck // ignore using string with context value + //nolint:revive,staticcheck // ignore using string with context value return context.WithValue(c, key, e) } diff --git a/compiler/context_test.go b/compiler/context_test.go index cc4fbee7a..20ef576a2 100644 --- a/compiler/context_test.go +++ b/compiler/context_test.go @@ -22,7 +22,7 @@ func TestCompiler_FromContext(t *testing.T) { want Engine }{ { - // nolint: staticcheck, revive // ignore using string with context value + //nolint: staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, _engine), want: _engine, }, @@ -31,7 +31,7 @@ func TestCompiler_FromContext(t *testing.T) { want: nil, }, { - // nolint: staticcheck, revive // ignore using string with context value + //nolint: staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, "foo"), want: nil, }, @@ -92,7 +92,7 @@ func TestCompiler_WithContext(t *testing.T) { // setup types var _engine Engine - // nolint: staticcheck, revive // ignore using string with context value + //nolint: staticcheck, revive // ignore using string with context value want := context.WithValue(context.Background(), key, _engine) // run test diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 9a2b0eb51..709862e44 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -9,7 +9,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" "time" @@ -266,12 +266,12 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu case len(parsed.Secrets) > 0: newPipeline.Secrets = append(newPipeline.Secrets, parsed.Secrets...) default: - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message return nil, fmt.Errorf("empty template %s provided: template must contain secrets, services, stages or steps", template.Name) } if len(newPipeline.Stages) > 0 && len(newPipeline.Steps) > 0 { - // nolint: lll // ignore long line length due to error message + //nolint:lll // ignore long line length due to error message return nil, fmt.Errorf("invalid template %s provided: templates cannot mix stages and steps", template.Name) } } @@ -287,7 +287,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu // compileSteps executes the workflow for converting a YAML pipeline into an executable struct. // -// nolint:dupl,lll // linter thinks the steps and stages workflows are identical +//nolint:dupl,lll // linter thinks the steps and stages workflows are identical func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) { var err error @@ -384,7 +384,7 @@ func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls // compileStages executes the workflow for converting a YAML pipeline into an executable struct. // -// nolint:dupl,lll // linter thinks the steps and stages workflows are identical +//nolint:dupl,lll // linter thinks the steps and stages workflows are identical func (c *client) compileStages(p *yaml.Build, _pipeline *library.Pipeline, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*pipeline.Build, *library.Pipeline, error) { var err error @@ -547,7 +547,7 @@ func (c *client) modifyConfig(build *yaml.Build, libraryBuild *library.Build, re return nil, fmt.Errorf("modification endpoint returned status code %v", resp.StatusCode) } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read payload: %w", err) } diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 780586ee8..0a7d64d7c 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -7,9 +7,9 @@ package native import ( "flag" "fmt" - "io/ioutil" "net/http" "net/http/httptest" + "os" "path/filepath" "github.com/go-vela/types/constants" @@ -242,7 +242,7 @@ func TestNative_Compile_StagesPipeline(t *testing.T) { } // run test - yaml, err := ioutil.ReadFile("testdata/stages_pipeline.yml") + yaml, err := os.ReadFile("testdata/stages_pipeline.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -297,7 +297,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { number := 1 // run test - yaml, err := ioutil.ReadFile("testdata/stages_pipeline.yml") + yaml, err := os.ReadFile("testdata/stages_pipeline.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -365,7 +365,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { number := 1 // run test - yaml, err := ioutil.ReadFile("testdata/steps_pipeline.yml") + yaml, err := os.ReadFile("testdata/steps_pipeline.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -572,7 +572,7 @@ func TestNative_Compile_StepsPipeline(t *testing.T) { } // run test - yaml, err := ioutil.ReadFile("testdata/steps_pipeline.yml") + yaml, err := os.ReadFile("testdata/steps_pipeline.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -823,7 +823,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { } // run test - yaml, err := ioutil.ReadFile("testdata/stages_pipeline_template.yml") + yaml, err := os.ReadFile("testdata/stages_pipeline_template.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1060,7 +1060,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { } // run test - yaml, err := ioutil.ReadFile("testdata/steps_pipeline_template.yml") + yaml, err := os.ReadFile("testdata/steps_pipeline_template.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1136,7 +1136,7 @@ func TestNative_Compile_InvalidType(t *testing.T) { dockerEnv["PARAMETER_TAGS"] = "latest,dev" // run test - invalidYaml, err := ioutil.ReadFile("testdata/invalid_type.yml") + invalidYaml, err := os.ReadFile("testdata/invalid_type.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1319,7 +1319,7 @@ func TestNative_Compile_Clone(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // run test - yaml, err := ioutil.ReadFile(tt.args.file) + yaml, err := os.ReadFile(tt.args.file) if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1522,7 +1522,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // run test - yaml, err := ioutil.ReadFile(tt.args.file) + yaml, err := os.ReadFile(tt.args.file) if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1556,7 +1556,7 @@ func TestNative_Compile_NoStepsorStages(t *testing.T) { number := 1 // run test - yaml, err := ioutil.ReadFile("testdata/metadata.yml") + yaml, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1588,7 +1588,7 @@ func TestNative_Compile_StepsandStages(t *testing.T) { number := 1 // run test - yaml, err := ioutil.ReadFile("testdata/steps_and_stages.yml") + yaml, err := os.ReadFile("testdata/steps_and_stages.yml") if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -1869,7 +1869,7 @@ func Test_client_modifyConfig(t *testing.T) { } func convertFileToGithubResponse(file string) (github.RepositoryContent, error) { - body, err := ioutil.ReadFile(filepath.Join("testdata", file)) + body, err := os.ReadFile(filepath.Join("testdata", file)) if err != nil { return github.RepositoryContent{}, err } @@ -2633,7 +2633,7 @@ func Test_Compile_Inline(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - yaml, err := ioutil.ReadFile(tt.args.file) + yaml, err := os.ReadFile(tt.args.file) if err != nil { t.Errorf("Reading yaml file return err: %v", err) } @@ -2972,7 +2972,7 @@ func Test_CompileLite(t *testing.T) { compiler.WithRepo(&library.Repo{PipelineType: &tt.args.pipelineType}) } - yaml, err := ioutil.ReadFile(tt.args.file) + yaml, err := os.ReadFile(tt.args.file) if err != nil { t.Errorf("Reading yaml file return err: %v", err) } diff --git a/compiler/native/expand.go b/compiler/native/expand.go index e6a8bcdd8..c4395d6dc 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -219,17 +219,17 @@ func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) { return bytes, nil } -// nolint: lll // ignore long line length due to input arguments +//nolint:lll // ignore long line length due to input arguments func (c *client) mergeTemplate(bytes []byte, tmpl *yaml.Template, step *yaml.Step) (*yaml.Build, error) { switch tmpl.Format { case constants.PipelineTypeGo, "golang", "": - // nolint: lll // ignore long line length due to return + //nolint:lll // ignore long line length due to return return native.Render(string(bytes), step.Name, step.Template.Name, step.Environment, step.Template.Variables) case constants.PipelineTypeStarlark: - // nolint: lll // ignore long line length due to return + //nolint:lll // ignore long line length due to return return starlark.Render(string(bytes), step.Name, step.Template.Name, step.Environment, step.Template.Variables) default: - // nolint: lll // ignore long line length due to return + //nolint:lll // ignore long line length due to return return &yaml.Build{}, fmt.Errorf("format of %s is unsupported", tmpl.Format) } } diff --git a/compiler/native/native.go b/compiler/native/native.go index 4c0ca1d42..2e9d90357 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -43,7 +43,7 @@ type client struct { // New returns a Pipeline implementation that integrates with the supported registries. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(ctx *cli.Context) (*client, error) { logrus.Debug("Creating registry clients from CLI configuration") diff --git a/compiler/native/parse.go b/compiler/native/parse.go index 8ae8ac660..1d9f1206b 100644 --- a/compiler/native/parse.go +++ b/compiler/native/parse.go @@ -7,7 +7,6 @@ package native import ( "fmt" "io" - "io/ioutil" "os" "github.com/go-vela/server/compiler/template/native" @@ -158,7 +157,7 @@ func ParsePathRaw(p string) (string, error) { // ParseReader converts an io.Reader into a yaml configuration. func ParseReader(r io.Reader) (*types.Build, []byte, error) { // read all the bytes from the reader - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return nil, nil, fmt.Errorf("unable to read bytes for yaml: %w", err) } @@ -169,7 +168,7 @@ func ParseReader(r io.Reader) (*types.Build, []byte, error) { // ParseReaderRaw converts an io.Reader into a yaml configuration. func ParseReaderRaw(r io.Reader) (string, error) { // read all the bytes from the reader - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err != nil { return "", fmt.Errorf("unable to read bytes for yaml: %w", err) } diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index 1c5016a50..bdd76f2e1 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -8,7 +8,6 @@ import ( "bytes" "errors" "flag" - "io/ioutil" "os" "reflect" "testing" @@ -36,7 +35,7 @@ func TestNative_Parse_Metadata_Bytes(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -133,7 +132,7 @@ func TestNative_Parse_Metadata_Reader(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -161,7 +160,7 @@ func TestNative_Parse_Metadata_String(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -208,7 +207,7 @@ func TestNative_Parse_Parameters(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/parameters.yml") + b, err := os.ReadFile("testdata/parameters.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -334,7 +333,7 @@ func TestNative_Parse_StagesPipeline(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/stages_pipeline.yml") + b, err := os.ReadFile("testdata/stages_pipeline.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -431,7 +430,7 @@ func TestNative_Parse_StepsPipeline(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/steps_pipeline.yml") + b, err := os.ReadFile("testdata/steps_pipeline.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -494,7 +493,7 @@ func TestNative_Parse_Secrets(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/secrets.yml") + b, err := os.ReadFile("testdata/secrets.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -570,7 +569,7 @@ func TestNative_Parse_Stages(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/stages.yml") + b, err := os.ReadFile("testdata/stages.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -628,7 +627,7 @@ func TestNative_Parse_Steps(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/steps.yml") + b, err := os.ReadFile("testdata/steps.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -656,7 +655,7 @@ func TestNative_ParseBytes_Metadata(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -674,7 +673,7 @@ func TestNative_ParseBytes_Metadata(t *testing.T) { func TestNative_ParseBytes_Invalid(t *testing.T) { // run test - b, err := ioutil.ReadFile("testdata/invalid.yml") + b, err := os.ReadFile("testdata/invalid.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -788,7 +787,7 @@ func TestNative_ParseReader_Metadata(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -829,7 +828,7 @@ func TestNative_ParseString_Metadata(t *testing.T) { } // run test - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -893,7 +892,7 @@ func Test_client_Parse(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - content, err := ioutil.ReadFile(tt.args.file) + content, err := os.ReadFile(tt.args.file) if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -920,7 +919,7 @@ func Test_client_Parse(t *testing.T) { } func Test_client_ParseRaw(t *testing.T) { - expected, err := ioutil.ReadFile("testdata/metadata.yml") + expected, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -949,7 +948,7 @@ func Test_client_ParseRaw(t *testing.T) { var err error switch tt.args.kind { case "byte": - content, err = ioutil.ReadFile("testdata/metadata.yml") + content, err = os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -959,7 +958,7 @@ func Test_client_ParseRaw(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } case "ioreader": - b, err := ioutil.ReadFile("testdata/metadata.yml") + b, err := os.ReadFile("testdata/metadata.yml") if err != nil { t.Errorf("ParseReader returned err: %v", err) } diff --git a/compiler/native/script.go b/compiler/native/script.go index 83ff32f84..8256ee5a1 100644 --- a/compiler/native/script.go +++ b/compiler/native/script.go @@ -39,7 +39,7 @@ func (c *client) ScriptSteps(s yaml.StepSlice) (yaml.StepSlice, error) { } // set the default home - // nolint: goconst // ignore making this a constant for now + //nolint:goconst // ignore making this a constant for now home := "/root" // override the home value if user is defined // TODO: @@ -60,7 +60,7 @@ func (c *client) ScriptSteps(s yaml.StepSlice) (yaml.StepSlice, error) { // set the environment variables for the step step.Environment["VELA_BUILD_SCRIPT"] = script step.Environment["HOME"] = home - // nolint: goconst // ignore making this a constant for now + //nolint:goconst // ignore making this a constant for now step.Environment["SHELL"] = "/bin/sh" } diff --git a/compiler/native/transform.go b/compiler/native/transform.go index 85be86d0b..4742ae700 100644 --- a/compiler/native/transform.go +++ b/compiler/native/transform.go @@ -33,7 +33,7 @@ const ( // default ID for secrets in a pipeline. // format: `secret____` // - // nolint: gosec // ignore gosec keying off of secret as no credentials are hardcoded + //nolint:gosec // ignore gosec keying off of secret as no credentials are hardcoded secretID = "secret_%s_%s_%d_%s" ) diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index 35435c33a..ab7f13d45 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -27,7 +27,7 @@ type client struct { // New returns a Registry implementation that integrates // with GitHub or a GitHub Enterprise instance. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(address, token string) (*client, error) { // create the client object c := &client{ diff --git a/compiler/registry/github/template_test.go b/compiler/registry/github/template_test.go index 16e9ee696..af59a6d61 100644 --- a/compiler/registry/github/template_test.go +++ b/compiler/registry/github/template_test.go @@ -5,9 +5,9 @@ package github import ( - "io/ioutil" "net/http" "net/http/httptest" + "os" "reflect" "testing" @@ -49,7 +49,7 @@ func TestGithub_Template(t *testing.T) { Name: "template.yml", } - want, err := ioutil.ReadFile("testdata/template.yml") + want, err := os.ReadFile("testdata/template.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -111,7 +111,7 @@ func TestGithub_TemplateSourceRef(t *testing.T) { Ref: "main", } - want, err := ioutil.ReadFile("testdata/template.yml") + want, err := os.ReadFile("testdata/template.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } @@ -176,7 +176,7 @@ func TestGithub_TemplateEmptySourceRef(t *testing.T) { Name: "template.yml", } - want, err := ioutil.ReadFile("testdata/template.yml") + want, err := os.ReadFile("testdata/template.yml") if err != nil { t.Errorf("Reading file returned err: %v", err) } diff --git a/compiler/template/native/render_test.go b/compiler/template/native/render_test.go index 574f9b10f..260b3c116 100644 --- a/compiler/template/native/render_test.go +++ b/compiler/template/native/render_test.go @@ -5,7 +5,7 @@ package native import ( - "io/ioutil" + "os" "testing" goyaml "github.com/buildkite/yaml" @@ -43,7 +43,7 @@ func TestNative_Render(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sFile, err := ioutil.ReadFile(tt.args.velaFile) + sFile, err := os.ReadFile(tt.args.velaFile) if err != nil { t.Error(err) } @@ -56,7 +56,7 @@ func TestNative_Render(t *testing.T) { "VELA_REPO_FULL_NAME": "octocat/hello-world", } - tmpl, err := ioutil.ReadFile(tt.args.templateFile) + tmpl, err := os.ReadFile(tt.args.templateFile) if err != nil { t.Error(err) } @@ -68,7 +68,7 @@ func TestNative_Render(t *testing.T) { } if tt.wantErr != true { - wFile, err := ioutil.ReadFile(tt.wantFile) + wFile, err := os.ReadFile(tt.wantFile) if err != nil { t.Error(err) } @@ -117,7 +117,7 @@ func TestNative_RenderBuild(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sFile, err := ioutil.ReadFile(tt.args.velaFile) + sFile, err := os.ReadFile(tt.args.velaFile) if err != nil { t.Error(err) } @@ -132,7 +132,7 @@ func TestNative_RenderBuild(t *testing.T) { } if tt.wantErr != true { - wFile, err := ioutil.ReadFile(tt.wantFile) + wFile, err := os.ReadFile(tt.wantFile) if err != nil { t.Error(err) } diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index 4ec617d18..e85eafd3a 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -136,7 +136,7 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM // RenderBuild renders the templated build. // -// nolint: lll // ignore function length due to input args +//nolint:lll // ignore function length due to input args func RenderBuild(b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { config := new(types.Build) diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index 3d64874c9..b97de2c54 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -5,7 +5,7 @@ package starlark import ( - "io/ioutil" + "os" "testing" goyaml "github.com/buildkite/yaml" @@ -35,7 +35,7 @@ func TestStarlark_Render(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sFile, err := ioutil.ReadFile(tt.args.velaFile) + sFile, err := os.ReadFile(tt.args.velaFile) if err != nil { t.Error(err) } @@ -48,7 +48,7 @@ func TestStarlark_Render(t *testing.T) { "VELA_REPO_FULL_NAME": "octocat/hello-world", } - tmpl, err := ioutil.ReadFile(tt.args.starlarkFile) + tmpl, err := os.ReadFile(tt.args.starlarkFile) if err != nil { t.Error(err) } @@ -60,7 +60,7 @@ func TestStarlark_Render(t *testing.T) { } if tt.wantErr != true { - wFile, err := ioutil.ReadFile(tt.wantFile) + wFile, err := os.ReadFile(tt.wantFile) if err != nil { t.Error(err) } @@ -109,7 +109,7 @@ func TestNative_RenderBuild(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sFile, err := ioutil.ReadFile(tt.args.velaFile) + sFile, err := os.ReadFile(tt.args.velaFile) if err != nil { t.Error(err) } @@ -124,7 +124,7 @@ func TestNative_RenderBuild(t *testing.T) { } if tt.wantErr != true { - wFile, err := ioutil.ReadFile(tt.wantFile) + wFile, err := os.ReadFile(tt.wantFile) if err != nil { t.Error(err) } diff --git a/compiler/template/starlark/starlark.go b/compiler/template/starlark/starlark.go index 7df72e250..0299ef259 100644 --- a/compiler/template/starlark/starlark.go +++ b/compiler/template/starlark/starlark.go @@ -33,7 +33,7 @@ var ( // // https://github.com/wonderix/shalm/blob/899b8f7787883d40619eefcc39bd12f42a09b5e7/pkg/shalm/convert.go#L14-L85 // -// nolint: gocyclo // ignore complexity +//nolint:gocyclo // ignore complexity func toStarlark(value interface{}) (starlark.Value, error) { logrus.Tracef("converting %v to starlark type", value) @@ -152,7 +152,7 @@ func toStarlark(value interface{}) (starlark.Value, error) { // if/when we try to return values it breaks the recursion. Panics were swapped to error // returns from implementation. // -// nolint: gocyclo // ignore cyclomatic complexity +//nolint:gocyclo // ignore cyclomatic complexity func writeJSON(out *bytes.Buffer, v starlark.Value) error { logrus.Tracef("converting %v to JSON", v) diff --git a/database/database.go b/database/database.go index 884d8a734..a6e8c8958 100644 --- a/database/database.go +++ b/database/database.go @@ -12,8 +12,6 @@ import ( "github.com/sirupsen/logrus" ) -// nolint: godot // top level comment ends in a list -// // New creates and returns a Vela service capable of // integrating with the configured database provider. // @@ -21,6 +19,7 @@ import ( // // * Postgres // * Sqlite +// . func New(s *Setup) (Service, error) { // validate the setup being provided // diff --git a/database/pipeline/list_repo.go b/database/pipeline/list_repo.go index e90db6700..609dcc340 100644 --- a/database/pipeline/list_repo.go +++ b/database/pipeline/list_repo.go @@ -13,7 +13,7 @@ import ( // ListPipelinesForRepo gets a list of pipelines by repo ID from the database. // -// nolint: lll // ignore long line length due to variable names +//nolint:lll // ignore long line length due to variable names func (e *engine) ListPipelinesForRepo(r *library.Repo, page, perPage int) ([]*library.Pipeline, int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/pipeline/pipeline.go b/database/pipeline/pipeline.go index 2a305d8e4..b99bdbfef 100644 --- a/database/pipeline/pipeline.go +++ b/database/pipeline/pipeline.go @@ -41,7 +41,7 @@ type ( // New creates and returns a Vela service for integrating with pipelines in the database. // -// nolint: revive // ignore returning unexported engine +//nolint:revive // ignore returning unexported engine func New(opts ...EngineOpt) (*engine, error) { // create new Pipeline engine e := new(engine) diff --git a/database/pipeline/service.go b/database/pipeline/service.go index 8ff5ec8d5..c619fda46 100644 --- a/database/pipeline/service.go +++ b/database/pipeline/service.go @@ -11,7 +11,7 @@ import ( // PipelineService represents the Vela interface for pipeline // functions with the supported Database backends. // -// nolint: revive // ignore name stutter +//nolint:revive // ignore name stutter type PipelineService interface { // Pipeline Data Definition Language Functions // diff --git a/database/postgres/build.go b/database/postgres/build.go index 84e4d2140..69e898d90 100644 --- a/database/postgres/build.go +++ b/database/postgres/build.go @@ -19,7 +19,7 @@ import ( // GetBuild gets a build by number and repo ID from the database. // -// nolint: dupl // ignore similar code with hook +//nolint:dupl // ignore similar code with hook func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "build": number, diff --git a/database/postgres/ddl/secret.go b/database/postgres/ddl/secret.go index 6139c783a..e6bbcc6a0 100644 --- a/database/postgres/ddl/secret.go +++ b/database/postgres/ddl/secret.go @@ -33,7 +33,7 @@ secrets ( // CreateSecretTypeOrgRepo represents a query to create an // index on the secrets table for the type, org and repo columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrgRepo = ` CREATE INDEX IF NOT EXISTS @@ -44,7 +44,7 @@ ON secrets (type, org, repo); // CreateSecretTypeOrgTeam represents a query to create an // index on the secrets table for the type, org and team columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrgTeam = ` CREATE INDEX IF NOT EXISTS @@ -55,7 +55,7 @@ ON secrets (type, org, team); // CreateSecretTypeOrg represents a query to create an // index on the secrets table for the type, and org columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrg = ` CREATE INDEX IF NOT EXISTS diff --git a/database/postgres/dml/secret.go b/database/postgres/dml/secret.go index 9fe094a51..28d7607bc 100644 --- a/database/postgres/dml/secret.go +++ b/database/postgres/dml/secret.go @@ -8,7 +8,7 @@ const ( // ListSecrets represents a query to // list all secrets in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListSecrets = ` SELECT * FROM secrets; @@ -17,7 +17,7 @@ FROM secrets; // ListOrgSecrets represents a query to list all // secrets for a type and org in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListOrgSecrets = ` SELECT * FROM secrets @@ -31,7 +31,7 @@ OFFSET ?; // ListRepoSecrets represents a query to list all // secrets for a type, org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListRepoSecrets = ` SELECT * FROM secrets @@ -46,7 +46,7 @@ OFFSET ?; // ListSharedSecrets represents a query to list all // secrets for a type, org and team in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListSharedSecrets = ` SELECT * FROM secrets @@ -61,7 +61,7 @@ OFFSET ?; // SelectOrgSecretsCount represents a query to select the // count of org secrets for an org in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectOrgSecretsCount = ` SELECT count(*) as count FROM secrets @@ -72,7 +72,7 @@ AND org = ?; // SelectRepoSecretsCount represents a query to select the // count of repo secrets for an org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectRepoSecretsCount = ` SELECT count(*) as count FROM secrets @@ -84,7 +84,7 @@ AND repo = ?; // SelectSharedSecretsCount represents a query to select the // count of shared secrets for an org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectSharedSecretsCount = ` SELECT count(*) as count FROM secrets @@ -96,7 +96,7 @@ AND team = ?; // SelectOrgSecret represents a query to select a // secret for an org and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectOrgSecret = ` SELECT * FROM secrets @@ -109,7 +109,7 @@ LIMIT 1; // SelectRepoSecret represents a query to select a // secret for an org, repo and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectRepoSecret = ` SELECT * FROM secrets @@ -123,7 +123,7 @@ LIMIT 1; // SelectSharedSecret represents a query to select a // secret for an org, team and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectSharedSecret = ` SELECT * FROM secrets @@ -137,7 +137,7 @@ LIMIT 1; // DeleteSecret represents a query to // remove a secret from the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive DeleteSecret = ` DELETE FROM secrets diff --git a/database/postgres/hook.go b/database/postgres/hook.go index 9bd5f8a2d..5994e5e20 100644 --- a/database/postgres/hook.go +++ b/database/postgres/hook.go @@ -19,7 +19,7 @@ import ( // GetHook gets a hook by number and repo ID from the database. // -// nolint: dupl // ignore similar code with build +//nolint:dupl // ignore similar code with build func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { c.Logger.WithFields(logrus.Fields{ "hook": number, diff --git a/database/postgres/log.go b/database/postgres/log.go index 840f5f154..fe23549eb 100644 --- a/database/postgres/log.go +++ b/database/postgres/log.go @@ -59,7 +59,7 @@ func (c *client) GetBuildLogs(id int64) ([]*library.Log, error) { // GetStepLog gets a log by unique ID from the database. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func (c *client) GetStepLog(id int64) (*library.Log, error) { c.Logger.Tracef("getting log for step %d from the database", id) @@ -97,7 +97,7 @@ func (c *client) GetStepLog(id int64) (*library.Log, error) { // GetServiceLog gets a log by unique ID from the database. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func (c *client) GetServiceLog(id int64) (*library.Log, error) { c.Logger.Tracef("getting log for service %d from the database", id) @@ -135,7 +135,7 @@ func (c *client) GetServiceLog(id int64) (*library.Log, error) { // CreateLog creates a new log in the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) CreateLog(l *library.Log) error { // check if the log entry is for a step if l.GetStepID() > 0 { @@ -169,7 +169,7 @@ func (c *client) CreateLog(l *library.Log) error { // UpdateLog updates a log in the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) UpdateLog(l *library.Log) error { // check if the log entry is for a step if l.GetStepID() > 0 { diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index cedb34c49..a2a446947 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -52,7 +52,7 @@ type ( // New returns a Database implementation that integrates with a Postgres instance. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new Postgres client c := new(client) @@ -109,7 +109,7 @@ func New(opts ...ClientOpt) (*client, error) { // // This function is intended for running tests only. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func NewTest() (*client, sqlmock.Sqlmock, error) { // create new Postgres client c := new(client) diff --git a/database/postgres/repo.go b/database/postgres/repo.go index 409a2b7ef..1f39f3c1a 100644 --- a/database/postgres/repo.go +++ b/database/postgres/repo.go @@ -59,7 +59,7 @@ func (c *client) GetRepo(org, name string) (*library.Repo, error) { // CreateRepo creates a new repo in the database. // -// nolint: dupl // ignore similar code with update +//nolint:dupl // ignore similar code with update func (c *client) CreateRepo(r *library.Repo) error { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), @@ -91,7 +91,7 @@ func (c *client) CreateRepo(r *library.Repo) error { // UpdateRepo updates a repo in the database. // -// nolint: dupl // ignore similar code with create +//nolint:dupl // ignore similar code with create func (c *client) UpdateRepo(r *library.Repo) error { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/postgres/repo_list.go b/database/postgres/repo_list.go index 3cafb1a43..7b10a168d 100644 --- a/database/postgres/repo_list.go +++ b/database/postgres/repo_list.go @@ -14,7 +14,7 @@ import ( // GetRepoList gets a list of all repos from the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) GetRepoList() ([]*library.Repo, error) { c.Logger.Trace("listing repos from the database") diff --git a/database/postgres/secret.go b/database/postgres/secret.go index 0d7433c8f..ee28853ca 100644 --- a/database/postgres/secret.go +++ b/database/postgres/secret.go @@ -111,7 +111,7 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) // CreateSecret creates a new secret in the database. // -// nolint: dupl // ignore similar code with update +//nolint:dupl // ignore similar code with update func (c *client) CreateSecret(s *library.Secret) error { // create log fields from secret metadata fields := logrus.Fields{ @@ -159,7 +159,7 @@ func (c *client) CreateSecret(s *library.Secret) error { // UpdateSecret updates a secret in the database. // -// nolint: dupl // ignore similar code with create +//nolint:dupl // ignore similar code with create func (c *client) UpdateSecret(s *library.Secret) error { // create log fields from secret metadata fields := logrus.Fields{ diff --git a/database/postgres/secret_list.go b/database/postgres/secret_list.go index 6ae3dfb2b..2913f6eef 100644 --- a/database/postgres/secret_list.go +++ b/database/postgres/secret_list.go @@ -17,7 +17,7 @@ import ( // GetSecretList gets a list of all secrets from the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) GetSecretList() ([]*library.Secret, error) { c.Logger.Tracef("listing secrets from the database") diff --git a/database/sqlite/build.go b/database/sqlite/build.go index 5a3347b09..b32f85f53 100644 --- a/database/sqlite/build.go +++ b/database/sqlite/build.go @@ -19,7 +19,7 @@ import ( // GetBuild gets a build by number and repo ID from the database. // -// nolint: dupl // ignore similar code with hook +//nolint:dupl // ignore similar code with hook func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "build": number, diff --git a/database/sqlite/ddl/secret.go b/database/sqlite/ddl/secret.go index 4348ec1de..a23bad110 100644 --- a/database/sqlite/ddl/secret.go +++ b/database/sqlite/ddl/secret.go @@ -33,7 +33,7 @@ secrets ( // CreateSecretTypeOrgRepo represents a query to create an // index on the secrets table for the type, org and repo columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrgRepo = ` CREATE INDEX IF NOT EXISTS @@ -44,7 +44,7 @@ ON secrets (type, org, repo); // CreateSecretTypeOrgTeam represents a query to create an // index on the secrets table for the type, org and team columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrgTeam = ` CREATE INDEX IF NOT EXISTS @@ -55,7 +55,7 @@ ON secrets (type, org, team); // CreateSecretTypeOrg represents a query to create an // index on the secrets table for the type, and org columns. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive CreateSecretTypeOrg = ` CREATE INDEX IF NOT EXISTS diff --git a/database/sqlite/dml/secret.go b/database/sqlite/dml/secret.go index 9fe094a51..28d7607bc 100644 --- a/database/sqlite/dml/secret.go +++ b/database/sqlite/dml/secret.go @@ -8,7 +8,7 @@ const ( // ListSecrets represents a query to // list all secrets in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListSecrets = ` SELECT * FROM secrets; @@ -17,7 +17,7 @@ FROM secrets; // ListOrgSecrets represents a query to list all // secrets for a type and org in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListOrgSecrets = ` SELECT * FROM secrets @@ -31,7 +31,7 @@ OFFSET ?; // ListRepoSecrets represents a query to list all // secrets for a type, org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListRepoSecrets = ` SELECT * FROM secrets @@ -46,7 +46,7 @@ OFFSET ?; // ListSharedSecrets represents a query to list all // secrets for a type, org and team in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive ListSharedSecrets = ` SELECT * FROM secrets @@ -61,7 +61,7 @@ OFFSET ?; // SelectOrgSecretsCount represents a query to select the // count of org secrets for an org in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectOrgSecretsCount = ` SELECT count(*) as count FROM secrets @@ -72,7 +72,7 @@ AND org = ?; // SelectRepoSecretsCount represents a query to select the // count of repo secrets for an org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectRepoSecretsCount = ` SELECT count(*) as count FROM secrets @@ -84,7 +84,7 @@ AND repo = ?; // SelectSharedSecretsCount represents a query to select the // count of shared secrets for an org and repo in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectSharedSecretsCount = ` SELECT count(*) as count FROM secrets @@ -96,7 +96,7 @@ AND team = ?; // SelectOrgSecret represents a query to select a // secret for an org and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectOrgSecret = ` SELECT * FROM secrets @@ -109,7 +109,7 @@ LIMIT 1; // SelectRepoSecret represents a query to select a // secret for an org, repo and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectRepoSecret = ` SELECT * FROM secrets @@ -123,7 +123,7 @@ LIMIT 1; // SelectSharedSecret represents a query to select a // secret for an org, team and name in the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive SelectSharedSecret = ` SELECT * FROM secrets @@ -137,7 +137,7 @@ LIMIT 1; // DeleteSecret represents a query to // remove a secret from the database. // - // nolint: gosec // ignore false positive + //nolint:gosec // ignore false positive DeleteSecret = ` DELETE FROM secrets diff --git a/database/sqlite/hook.go b/database/sqlite/hook.go index 5ebd054e3..517a08c06 100644 --- a/database/sqlite/hook.go +++ b/database/sqlite/hook.go @@ -19,7 +19,7 @@ import ( // GetHook gets a hook by number and repo ID from the database. // -// nolint: dupl // ignore similar code with build +//nolint:dupl // ignore similar code with build func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { c.Logger.WithFields(logrus.Fields{ "hook": number, diff --git a/database/sqlite/log.go b/database/sqlite/log.go index aed36ca20..037bdcc08 100644 --- a/database/sqlite/log.go +++ b/database/sqlite/log.go @@ -59,7 +59,7 @@ func (c *client) GetBuildLogs(id int64) ([]*library.Log, error) { // GetStepLog gets a log by unique ID from the database. // -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service func (c *client) GetStepLog(id int64) (*library.Log, error) { c.Logger.Tracef("getting log for step %d from the database", id) @@ -97,7 +97,7 @@ func (c *client) GetStepLog(id int64) (*library.Log, error) { // GetServiceLog gets a log by unique ID from the database. // -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step func (c *client) GetServiceLog(id int64) (*library.Log, error) { c.Logger.Tracef("getting log for service %d from the database", id) @@ -135,7 +135,7 @@ func (c *client) GetServiceLog(id int64) (*library.Log, error) { // CreateLog creates a new log in the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) CreateLog(l *library.Log) error { // check if the log entry is for a step if l.GetStepID() > 0 { @@ -169,7 +169,7 @@ func (c *client) CreateLog(l *library.Log) error { // UpdateLog updates a log in the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) UpdateLog(l *library.Log) error { // check if the log entry is for a step if l.GetStepID() > 0 { diff --git a/database/sqlite/repo.go b/database/sqlite/repo.go index 76767c277..0bcac5983 100644 --- a/database/sqlite/repo.go +++ b/database/sqlite/repo.go @@ -59,7 +59,7 @@ func (c *client) GetRepo(org, name string) (*library.Repo, error) { // CreateRepo creates a new repo in the database. // -// nolint: dupl // ignore similar code with update +//nolint:dupl // ignore similar code with update func (c *client) CreateRepo(r *library.Repo) error { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), @@ -91,7 +91,7 @@ func (c *client) CreateRepo(r *library.Repo) error { // UpdateRepo updates a repo in the database. // -// nolint: dupl // ignore similar code with create +//nolint:dupl // ignore similar code with create func (c *client) UpdateRepo(r *library.Repo) error { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/sqlite/repo_list.go b/database/sqlite/repo_list.go index b4807d1ca..6b6ae6f55 100644 --- a/database/sqlite/repo_list.go +++ b/database/sqlite/repo_list.go @@ -14,7 +14,7 @@ import ( // GetRepoList gets a list of all repos from the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) GetRepoList() ([]*library.Repo, error) { c.Logger.Trace("listing repos from the database") diff --git a/database/sqlite/secret.go b/database/sqlite/secret.go index b0c84d4a3..d4e25572a 100644 --- a/database/sqlite/secret.go +++ b/database/sqlite/secret.go @@ -111,7 +111,7 @@ func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) // CreateSecret creates a new secret in the database. // -// nolint: dupl // ignore similar code with update +//nolint:dupl // ignore similar code with update func (c *client) CreateSecret(s *library.Secret) error { // create log fields from secret metadata fields := logrus.Fields{ @@ -159,7 +159,7 @@ func (c *client) CreateSecret(s *library.Secret) error { // UpdateSecret updates a secret in the database. // -// nolint: dupl // ignore similar code with create +//nolint:dupl // ignore similar code with create func (c *client) UpdateSecret(s *library.Secret) error { // create log fields from secret metadata fields := logrus.Fields{ diff --git a/database/sqlite/secret_list.go b/database/sqlite/secret_list.go index d4edc5304..ef57da67f 100644 --- a/database/sqlite/secret_list.go +++ b/database/sqlite/secret_list.go @@ -17,7 +17,7 @@ import ( // GetSecretList gets a list of all secrets from the database. // -// nolint: dupl // ignore false positive of duplicate code +//nolint:dupl // ignore false positive of duplicate code func (c *client) GetSecretList() ([]*library.Secret, error) { c.Logger.Tracef("listing secrets from the database") diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 32f476f16..2369db0cd 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -51,7 +51,7 @@ type ( // New returns a Database implementation that integrates with a Sqlite instance. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new Sqlite client c := new(client) @@ -108,7 +108,7 @@ func New(opts ...ClientOpt) (*client, error) { // // This function is intended for running tests only. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func NewTest() (*client, error) { // create new Sqlite client c := new(client) diff --git a/database/user/create.go b/database/user/create.go index 51c960e79..f527979b9 100644 --- a/database/user/create.go +++ b/database/user/create.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code in update.go +//nolint:dupl // ignore similar code in update.go package user import ( diff --git a/database/user/list_lite.go b/database/user/list_lite.go index 50957e5f5..ee90bca3b 100644 --- a/database/user/list_lite.go +++ b/database/user/list_lite.go @@ -12,7 +12,7 @@ import ( // ListLiteUsers gets a lite (only: id, name) list of users from the database. // -// nolint: lll // ignore long line length due to variable names +//nolint:lll // ignore long line length due to variable names func (e *engine) ListLiteUsers(page, perPage int) ([]*library.User, int64, error) { e.logger.Trace("listing lite users from the database") diff --git a/database/user/service.go b/database/user/service.go index 096cea933..b33c8cd63 100644 --- a/database/user/service.go +++ b/database/user/service.go @@ -11,7 +11,7 @@ import ( // UserService represents the Vela interface for user // functions with the supported Database backends. // -// nolint: revive // ignore name stutter +//nolint:revive // ignore name stutter type UserService interface { // User Data Definition Language Functions // diff --git a/database/user/update.go b/database/user/update.go index f41d80a30..c7efc5e7f 100644 --- a/database/user/update.go +++ b/database/user/update.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code in create.go +//nolint:dupl // ignore similar code in create.go package user import ( diff --git a/database/user/user.go b/database/user/user.go index e37b18644..9bef43843 100644 --- a/database/user/user.go +++ b/database/user/user.go @@ -41,7 +41,7 @@ type ( // New creates and returns a Vela service for integrating with users in the database. // -// nolint: revive // ignore returning unexported engine +//nolint:revive // ignore returning unexported engine func New(opts ...EngineOpt) (*engine, error) { // create new User engine e := new(engine) diff --git a/mock/server/authentication.go b/mock/server/authentication.go index 2d100f0d4..4f9e5055e 100644 --- a/mock/server/authentication.go +++ b/mock/server/authentication.go @@ -16,7 +16,7 @@ import ( const ( // TokenRefreshResp represents a JSON return for a token refresh. - // nolint:gosec // not a hardcoded credential + //nolint:gosec // not a hardcoded credential TokenRefreshResp = `{ "token": "header.payload.signature" }` diff --git a/mock/server/hook.go b/mock/server/hook.go index 3bca13258..d2c21da46 100644 --- a/mock/server/hook.go +++ b/mock/server/hook.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore duplicate with user code +//nolint:dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/secret.go b/mock/server/secret.go index eefbe9861..eb1bcd72a 100644 --- a/mock/server/secret.go +++ b/mock/server/secret.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore duplicate with user code +//nolint:dupl // ignore duplicate with user code package server import ( @@ -16,7 +16,7 @@ import ( "github.com/go-vela/types/library" ) -// nolint:gosec // these are mock responses +//nolint:gosec // these are mock responses const ( // SecretResp represents a JSON return for a single secret. SecretResp = `{ diff --git a/mock/server/server.go b/mock/server/server.go index 14df28d7f..843a2f591 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -12,7 +12,8 @@ import ( // FakeHandler returns an http.Handler that is capable of handling // Vela API requests and returning mock responses. -// nolint:funlen // number of endpoints is causing linter warning +// +//nolint:funlen // number of endpoints is causing linter warning func FakeHandler() http.Handler { gin.SetMode(gin.TestMode) diff --git a/mock/server/service.go b/mock/server/service.go index ba4136515..0d4ce36f1 100644 --- a/mock/server/service.go +++ b/mock/server/service.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore duplicate with user code +//nolint:dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/step.go b/mock/server/step.go index c88ce6250..c7111aded 100644 --- a/mock/server/step.go +++ b/mock/server/step.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore duplicate with user code +//nolint:dupl // ignore duplicate with user code package server import ( diff --git a/mock/server/user.go b/mock/server/user.go index 7e69c809a..85029962b 100644 --- a/mock/server/user.go +++ b/mock/server/user.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore duplicate with user code +//nolint:dupl // ignore duplicate with user code package server import ( diff --git a/queue/context.go b/queue/context.go index d6789e5bb..e5bf48c78 100644 --- a/queue/context.go +++ b/queue/context.go @@ -56,7 +56,7 @@ func WithContext(c context.Context, s Service) context.Context { // // https://pkg.go.dev/context?tab=doc#WithValue // - // nolint: staticcheck,revive // ignore using string with context value + //nolint:staticcheck,revive // ignore using string with context value return context.WithValue(c, key, s) } diff --git a/queue/context_test.go b/queue/context_test.go index b88b8f3d8..92218a1f4 100644 --- a/queue/context_test.go +++ b/queue/context_test.go @@ -22,7 +22,7 @@ func TestExecutor_FromContext(t *testing.T) { want Service }{ { - // nolint: staticcheck // ignore using string with context value + //nolint:staticcheck,revive // ignore using string with context value context: context.WithValue(context.Background(), key, _service), want: _service, }, @@ -31,7 +31,7 @@ func TestExecutor_FromContext(t *testing.T) { want: nil, }, { - // nolint: staticcheck // ignore using string with context value + //nolint:staticcheck,revive // ignore using string with context value context: context.WithValue(context.Background(), key, "foo"), want: nil, }, @@ -92,7 +92,7 @@ func TestExecutor_WithContext(t *testing.T) { // setup types _service, _ := New(&Setup{}) - // nolint: staticcheck // ignore using string with context value + //nolint:staticcheck,revive // ignore using string with context value want := context.WithValue(context.Background(), key, _service) // run test diff --git a/queue/queue.go b/queue/queue.go index f665c74ba..fca90b8a2 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -11,13 +11,12 @@ import ( "github.com/sirupsen/logrus" ) -// nolint: godot // ignore period at end for comment ending in a list -// // New creates and returns a Vela service capable of // integrating with the configured queue environment. // Currently, the following queues are supported: // // * redis +// . func New(s *Setup) (Service, error) { // validate the setup being provided // diff --git a/queue/redis/redis.go b/queue/redis/redis.go index 1d2c1467b..2821e3cde 100644 --- a/queue/redis/redis.go +++ b/queue/redis/redis.go @@ -38,7 +38,7 @@ type client struct { // New returns a Queue implementation that // integrates with a Redis queue instance. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new Redis client c := new(client) @@ -172,7 +172,7 @@ func pingQueue(c *client) error { // // This function is intended for running tests only. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func NewTest(channels ...string) (*client, error) { // create a local fake redis instance // diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index ac775ac27..acd115537 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -8,7 +8,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "time" @@ -65,7 +65,7 @@ func Establish() gin.HandlerFunc { defer resp.Body.Close() // Read Response Body - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { retErr := fmt.Errorf("unable to read response from %s: %w", endpoint, err) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/router/middleware/logger.go b/router/middleware/logger.go index 9be222039..a6cb7f835 100644 --- a/router/middleware/logger.go +++ b/router/middleware/logger.go @@ -27,8 +27,7 @@ import ( // // It receives: // 1. A time package format string (e.g. time.RFC3339). -// 2. A boolean stating whether to use UTC time zone or local. -func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc { +func Logger(logger *logrus.Logger, timeFormat string) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() // some evil middlewares modify this values @@ -37,11 +36,8 @@ func Logger(logger *logrus.Logger, timeFormat string, utc bool) gin.HandlerFunc c.Next() end := time.Now() - latency := end.Sub(start) - if utc { - end = end.UTC() - } + latency := end.Sub(start) // prevent us from logging the health endpoint if c.Request.URL.Path != "/health" { diff --git a/router/middleware/logger_test.go b/router/middleware/logger_test.go index 87f4e267b..5204763e7 100644 --- a/router/middleware/logger_test.go +++ b/router/middleware/logger_test.go @@ -87,7 +87,7 @@ func TestMiddleware_Logger(t *testing.T) { engine.Use(func(c *gin.Context) { user.ToContext(c, u) }) engine.Use(func(c *gin.Context) { worker.ToContext(c, w) }) engine.Use(Payload()) - engine.Use(Logger(logger, time.RFC3339, true)) + engine.Use(Logger(logger, time.RFC3339)) engine.POST("/foobar", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -127,9 +127,9 @@ func TestMiddleware_Logger_Error(t *testing.T) { context.Request, _ = http.NewRequest(http.MethodGet, "/foobar", nil) // setup mock server - engine.Use(Logger(logger, time.RFC3339, true)) + engine.Use(Logger(logger, time.RFC3339)) engine.GET("/foobar", func(c *gin.Context) { - // nolint: errcheck // ignore checking error + //nolint:errcheck // ignore checking error c.Error(fmt.Errorf("test error")) c.Status(http.StatusOK) }) diff --git a/router/middleware/payload.go b/router/middleware/payload.go index 2ef7e5e22..c2241fa9f 100644 --- a/router/middleware/payload.go +++ b/router/middleware/payload.go @@ -7,7 +7,7 @@ package middleware import ( "bytes" "encoding/json" - "io/ioutil" + "io" "github.com/gin-gonic/gin" ) @@ -24,7 +24,7 @@ func Payload() gin.HandlerFunc { c.Set("payload", payload) - c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) c.Next() } diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 92a7e8687..0c4c20243 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -205,7 +205,7 @@ func MustAdmin() gin.HandlerFunc { } switch perm { - // nolint: goconst // ignore making constant + //nolint:goconst // ignore making constant case "admin": return default: diff --git a/router/middleware/token/token.go b/router/middleware/token/token.go index 68c53aa99..7bd9ae257 100644 --- a/router/middleware/token/token.go +++ b/router/middleware/token/token.go @@ -146,7 +146,8 @@ func RetrieveRefreshToken(r *http.Request) (string, error) { } // CreateAccessToken creates a new access token for the given user and duration. -// nolint:staticcheck // ignore deprecated +// +//nolint:staticcheck // ignore deprecated func CreateAccessToken(u *library.User, d time.Duration) (string, error) { now := time.Now() exp := now.Add(d) @@ -172,7 +173,8 @@ func CreateAccessToken(u *library.User, d time.Duration) (string, error) { } // CreateCreateRefreshToken creates a new refresh token for the given user and duration. -// nolint:staticcheck // ignore deprecated +// +//nolint:staticcheck // ignore deprecated func CreateRefreshToken(u *library.User, d time.Duration) (string, int, error) { exp := time.Now().Add(d) diff --git a/router/middleware/token/token_test.go b/router/middleware/token/token_test.go index 82293ab12..6add3ed56 100644 --- a/router/middleware/token/token_test.go +++ b/router/middleware/token/token_test.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: staticcheck // ignore deprecated +//nolint:staticcheck // ignore deprecated package token import ( diff --git a/router/service.go b/router/service.go index 647d301e1..400feb4b5 100644 --- a/router/service.go +++ b/router/service.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code with step +//nolint:dupl // ignore similar code with step package router import ( diff --git a/router/step.go b/router/step.go index ac73ca238..5ac9b05de 100644 --- a/router/step.go +++ b/router/step.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -// nolint: dupl // ignore similar code with service +//nolint:dupl // ignore similar code with service package router import ( diff --git a/scm/github/access.go b/scm/github/access.go index ba9d4826c..c9f152cd1 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -22,7 +22,7 @@ func (c *client) OrgAccess(u *library.User, org string) (string, error) { // if user is accessing personal org if strings.EqualFold(org, *u.Name) { - // nolint: goconst // ignore making constant + //nolint:goconst // ignore making constant return "admin", nil } diff --git a/scm/github/github.go b/scm/github/github.go index 037c779f2..4bc9995b4 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -61,7 +61,7 @@ type client struct { // New returns a SCM implementation that integrates with // a GitHub or a GitHub Enterprise instance. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new GitHub client c := new(client) @@ -120,7 +120,7 @@ func New(opts ...ClientOpt) (*client, error) { // // This function is intended for running tests only. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func NewTest(urls ...string) (*client, error) { address := urls[0] server := address diff --git a/scm/github/github_test.go b/scm/github/github_test.go index 5131e161d..4f8016463 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -76,12 +76,12 @@ func TestGithub_newClientToken(t *testing.T) { // run test got := client.newClientToken("foobar") - // nolint: staticcheck // ignore false positive + //nolint: staticcheck // ignore false positive if got == nil { t.Errorf("newClientToken is nil, want %v", want) } - // nolint: staticcheck // ignore false positive + //nolint: staticcheck // ignore false positive if !reflect.DeepEqual(got.BaseURL, want.BaseURL) { t.Errorf("newClientToken BaseURL is %v, want %v", got.BaseURL, want.BaseURL) } diff --git a/scm/github/repo.go b/scm/github/repo.go index f841f055b..dc51768b2 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -217,7 +217,7 @@ func (c *client) Status(u *library.User, b *library.Build, org, name string) err state = "success" description = "the build was successful" case constants.StatusFailure: - // nolint: goconst // ignore making constant + //nolint:goconst // ignore making constant state = "failure" description = "the build has failed" case constants.StatusCanceled: diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index b7b524a24..b9521a061 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -6,9 +6,9 @@ package github import ( "fmt" - "io/ioutil" "net/http" "net/http/httptest" + "os" "reflect" "strings" "testing" @@ -41,7 +41,7 @@ func TestGithub_Config_YML(t *testing.T) { s := httptest.NewServer(engine) defer s.Close() - want, err := ioutil.ReadFile("testdata/pipeline.yml") + want, err := os.ReadFile("testdata/pipeline.yml") if err != nil { t.Errorf("Config reading file returned err: %v", err) } @@ -95,7 +95,7 @@ func TestGithub_ConfigBackoff_YML(t *testing.T) { s := httptest.NewServer(engine) defer s.Close() - want, err := ioutil.ReadFile("testdata/pipeline.yml") + want, err := os.ReadFile("testdata/pipeline.yml") if err != nil { t.Errorf("Config reading file returned err: %v", err) } @@ -191,7 +191,7 @@ func TestGithub_Config_YAML(t *testing.T) { s := httptest.NewServer(engine) defer s.Close() - want, err := ioutil.ReadFile("testdata/pipeline.yml") + want, err := os.ReadFile("testdata/pipeline.yml") if err != nil { t.Errorf("Config reading file returned err: %v", err) } @@ -245,7 +245,7 @@ func TestGithub_Config_Star(t *testing.T) { s := httptest.NewServer(engine) defer s.Close() - want, err := ioutil.ReadFile("testdata/pipeline.yml") + want, err := os.ReadFile("testdata/pipeline.yml") if err != nil { t.Errorf("Config reading file returned err: %v", err) } @@ -300,7 +300,7 @@ func TestGithub_Config_Py(t *testing.T) { s := httptest.NewServer(engine) defer s.Close() - want, err := ioutil.ReadFile("testdata/pipeline.yml") + want, err := os.ReadFile("testdata/pipeline.yml") if err != nil { t.Errorf("Config reading file returned err: %v", err) } diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 4d48778b8..a9d42b464 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -22,8 +22,9 @@ import ( "github.com/google/go-github/v44/github" ) -// nolint: nilerr // ignore webhook returning nil // ProcessWebhook parses the webhook from a repo. +// +//nolint:nilerr // ignore webhook returning nil func (c *client) ProcessWebhook(request *http.Request) (*types.Webhook, error) { c.Logger.Tracef("processing GitHub webhook") @@ -93,7 +94,7 @@ func (c *client) VerifyWebhook(request *http.Request, r *library.Repo) error { // RedeliverWebhook redelivers webhooks from GitHub. func (c *client) RedeliverWebhook(ctx context.Context, u *library.User, r *library.Repo, h *library.Hook) error { // create GitHub OAuth client with user's token - // nolint: contextcheck // do not need to pass context in this instance + //nolint:contextcheck // do not need to pass context in this instance client := c.newClientToken(*u.Token) // capture the delivery ID of the hook using GitHub API diff --git a/scm/scm.go b/scm/scm.go index faf2881a9..2bd5c8170 100644 --- a/scm/scm.go +++ b/scm/scm.go @@ -12,14 +12,13 @@ import ( "github.com/sirupsen/logrus" ) -// nolint: godot // top level comment ends in a list -// // New creates and returns a Vela service capable of // integrating with the configured scm provider. // // Currently the following scm providers are supported: // // * Github +// . func New(s *Setup) (Service, error) { // validate the setup being provided // diff --git a/secret/native/native.go b/secret/native/native.go index fbc53cb5b..4109d8e4f 100644 --- a/secret/native/native.go +++ b/secret/native/native.go @@ -19,7 +19,7 @@ type client struct { // New returns a Secret implementation that integrates with a Native secrets engine. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new native client c := new(client) diff --git a/secret/secret.go b/secret/secret.go index eb39b07b1..edeec6c93 100644 --- a/secret/secret.go +++ b/secret/secret.go @@ -12,8 +12,6 @@ import ( "github.com/sirupsen/logrus" ) -// nolint: godot // top level comment ends in a list -// // New creates and returns a Vela service capable of // integrating with the configured secret provider. // @@ -21,6 +19,7 @@ import ( // // * Native // * Vault +// . func New(s *Setup) (Service, error) { // validate the setup being provided // diff --git a/secret/vault/count.go b/secret/vault/count.go index 21373d861..44dbf2335 100644 --- a/secret/vault/count.go +++ b/secret/vault/count.go @@ -35,7 +35,7 @@ func (c *client) Count(sType, org, name string, _ []string) (i int64, err error) c.Logger.WithFields(fields).Tracef("counting vault %s secrets for %s/%s", sType, org, name) - // nolint: staticcheck // ignore false positive + //nolint:staticcheck // ignore false positive vault := new(api.Secret) count := 0 diff --git a/secret/vault/get.go b/secret/vault/get.go index 625b036ff..3612176a5 100644 --- a/secret/vault/get.go +++ b/secret/vault/get.go @@ -38,7 +38,7 @@ func (c *client) Get(sType, org, name, path string) (s *library.Secret, err erro c.Logger.WithFields(fields).Tracef("getting vault %s secret %s for %s/%s", sType, path, org, name) - // nolint: ineffassign,staticcheck // ignore false positive + //nolint:ineffassign,staticcheck // ignore false positive vault := new(api.Secret) // capture the secret from the Vault service diff --git a/secret/vault/list.go b/secret/vault/list.go index 45172f548..00b64db29 100644 --- a/secret/vault/list.go +++ b/secret/vault/list.go @@ -43,7 +43,7 @@ func (c *client) List(sType, org, name string, _, _ int, _ []string) ([]*library var err error s := []*library.Secret{} - // nolint: staticcheck // ignore false positive + //nolint:staticcheck // ignore false positive vault := new(api.Secret) // capture the list of secrets from the Vault service diff --git a/secret/vault/refresh.go b/secret/vault/refresh.go index 83bf76a76..461d49fe8 100644 --- a/secret/vault/refresh.go +++ b/secret/vault/refresh.go @@ -8,7 +8,7 @@ import ( "encoding/base64" "encoding/json" "fmt" - "io/ioutil" + "io" "time" "github.com/aws/aws-sdk-go/aws" @@ -102,7 +102,7 @@ func (c *client) generateAwsAuthHeader() (map[string]interface{}, error) { } // read the STS request body - requestBody, err := ioutil.ReadAll(req.Body) + requestBody, err := io.ReadAll(req.Body) if err != nil { return nil, err } diff --git a/secret/vault/refresh_test.go b/secret/vault/refresh_test.go index 0bdb16233..33b41fa35 100644 --- a/secret/vault/refresh_test.go +++ b/secret/vault/refresh_test.go @@ -6,10 +6,10 @@ package vault import ( "fmt" - "io/ioutil" "net/http" "net/http/httptest" "net/url" + "os" "strings" "testing" "time" @@ -45,7 +45,7 @@ func Test_client_initialize(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - data, err := ioutil.ReadFile(fmt.Sprintf("testdata/refresh/%s", tt.responseFile)) + data, err := os.ReadFile(fmt.Sprintf("testdata/refresh/%s", tt.responseFile)) if err != nil { t.Error(err) } @@ -201,7 +201,7 @@ func Test_client_getAwsToken(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(*testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - data, err := ioutil.ReadFile(fmt.Sprintf("testdata/refresh/%s", tt.responseFile)) + data, err := os.ReadFile(fmt.Sprintf("testdata/refresh/%s", tt.responseFile)) if err != nil { t.Error(err) } diff --git a/secret/vault/vault.go b/secret/vault/vault.go index f49755737..997ff46f5 100644 --- a/secret/vault/vault.go +++ b/secret/vault/vault.go @@ -58,7 +58,7 @@ type ( // New returns a Secret implementation that integrates with a Vault secrets engine. // -// nolint: revive // ignore returning unexported client +//nolint:revive // ignore returning unexported client func New(opts ...ClientOpt) (*client, error) { // create new Vault client c := new(client) @@ -132,7 +132,7 @@ func New(opts ...ClientOpt) (*client, error) { // secretFromVault is a helper function to convert a HashiCorp Vault secret to a Vela secret. // -// nolint: gocyclo,funlen // ignore cyclomatic complexity and function length due to conditionals +//nolint:gocyclo,funlen // ignore cyclomatic complexity and function length due to conditionals func secretFromVault(vault *api.Secret) *library.Secret { s := new(library.Secret) diff --git a/util/util.go b/util/util.go index 24ac89b67..59b08121f 100644 --- a/util/util.go +++ b/util/util.go @@ -15,7 +15,7 @@ import ( // HandleError appends the error to the handler chain for logging and outputs it. func HandleError(c *gin.Context, status int, err error) { msg := err.Error() - // nolint: errcheck // ignore checking error + //nolint:errcheck // ignore checking error c.Error(err) c.AbortWithStatusJSON(status, types.Error{Message: &msg}) } From b7cdc17a4b9d98720be2b37f7c3efb189a756fb5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Sep 2022 10:56:58 -0500 Subject: [PATCH 102/298] fix(deps): update golang.org/x/oauth2 digest to f213421 (#669) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3c8b4852c..e50766244 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.11.1 go.starlark.net v0.0.0-20220817180228-f738f5508c12 - golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 + golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.3.8 diff --git a/go.sum b/go.sum index 06ea52028..674e8e4a7 100644 --- a/go.sum +++ b/go.sum @@ -676,8 +676,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw= -golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 2f14f3894de0b7f82bee337b8f042926a4b4385d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 Sep 2022 14:26:51 -0500 Subject: [PATCH 103/298] fix(deps): update module github.com/go-playground/assert/v2 to v2.2.0 (#689) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e50766244..18dff43e6 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 - github.com/go-playground/assert/v2 v2.0.1 + github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.14.0 github.com/golang-jwt/jwt/v4 v4.4.2 diff --git a/go.sum b/go.sum index 674e8e4a7..be41ff596 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,9 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= From 17b6c3d8722c1b58e575d276939f0ef6a355fc20 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Sep 2022 11:01:07 -0500 Subject: [PATCH 104/298] fix(deps): update module github.com/urfave/cli/v2 to v2.16.3 (#695) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 18dff43e6..a0be02d0a 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 - github.com/urfave/cli/v2 v2.11.1 + github.com/urfave/cli/v2 v2.16.3 go.starlark.net v0.0.0-20220817180228-f738f5508c12 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index be41ff596..2d82e700f 100644 --- a/go.sum +++ b/go.sum @@ -541,8 +541,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE= -github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= +github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 99d66e6983d363134706474ac3593c2b18f0d42b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:04:50 -0500 Subject: [PATCH 105/298] fix(deps): update deps (patch) (#688) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index a0be02d0a..7b0667b9e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.23.0 - github.com/aws/aws-sdk-go v1.44.70 + github.com/aws/aws-sdk-go v1.44.99 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -16,7 +16,7 @@ require ( github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.14.0 github.com/golang-jwt/jwt/v4 v4.4.2 - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 @@ -34,9 +34,9 @@ require ( golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.8 + gorm.io/driver/postgres v1.3.9 gorm.io/driver/sqlite v1.3.6 - gorm.io/gorm v1.23.8 + gorm.io/gorm v1.23.9 k8s.io/apimachinery v0.25.0 ) diff --git a/go.sum b/go.sum index 2d82e700f..4faa8c428 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.70 h1:wrwAbqJqf+ncEK1F/bXTYpgO6zXIgQXi/2ppBgmYI9g= -github.com/aws/aws-sdk-go v1.44.70/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.99 h1:ITZ9q/fmH+Ksaz2TbyMU2d19vOOWs/hAlt8NbXAieHw= +github.com/aws/aws-sdk-go v1.44.99/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -216,8 +216,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v44 v44.1.0 h1:shWPaufgdhr+Ad4eo/pZv9ORTxFpsxPEPEuuXAKIQGA= github.com/google/go-github/v44 v44.1.0/go.mod h1:iWn00mWcP6PRWHhXm0zuFJ8wbEjE5AGO5D5HXYM4zgw= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -950,14 +950,14 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gorm.io/driver/postgres v1.3.8 h1:8bEphSAB69t3odsCR4NDzt581iZEWQuRM27Cg6KgfPY= -gorm.io/driver/postgres v1.3.8/go.mod h1:qB98Aj6AhRO/oyu/jmZsi/YM9g6UzVCjMxO/6frFvcA= +gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= +gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= -gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw= +gorm.io/gorm v1.23.9/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 4d07c5b5351c67282eff58ad897d62790f521cd4 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 16 Sep 2022 13:35:57 -0500 Subject: [PATCH 106/298] chore: change default branch to main (#696) --- .github/CONTRIBUTING.md | 2 +- .github/README.md | 2 +- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/publish.yml | 4 ++-- queue/redis/redis_test.go | 2 +- queue/redis/route.go | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 65e1e66a9..757c77071 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -73,7 +73,7 @@ make clean ```bash # push your code up to your fork -git push fork master +git push fork main ``` * Make sure to follow our [PR process](https://go-vela.github.io/docs/community/contributing_guidelines/#development-workflow) when opening a pull request diff --git a/.github/README.md b/.github/README.md index 00578e3c3..30a9fd391 100644 --- a/.github/README.md +++ b/.github/README.md @@ -3,7 +3,7 @@ [![license](https://img.shields.io/crates/l/gl.svg)](../LICENSE) [![GoDoc](https://godoc.org/github.com/go-vela/server?status.svg)](https://godoc.org/github.com/go-vela/server) [![Go Report Card](https://goreportcard.com/badge/go-vela/server)](https://goreportcard.com/report/go-vela/server) -[![codecov](https://codecov.io/gh/go-vela/server/branch/master/graph/badge.svg)](https://codecov.io/gh/go-vela/server) +[![codecov](https://codecov.io/gh/go-vela/server/branch/main/graph/badge.svg)](https://codecov.io/gh/go-vela/server) > Vela is in active development and is a pre-release product. > diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fc1738a88..ecc65e90c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,10 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [ main ] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [ main ] schedule: - cron: '23 1 * * 0' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 71d077009..9f234a8c7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,10 +1,10 @@ # name of the action name: publish -# trigger on push events with branch master +# trigger on push events with branch main on: push: - branches: [ master ] + branches: [ main ] # pipeline to execute jobs: diff --git a/queue/redis/redis_test.go b/queue/redis/redis_test.go index 8c37fd3fc..aa1bf1a0f 100644 --- a/queue/redis/redis_test.go +++ b/queue/redis/redis_test.go @@ -15,7 +15,7 @@ import ( ) // The following functions were taken from -// https://github.com/go-vela/sdk-go/blob/master/vela/go +// https://github.com/go-vela/sdk-go/blob/main/vela/go // which is the only reason go-vela/sdk-go is // a dependency for go-vela/server // TODO: consider moving to go-vela/types? diff --git a/queue/redis/route.go b/queue/redis/route.go index fa1a3b4f3..58e10b78f 100644 --- a/queue/redis/route.go +++ b/queue/redis/route.go @@ -22,7 +22,7 @@ func (c *client) Route(w *pipeline.Worker) (string, error) { // if pipline does not specify route information return default // - // https://github.com/go-vela/types/blob/master/constants/queue.go#L10 + // https://github.com/go-vela/types/blob/main/constants/queue.go#L10 if w.Empty() { return constants.DefaultRoute, nil } From ada3f0077992d7bc23bceb5073842aafc5904b6d Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 16 Sep 2022 13:48:05 -0500 Subject: [PATCH 107/298] chore(ci): fix full-review to use setup-go action (#698) --- .github/workflows/reviewdog.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 09ff67bb7..5e2ccc811 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -32,12 +32,18 @@ jobs: full-review: runs-on: ubuntu-latest - container: - image: golang:1.19 + steps: - name: clone uses: actions/checkout@v3 + - name: install go + uses: actions/setup-go@v3 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 with: From 2015910b4cb7ea6891bec9ae87392c28e5762de8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 14:24:54 -0500 Subject: [PATCH 108/298] fix(deps): update module github.com/hashicorp/vault/api to v1.8.0 (#699) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 7b0667b9e..840ccfa25 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/hashicorp/vault/api v1.7.2 + github.com/hashicorp/vault/api v1.8.0 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.13.0 @@ -81,7 +81,7 @@ require ( github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.5.1 // indirect + github.com/hashicorp/vault/sdk v0.6.0 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect diff --git a/go.sum b/go.sum index 4faa8c428..2761d23c9 100644 --- a/go.sum +++ b/go.sum @@ -295,10 +295,10 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.7.2 h1:kawHE7s/4xwrdKbkmwQi0wYaIeUhk5ueek7ljuezCVQ= -github.com/hashicorp/vault/api v1.7.2/go.mod h1:xbfA+1AvxFseDzxxdWaL0uO99n1+tndus4GCrtouy0M= -github.com/hashicorp/vault/sdk v0.5.1 h1:zly/TmNgOXCGgWIRA8GojyXzG817POtVh3uzIwzZx+8= -github.com/hashicorp/vault/sdk v0.5.1/go.mod h1:DoGraE9kKGNcVgPmTuX357Fm6WAx1Okvde8Vp3dPDoU= +github.com/hashicorp/vault/api v1.8.0 h1:7765sW1XBt+qf4XKIYE4ebY9qc/yi9V2/egzGSUNMZU= +github.com/hashicorp/vault/api v1.8.0/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E= +github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZTIAhs= +github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= From 49e720db1444794f60d77f5fd25abb4b36b72bbc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 14:35:28 -0500 Subject: [PATCH 109/298] fix(deps): update go.starlark.net digest to 14b0506 (#702) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 840ccfa25..7b93f1fe5 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.16.3 - go.starlark.net v0.0.0-20220817180228-f738f5508c12 + go.starlark.net v0.0.0-20220926145019-14b050677505 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 2761d23c9..9273a8434 100644 --- a/go.sum +++ b/go.sum @@ -561,8 +561,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g= -go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk= +go.starlark.net v0.0.0-20220926145019-14b050677505 h1:W0MibAL5BiEenQR+F/EF/a4HJhgLngHVvm6jbtUW0PM= +go.starlark.net v0.0.0-20220926145019-14b050677505/go.mod h1:qsNirHv+Awo5xHuNyQ/0niov6kDxdBs+bqpVMBCW77k= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -750,6 +750,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From f0741c99da0a088c3f493e27c76c99ac88e410e9 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 26 Sep 2022 15:06:04 -0500 Subject: [PATCH 110/298] refactor(database): move repo logic into separate package (#687) --- api/admin/repo.go | 2 +- api/metrics.go | 5 +- api/repo.go | 49 ++- api/scm.go | 9 +- api/user.go | 4 +- api/webhook.go | 6 +- database/pipeline/get.go | 3 +- database/pipeline/get_repo.go | 3 +- database/postgres/ddl/repo.go | 49 --- database/postgres/dml/repo.go | 76 ----- database/postgres/postgres.go | 30 +- database/postgres/postgres_test.go | 48 ++- database/postgres/repo.go | 132 -------- database/postgres/repo_count.go | 66 ---- database/postgres/repo_count_test.go | 301 ----------------- database/postgres/repo_list.go | 162 ---------- database/postgres/repo_list_test.go | 407 ----------------------- database/postgres/repo_test.go | 280 ---------------- database/repo/count.go | 25 ++ database/repo/count_org.go | 30 ++ database/repo/count_org_test.go | 101 ++++++ database/repo/count_test.go | 99 ++++++ database/repo/count_user.go | 31 ++ database/repo/count_user_test.go | 107 +++++++ database/repo/create.go | 50 +++ database/repo/create_test.go | 78 +++++ database/repo/delete.go | 31 ++ database/repo/delete_test.go | 76 +++++ database/repo/get.go | 52 +++ database/repo/get_org.go | 57 ++++ database/repo/get_org_test.go | 89 ++++++ database/repo/get_test.go | 89 ++++++ database/repo/index.go | 24 ++ database/repo/index_test.go | 59 ++++ database/repo/list.go | 67 ++++ database/repo/list_org.go | 104 ++++++ database/repo/list_org_test.go | 175 ++++++++++ database/repo/list_test.go | 111 +++++++ database/repo/list_user.go | 104 ++++++ database/repo/list_user_test.go | 180 +++++++++++ database/repo/opts.go | 54 ++++ database/repo/opts_test.go | 210 ++++++++++++ database/repo/repo.go | 82 +++++ database/repo/repo_test.go | 215 +++++++++++++ database/repo/service.go | 51 +++ database/repo/table.go | 90 ++++++ database/repo/table_test.go | 59 ++++ database/repo/update.go | 50 +++ database/repo/update_test.go | 80 +++++ database/service.go | 36 +-- database/sqlite/ddl/repo.go | 49 --- database/sqlite/dml/repo.go | 76 ----- database/sqlite/repo.go | 132 -------- database/sqlite/repo_count.go | 66 ---- database/sqlite/repo_count_test.go | 341 -------------------- database/sqlite/repo_list.go | 162 ---------- database/sqlite/repo_list_test.go | 461 --------------------------- database/sqlite/repo_test.go | 278 ---------------- database/sqlite/sqlite.go | 28 +- database/sqlite/sqlite_test.go | 37 +++ database/user/get.go | 3 +- database/user/get_name.go | 3 +- router/middleware/repo/repo.go | 2 +- 63 files changed, 2788 insertions(+), 3148 deletions(-) delete mode 100644 database/postgres/ddl/repo.go delete mode 100644 database/postgres/dml/repo.go delete mode 100644 database/postgres/repo.go delete mode 100644 database/postgres/repo_count.go delete mode 100644 database/postgres/repo_count_test.go delete mode 100644 database/postgres/repo_list.go delete mode 100644 database/postgres/repo_list_test.go delete mode 100644 database/postgres/repo_test.go create mode 100644 database/repo/count.go create mode 100644 database/repo/count_org.go create mode 100644 database/repo/count_org_test.go create mode 100644 database/repo/count_test.go create mode 100644 database/repo/count_user.go create mode 100644 database/repo/count_user_test.go create mode 100644 database/repo/create.go create mode 100644 database/repo/create_test.go create mode 100644 database/repo/delete.go create mode 100644 database/repo/delete_test.go create mode 100644 database/repo/get.go create mode 100644 database/repo/get_org.go create mode 100644 database/repo/get_org_test.go create mode 100644 database/repo/get_test.go create mode 100644 database/repo/index.go create mode 100644 database/repo/index_test.go create mode 100644 database/repo/list.go create mode 100644 database/repo/list_org.go create mode 100644 database/repo/list_org_test.go create mode 100644 database/repo/list_test.go create mode 100644 database/repo/list_user.go create mode 100644 database/repo/list_user_test.go create mode 100644 database/repo/opts.go create mode 100644 database/repo/opts_test.go create mode 100644 database/repo/repo.go create mode 100644 database/repo/repo_test.go create mode 100644 database/repo/service.go create mode 100644 database/repo/table.go create mode 100644 database/repo/table_test.go create mode 100644 database/repo/update.go create mode 100644 database/repo/update_test.go delete mode 100644 database/sqlite/ddl/repo.go delete mode 100644 database/sqlite/dml/repo.go delete mode 100644 database/sqlite/repo.go delete mode 100644 database/sqlite/repo_count.go delete mode 100644 database/sqlite/repo_count_test.go delete mode 100644 database/sqlite/repo_list.go delete mode 100644 database/sqlite/repo_list_test.go delete mode 100644 database/sqlite/repo_test.go diff --git a/api/admin/repo.go b/api/admin/repo.go index 1905275d7..c48e98933 100644 --- a/api/admin/repo.go +++ b/api/admin/repo.go @@ -45,7 +45,7 @@ func AllRepos(c *gin.Context) { logrus.Info("Admin: reading all repos") // send API call to capture all repos - r, err := database.FromContext(c).GetRepoList() + r, err := database.FromContext(c).ListRepos() if err != nil { retErr := fmt.Errorf("unable to capture all repos: %w", err) diff --git a/api/metrics.go b/api/metrics.go index 0b277d1a3..edbe8ecdd 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -8,9 +8,8 @@ import ( "net/http" "time" - "github.com/go-vela/server/database" - "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -218,7 +217,7 @@ func recordGauges(c *gin.Context) { // repo_count if q.RepoCount { // send API call to capture the total number of repos - r, err := database.FromContext(c).GetRepoCount() + r, err := database.FromContext(c).CountRepos() if err != nil { logrus.Errorf("unable to get count of all repos: %v", err) } diff --git a/api/repo.go b/api/repo.go index 28393fd1f..b1ee44035 100644 --- a/api/repo.go +++ b/api/repo.go @@ -206,7 +206,7 @@ func CreateRepo(c *gin.Context) { } // send API call to capture the repo from the database - dbRepo, err := database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) + dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) if err == nil && dbRepo.GetActive() { retErr := fmt.Errorf("unable to activate repo: %s is already active", r.GetFullName()) @@ -262,7 +262,7 @@ func CreateRepo(c *gin.Context) { } // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepo(dbRepo.GetOrg(), dbRepo.GetName()) + r, _ = database.FromContext(c).GetRepoForOrg(dbRepo.GetOrg(), dbRepo.GetName()) } else { // send API call to create the repo err = database.FromContext(c).CreateRepo(r) @@ -275,7 +275,7 @@ func CreateRepo(c *gin.Context) { } // send API call to capture the created repo - r, _ = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) + r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) } c.JSON(http.StatusCreated, r) @@ -361,18 +361,18 @@ func GetRepos(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) - // send API call to capture the total number of repos for the user - t, err := database.FromContext(c).GetUserRepoCount(u) - if err != nil { - retErr := fmt.Errorf("unable to get repo count for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) + // capture the sort_by query parameter if present + sortBy := util.QueryParameter(c, "sort_by", "name") - return + // capture the query parameters if present: + // + // * active + filters := map[string]interface{}{ + "active": util.QueryParameter(c, "active", "true"), } // send API call to capture the list of repos for the user - r, err := database.FromContext(c).GetUserRepoList(u, page, perPage) + r, t, err := database.FromContext(c).ListReposForUser(u, sortBy, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get repos for user %s: %w", u.GetName(), err) @@ -496,32 +496,25 @@ func GetOrgRepos(c *gin.Context) { // capture the sort_by query parameter if present sortBy := util.QueryParameter(c, "sort_by", "name") + // capture the query parameters if present: + // + // * active + filters := map[string]interface{}{ + "active": util.QueryParameter(c, "active", "true"), + } + // See if the user is an org admin to bypass individual permission checks perm, err := scm.FromContext(c).OrgAccess(u, o) if err != nil { logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) } - - filters := map[string]string{} // Only show public repos to non-admins if perm != "admin" { - filters["visibility"] = "public" - } - - filters["active"] = util.QueryParameter(c, "active", "true") - - // send API call to capture the total number of repos for the org - t, err := database.FromContext(c).GetOrgRepoCount(o, filters) - if err != nil { - retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return + filters["visibility"] = constants.VisibilityPublic } // send API call to capture the list of repos for the org - r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, perPage, sortBy) + r, t, err := database.FromContext(c).ListReposForOrg(o, sortBy, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", o, err) @@ -807,7 +800,7 @@ func UpdateRepo(c *gin.Context) { } // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) + r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) c.JSON(http.StatusOK, r) } diff --git a/api/scm.go b/api/scm.go index 4ad82015c..b497768cd 100644 --- a/api/scm.go +++ b/api/scm.go @@ -15,6 +15,7 @@ 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/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) @@ -69,14 +70,14 @@ func SyncRepos(c *gin.Context) { logger.Errorf("unable to get user %s access level for org %s", u.GetName(), o) } - filters := map[string]string{} + filters := map[string]interface{}{} // Only show public repos to non-admins if perm != "admin" { - filters["visibility"] = "public" + filters["visibility"] = constants.VisibilityPublic } // send API call to capture the total number of repos for the org - t, err := database.FromContext(c).GetOrgRepoCount(o, filters) + t, err := database.FromContext(c).CountReposForOrg(o, filters) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) @@ -89,7 +90,7 @@ func SyncRepos(c *gin.Context) { page := 0 // capture all repos belonging to a certain org in database for orgRepos := int64(0); orgRepos < t; orgRepos += 100 { - r, err := database.FromContext(c).GetOrgRepoList(o, filters, page, 100, "name") + r, _, err := database.FromContext(c).ListReposForOrg(o, "name", filters, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) diff --git a/api/user.go b/api/user.go index f22108c58..37c66d82d 100644 --- a/api/user.go +++ b/api/user.go @@ -432,11 +432,11 @@ func GetUserSourceRepos(c *gin.Context) { for org := range output { // capture source repos from the database backend, grouped by org page := 1 - filters := map[string]string{} + filters := map[string]interface{}{} for page > 0 { // send API call to capture the list of repos for the org - dbReposPart, err := database.FromContext(c).GetOrgRepoList(org, filters, page, 100, "name") + dbReposPart, _, err := database.FromContext(c).ListReposForOrg(org, "name", filters, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) diff --git a/api/webhook.go b/api/webhook.go index 76007bbe6..b9046b38e 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -172,7 +172,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture parsed repo from webhook - r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) + r, err = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -414,7 +414,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture repo for the counter - r, err = database.FromContext(c).GetRepo(r.GetOrg(), r.GetName()) + r, err = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) if err != nil { retErr := fmt.Errorf("%s: unable to get repo %s: %w", baseErr, r.GetFullName(), err) @@ -729,7 +729,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types // get the old name of the repo previousName := r.GetPreviousName() // get the repo from the database that matches the old name - dbR, err := database.FromContext(c).GetRepo(r.GetOrg(), previousName) + dbR, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), previousName) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s/%s from database", baseErr, r.GetOrg(), previousName) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/database/pipeline/get.go b/database/pipeline/get.go index 14f1b35a8..e8eb4b23a 100644 --- a/database/pipeline/get.go +++ b/database/pipeline/get.go @@ -21,8 +21,7 @@ func (e *engine) GetPipeline(id int64) (*library.Pipeline, error) { err := e.client. Table(constants.TablePipeline). Where("id = ?", id). - Limit(1). - Scan(p). + Take(p). Error if err != nil { return nil, err diff --git a/database/pipeline/get_repo.go b/database/pipeline/get_repo.go index 6df601b08..1d431ca10 100644 --- a/database/pipeline/get_repo.go +++ b/database/pipeline/get_repo.go @@ -27,8 +27,7 @@ func (e *engine) GetPipelineForRepo(commit string, r *library.Repo) (*library.Pi Table(constants.TablePipeline). Where("repo_id = ?", r.GetID()). Where("\"commit\" = ?", commit). - Limit(1). - Scan(p). + Take(p). Error if err != nil { return nil, err diff --git a/database/postgres/ddl/repo.go b/database/postgres/ddl/repo.go deleted file mode 100644 index f9b01d274..000000000 --- a/database/postgres/ddl/repo.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateRepoTable represents a query to - // create the repos table for Vela. - CreateRepoTable = ` -CREATE TABLE -IF NOT EXISTS -repos ( - id SERIAL PRIMARY KEY, - user_id INTEGER, - hash VARCHAR(500), - org VARCHAR(250), - name VARCHAR(250), - full_name VARCHAR(500), - link VARCHAR(1000), - clone VARCHAR(1000), - branch VARCHAR(250), - build_limit INTEGER, - timeout INTEGER, - counter INTEGER, - visibility TEXT, - private BOOLEAN, - trusted BOOLEAN, - active BOOLEAN, - allow_pull BOOLEAN, - allow_push BOOLEAN, - allow_deploy BOOLEAN, - allow_tag BOOLEAN, - allow_comment BOOLEAN, - pipeline_type TEXT, - previous_name VARCHAR(100), - UNIQUE(full_name) -); -` - - // CreateRepoOrgNameIndex represents a query to create an - // index on the repos table for the org and name columns. - CreateRepoOrgNameIndex = ` -CREATE INDEX -IF NOT EXISTS -repos_org_name -ON repos (org, name); -` -) diff --git a/database/postgres/dml/repo.go b/database/postgres/dml/repo.go deleted file mode 100644 index 5a1f96cfe..000000000 --- a/database/postgres/dml/repo.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListRepos represents a query to - // list all repos in the database. - ListRepos = ` -SELECT * -FROM repos; -` - - // ListUserRepos represents a query to list - // all repos for a user_id in the database. - ListUserRepos = ` -SELECT * -FROM repos -WHERE user_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectRepo represents a query to select a - // repo for an org and name in the database. - SelectRepo = ` -SELECT * -FROM repos -WHERE org = ? -AND name = ? -LIMIT 1; -` - - // SelectUserReposCount represents a query to select - // the count of repos for a user_id in the database. - SelectUserReposCount = ` -SELECT count(*) as count -FROM repos -WHERE user_id = ?; -` - - // SelectReposCount represents a query to select - // the count of repos in the database. - SelectReposCount = ` -SELECT count(*) as count -FROM repos; -` - - // DeleteRepo represents a query to - // remove a repo from the database. - DeleteRepo = ` -DELETE -FROM repos -WHERE id = ?; -` - - // ListReposByLastUpdate represents a query to list - // all repos in an org, ordered by latest activity. - // In this case, latest activity is synonymous with - // the created timestamp of the last build for the repo. - ListReposByLastUpdate = ` -SELECT r.* -FROM repos r LEFT JOIN ( - SELECT repos.id, MAX(builds.created) as latest_build - FROM builds INNER JOIN repos - ON builds.repo_id = repos.id - WHERE repos.org = ? - GROUP BY repos.id) t -ON r.id = t.id -ORDER BY latest_build DESC NULLS LAST -LIMIT ? -OFFSET ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index a2a446947..263b229a7 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -11,6 +11,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" + "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -45,6 +46,8 @@ type ( Logger *logrus.Entry // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService + // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService + repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService } @@ -145,6 +148,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -245,12 +250,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) } - // create the repos table - err = c.Postgres.Exec(ddl.CreateRepoTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) - } - // create the secrets table err = c.Postgres.Exec(ddl.CreateSecretTable).Error if err != nil { @@ -319,12 +318,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) } - // create the repos_org_name index for the repos table - err = c.Postgres.Exec(ddl.CreateRepoOrgNameIndex).Error - if err != nil { - return fmt.Errorf("unable to create repos_org_name index for the %s table: %w", constants.TableRepo, err) - } - // create the secrets_type_org_repo index for the secrets table err = c.Postgres.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { @@ -369,6 +362,19 @@ func createServices(c *client) error { return err } + // create the database agnostic repo service + // + // https://pkg.go.dev/github.com/go-vela/server/database/repo#New + c.RepoService, err = repo.New( + repo.WithClient(c.Postgres), + repo.WithEncryptionKey(c.config.EncryptionKey), + repo.WithLogger(c.Logger), + repo.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index e66919618..53375a1e7 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -12,7 +12,9 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" + "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" + "github.com/go-vela/types/library" ) func TestPostgres_New(t *testing.T) { @@ -77,7 +79,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateRepoTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -90,13 +91,16 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateRepoOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // setup the skip test database client _skipDatabase, _skipMock, err := NewTest() @@ -160,7 +164,6 @@ func TestPostgres_createTables(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateRepoTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -209,7 +212,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateRepoOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -254,6 +256,8 @@ func TestPostgres_createServices(t *testing.T) { // ensure the mock expects the index queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -295,3 +299,39 @@ type AnyArgument struct{} func (a AnyArgument) Match(v driver.Value) bool { return true } + +// testRepo is a test helper function to create a +// library Repo type with all fields set to their +// zero values. +func testRepo() *library.Repo { + i64 := int64(0) + i := 0 + str := "" + b := false + + return &library.Repo{ + ID: &i64, + PipelineType: &str, + UserID: &i64, + Hash: &str, + Org: &str, + Name: &str, + FullName: &str, + Link: &str, + Clone: &str, + Branch: &str, + BuildLimit: &i64, + Timeout: &i64, + Counter: &i, + Visibility: &str, + Private: &b, + Trusted: &b, + Active: &b, + AllowPull: &b, + AllowPush: &b, + AllowDeploy: &b, + AllowTag: &b, + AllowComment: &b, + PreviousName: &str, + } +} diff --git a/database/postgres/repo.go b/database/postgres/repo.go deleted file mode 100644 index 1f39f3c1a..000000000 --- a/database/postgres/repo.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - "fmt" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetRepo gets a repo by org and name from the database. -func (c *client) GetRepo(org, name string) (*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - "repo": name, - }).Tracef("getting repo %s/%s from the database", org, name) - - // variable to store query results - r := new(database.Repo) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableRepo). - Raw(dml.SelectRepo, org, name). - Scan(r) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err := r.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %s/%s: %v", org, name, err) - - // return the unencrypted repo - return r.ToLibrary(), result.Error - } - - // return the decrypted repo - return r.ToLibrary(), result.Error -} - -// CreateRepo creates a new repo in the database. -// -//nolint:dupl // ignore similar code with update -func (c *client) CreateRepo(r *library.Repo) error { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("creating repo %s in the database", r.GetFullName()) - - // cast to database type - repo := database.RepoFromLibrary(r) - - // validate the necessary fields are populated - err := repo.Validate() - if err != nil { - return err - } - - // encrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt - err = repo.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableRepo). - Create(repo).Error -} - -// UpdateRepo updates a repo in the database. -// -//nolint:dupl // ignore similar code with create -func (c *client) UpdateRepo(r *library.Repo) error { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("updating repo %s in the database", r.GetFullName()) - - // cast to database type - repo := database.RepoFromLibrary(r) - - // validate the necessary fields are populated - err := repo.Validate() - if err != nil { - return err - } - - // encrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt - err = repo.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableRepo). - Save(repo).Error -} - -// DeleteRepo deletes a repo by unique ID from the database. -func (c *client) DeleteRepo(id int64) error { - c.Logger.Tracef("deleting repo %d in the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableRepo). - Exec(dml.DeleteRepo, id).Error -} diff --git a/database/postgres/repo_count.go b/database/postgres/repo_count.go deleted file mode 100644 index aa3408c1a..000000000 --- a/database/postgres/repo_count.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetRepoCount gets a count of all repos from the database. -func (c *client) GetRepoCount() (int64, error) { - c.Logger.Trace("getting count of repos from the database") - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Raw(dml.SelectReposCount). - Pluck("count", &r).Error - - return r, err -} - -// GetOrgRepoCount gets a count of all repos for a specific org from the database. -func (c *client) GetOrgRepoCount(org string, filters map[string]string) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("getting count of repos for org %s from the database", org) - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Select("count(*)"). - Where("org = ?", org). - Where(filters). - Pluck("count", &r).Error - - return r, err -} - -// GetUserRepoCount gets a count of all repos for a specific user from the database. -func (c *client) GetUserRepoCount(u *library.User) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("getting count of repos for user %s in the database", u.GetName()) - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Raw(dml.SelectUserReposCount, u.GetID()). - Pluck("count", &r).Error - - return r, err -} diff --git a/database/postgres/repo_count_test.go b/database/postgres/repo_count_test.go deleted file mode 100644 index 324915eb5..000000000 --- a/database/postgres/repo_count_test.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectReposCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetRepoCount() - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetUserRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - _user := new(library.User) - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectUserReposCount, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUserRepoCount(_user) - - if test.failure { - if err == nil { - t.Errorf("GetUserRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"repos\" WHERE org = $1").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 1, - }, - } - filters := map[string]string{} - // run tests - for _, test := range tests { - got, err := _database.GetOrgRepoCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgRepoCount_NonAdmin(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("private") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"repos\" WHERE org = $1 AND \"visibility\" = $2").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 1, - }, - } - filters := map[string]string{} - filters["visibility"] = "private" - // run tests - for _, test := range tests { - got, err := _database.GetOrgRepoCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/repo_list.go b/database/postgres/repo_list.go deleted file mode 100644 index 7b10a168d..000000000 --- a/database/postgres/repo_list.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetRepoList gets a list of all repos from the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) GetRepoList() ([]*library.Repo, error) { - c.Logger.Trace("listing repos from the database") - - // variable to store query results - r := new([]database.Repo) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Raw(dml.ListRepos). - Scan(r).Error - if err != nil { - return nil, err - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} - -// GetOrgRepoList gets a list of all repos by org from the database. -func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int, sortBy string) ([]*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("listing repos for org %s from the database", org) - - // variable to store query results - r := new([]database.Repo) - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - switch sortBy { - case "latest": - err := c.Postgres. - Table(constants.TableRepo). - Raw(dml.ListReposByLastUpdate, org, perPage, offset). - Scan(r).Error - if err != nil { - return nil, err - } - default: - err := c.Postgres. - Table(constants.TableRepo). - Where("org = ?", org). - Where(filters). - Order("name"). - Limit(perPage). - Offset(offset). - Scan(r).Error - if err != nil { - return nil, err - } - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err := tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} - -// GetUserRepoList gets a list of all repos by user ID from the database. -func (c *client) GetUserRepoList(u *library.User, page, perPage int) ([]*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("listing repos for user %s from the database", u.GetName()) - - // variable to store query results - r := new([]database.Repo) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableRepo). - Raw(dml.ListUserRepos, u.GetID(), perPage, offset). - Scan(r).Error - if err != nil { - return nil, err - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} diff --git a/database/postgres/repo_list_test.go b/database/postgres/repo_list_test.go deleted file mode 100644 index 65871d82f..000000000 --- a/database/postgres/repo_list_test.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListRepos).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", ""). - AddRow(1, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "oldName") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetRepoList() - - if test.failure { - if err == nil { - t.Errorf("GetRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", ""). - AddRow(1, 1, "baz", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "oldName") - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT * FROM \"repos\" WHERE org = $1 ORDER BY name LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - filters := map[string]string{} - // run tests - for _, test := range tests { - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgRepoList_LastUpdate(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListReposByLastUpdate, "foo", "10", "1").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", ""). - AddRow(1, 1, "baz", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "oldName") - - // ensure the mock expects the query for test case - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - filters := map[string]string{} - // run tests - for _, test := range tests { - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "latest") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgRepoList_NonAdmin(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("private") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT * FROM \"repos\" WHERE org = $1 AND \"visibility\" = $2 ORDER BY name LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne}, - }, - } - filters := map[string]string{} - filters["visibility"] = "public" - // run tests - for _, test := range tests { - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetUserRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(1) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("") - - _user := new(library.User) - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListUserRepos, 1, 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", ""). - AddRow(1, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetUserRepoList(_user, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetUserRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserRepoList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/repo_test.go b/database/postgres/repo_test.go deleted file mode 100644 index b95d3ecc3..000000000 --- a/database/postgres/repo_test.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPipelineType("yaml") - _repo.SetPreviousName("") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepo, "foo", "bar").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}, - ).AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Repo - }{ - { - failure: false, - want: _repo, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetRepo("foo", "bar") - - if test.failure { - if err == nil { - t.Errorf("GetRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepo returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepo is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPipelineType("yaml") - _repo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "repos" ("user_id","hash","org","name","full_name","link","clone","branch","build_limit","timeout","counter","visibility","private","trusted","active","allow_pull","allow_push","allow_deploy","allow_tag","allow_comment","pipeline_type","previous_name","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23) RETURNING "id"`). - WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateRepo(_repo) - - if test.failure { - if err == nil { - t.Errorf("CreateRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateRepo returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPipelineType("yaml") - _repo.SetPreviousName("oldName") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "repos" SET "user_id"=$1,"hash"=$2,"org"=$3,"name"=$4,"full_name"=$5,"link"=$6,"clone"=$7,"branch"=$8,"build_limit"=$9,"timeout"=$10,"counter"=$11,"visibility"=$12,"private"=$13,"trusted"=$14,"active"=$15,"allow_pull"=$16,"allow_push"=$17,"allow_deploy"=$18,"allow_tag"=$19,"allow_comment"=$20,"pipeline_type"=$21,"previous_name"=$22 WHERE "id" = $23`). - WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateRepo(_repo) - - if test.failure { - if err == nil { - t.Errorf("UpdateRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateRepo returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteRepo(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteRepo, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteRepo(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteRepo returned err: %v", err) - } - } -} - -// testRepo is a test helper function to create a -// library Repo type with all fields set to their -// zero values. -func testRepo() *library.Repo { - i64 := int64(0) - i := 0 - str := "" - b := false - - return &library.Repo{ - ID: &i64, - PipelineType: &str, - UserID: &i64, - Hash: &str, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - BuildLimit: &i64, - Timeout: &i64, - Counter: &i, - Visibility: &str, - Private: &b, - Trusted: &b, - Active: &b, - AllowPull: &b, - AllowPush: &b, - AllowDeploy: &b, - AllowTag: &b, - AllowComment: &b, - PreviousName: &str, - } -} diff --git a/database/repo/count.go b/database/repo/count.go new file mode 100644 index 000000000..032e7d780 --- /dev/null +++ b/database/repo/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" +) + +// CountRepos gets the count of all repos from the database. +func (e *engine) CountRepos() (int64, error) { + e.logger.Tracef("getting count of all repos from the database") + + // variable to store query results + var r int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableRepo). + Count(&r). + Error + + return r, err +} diff --git a/database/repo/count_org.go b/database/repo/count_org.go new file mode 100644 index 000000000..938f151c6 --- /dev/null +++ b/database/repo/count_org.go @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// CountReposForOrg gets the count of repos by org name from the database. +func (e *engine) CountReposForOrg(org string, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + }).Tracef("getting count of repos for org %s from the database", org) + + // variable to store query results + var r int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableRepo). + Where("org = ?", org). + Where(filters). + Count(&r). + Error + + return r, err +} diff --git a/database/repo/count_org_test.go b/database/repo/count_org_test.go new file mode 100644 index 000000000..2ff3278f3 --- /dev/null +++ b/database/repo/count_org_test.go @@ -0,0 +1,101 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_CountReposForOrg(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("bar") + _repoTwo.SetName("foo") + _repoTwo.SetFullName("bar/foo") + _repoTwo.SetVisibility("public") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE org = $1`).WithArgs("foo").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountReposForOrg("foo", filters) + + if test.failure { + if err == nil { + t.Errorf("CountReposForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountReposForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountReposForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/count_test.go b/database/repo/count_test.go new file mode 100644 index 000000000..f63a935e8 --- /dev/null +++ b/database/repo/count_test.go @@ -0,0 +1,99 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_CountRepos(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("bar") + _repoTwo.SetName("foo") + _repoTwo.SetFullName("bar/foo") + _repoTwo.SetVisibility("public") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "repos"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountRepos() + + if test.failure { + if err == nil { + t.Errorf("CountRepos for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountRepos for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountRepos for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/count_user.go b/database/repo/count_user.go new file mode 100644 index 000000000..dbd226dac --- /dev/null +++ b/database/repo/count_user.go @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountReposForUser gets the count of repos by user ID from the database. +func (e *engine) CountReposForUser(u *library.User, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Tracef("getting count of repos for user %s from the database", u.GetName()) + + // variable to store query results + var r int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableRepo). + Where("user_id = ?", u.GetID()). + Where(filters). + Count(&r). + Error + + return r, err +} diff --git a/database/repo/count_user_test.go b/database/repo/count_user_test.go new file mode 100644 index 000000000..654788a69 --- /dev/null +++ b/database/repo/count_user_test.go @@ -0,0 +1,107 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestRepo_Engine_CountReposForUser(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("bar") + _repoTwo.SetName("foo") + _repoTwo.SetFullName("bar/foo") + _repoTwo.SetVisibility("public") + + _user := new(library.User) + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE user_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountReposForUser(_user, filters) + + if test.failure { + if err == nil { + t.Errorf("CountReposForUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountReposForUser for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountReposForUser for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/create.go b/database/repo/create.go new file mode 100644 index 000000000..fbfda486a --- /dev/null +++ b/database/repo/create.go @@ -0,0 +1,50 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with update.go +package repo + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateRepo creates a new repo in the database. +func (e *engine) CreateRepo(r *library.Repo) error { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("creating repo %s in the database", r.GetFullName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#RepoFromLibrary + repo := database.RepoFromLibrary(r) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Validate + err := repo.Validate() + if err != nil { + return err + } + + // encrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt + err = repo.Encrypt(e.config.EncryptionKey) + if err != nil { + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) + } + + // send query to the database + return e.client. + Table(constants.TableRepo). + Create(repo). + Error +} diff --git a/database/repo/create_test.go b/database/repo/create_test.go new file mode 100644 index 000000000..e2ab70417 --- /dev/null +++ b/database/repo/create_test.go @@ -0,0 +1,78 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_CreateRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + _repo.SetPreviousName("oldName") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "repos" +("user_id","hash","org","name","full_name","link","clone","branch","build_limit","timeout","counter","visibility","private","trusted","active","allow_pull","allow_push","allow_deploy","allow_tag","allow_comment","pipeline_type","previous_name","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23) RETURNING "id"`). + WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("CreateRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateRepo for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/repo/delete.go b/database/repo/delete.go new file mode 100644 index 000000000..64a515610 --- /dev/null +++ b/database/repo/delete.go @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteRepo deletes an existing repo from the database. +func (e *engine) DeleteRepo(r *library.Repo) error { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("deleting repo %s from the database", r.GetFullName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#RepoFromLibrary + repo := database.RepoFromLibrary(r) + + // send query to the database + return e.client. + Table(constants.TableRepo). + Delete(repo). + Error +} diff --git a/database/repo/delete_test.go b/database/repo/delete_test.go new file mode 100644 index 000000000..ccc50eb4a --- /dev/null +++ b/database/repo/delete_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_DeleteRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "repos" WHERE "repos"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("DeleteRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteRepo for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/repo/get.go b/database/repo/get.go new file mode 100644 index 000000000..5a162ffb2 --- /dev/null +++ b/database/repo/get.go @@ -0,0 +1,52 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetRepo gets a repo by ID from the database. +func (e *engine) GetRepo(id int64) (*library.Repo, error) { + e.logger.Tracef("getting repo %d from the database", id) + + // variable to store query results + r := new(database.Repo) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableRepo). + Where("id = ?", id). + Take(r). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err = r.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted repos + e.logger.Errorf("unable to decrypt repo %d: %v", id, err) + + // return the unencrypted repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + return r.ToLibrary(), nil + } + + // return the decrypted repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + return r.ToLibrary(), nil +} diff --git a/database/repo/get_org.go b/database/repo/get_org.go new file mode 100644 index 000000000..f03260b99 --- /dev/null +++ b/database/repo/get_org.go @@ -0,0 +1,57 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetRepoForOrg gets a repo by org and repo name from the database. +func (e *engine) GetRepoForOrg(org, name string) (*library.Repo, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + }).Tracef("getting repo %s/%s from the database", org, name) + + // variable to store query results + r := new(database.Repo) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableRepo). + Where("org = ?", org). + Where("name = ?", name). + Take(r). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err = r.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted repos + e.logger.Errorf("unable to decrypt repo %s/%s: %v", org, name, err) + + // return the unencrypted repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + return r.ToLibrary(), nil + } + + // return the decrypted repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + return r.ToLibrary(), nil +} diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go new file mode 100644 index 000000000..e5b545c1f --- /dev/null +++ b/database/repo/get_org_test.go @@ -0,0 +1,89 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestRepo_Engine_GetRepoForName(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE org = $1 AND name = $2 LIMIT 1`).WithArgs("foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Repo + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _repo, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _repo, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetRepoForOrg("foo", "bar") + + if test.failure { + if err == nil { + t.Errorf("GetRepoForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetRepoForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetRepoForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/get_test.go b/database/repo/get_test.go new file mode 100644 index 000000000..d5fd926be --- /dev/null +++ b/database/repo/get_test.go @@ -0,0 +1,89 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestRepo_Engine_GetRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Repo + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _repo, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _repo, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetRepo(1) + + if test.failure { + if err == nil { + t.Errorf("GetRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/index.go b/database/repo/index.go new file mode 100644 index 000000000..d112cccad --- /dev/null +++ b/database/repo/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +const ( + // CreateOrgNameIndex represents a query to create an + // index on the repos table for the org and name columns. + CreateOrgNameIndex = ` +CREATE INDEX +IF NOT EXISTS +repos_org_name +ON repos (org, name); +` +) + +// CreateRepoIndexes creates the indexes for the repos table in the database. +func (e *engine) CreateRepoIndexes() error { + e.logger.Tracef("creating indexes for repos table in the database") + + // create the repo_id column index for the repos table + return e.client.Exec(CreateOrgNameIndex).Error +} diff --git a/database/repo/index_test.go b/database/repo/index_test.go new file mode 100644 index 000000000..90550cae8 --- /dev/null +++ b/database/repo/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_CreateRepoIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateRepoIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateRepoIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateRepoIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/repo/list.go b/database/repo/list.go new file mode 100644 index 000000000..1b9b5d11c --- /dev/null +++ b/database/repo/list.go @@ -0,0 +1,67 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListRepos gets a list of all repos from the database. +func (e *engine) ListRepos() ([]*library.Repo, error) { + e.logger.Trace("listing all repos from the database") + + // variables to store query results and return value + count := int64(0) + r := new([]database.Repo) + repos := []*library.Repo{} + + // count the results + count, err := e.CountRepos() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return repos, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableRepo). + Find(&r). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, repo := range *r { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := repo + + // decrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted repos + e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + repos = append(repos, tmp.ToLibrary()) + } + + return repos, nil +} diff --git a/database/repo/list_org.go b/database/repo/list_org.go new file mode 100644 index 000000000..c673d2d88 --- /dev/null +++ b/database/repo/list_org.go @@ -0,0 +1,104 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListReposForOrg gets a list of repos by org name from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListReposForOrg(org, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + }).Tracef("listing repos for org %s from the database", org) + + // variables to store query results and return values + count := int64(0) + r := new([]database.Repo) + repos := []*library.Repo{} + + // count the results + count, err := e.CountReposForOrg(org, filters) + if err != nil { + return repos, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return repos, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + switch sortBy { + case "latest": + query := e.client. + Table(constants.TableBuild). + Select("repos.id, MAX(builds.created) AS latest_build"). + Joins("INNER JOIN repos repos ON builds.repo_id = repos.id"). + Where("repos.org = ?", org). + Group("repos.id") + + err = e.client. + Table(constants.TableRepo). + Select("repos.*"). + Joins("LEFT JOIN (?) t on repos.id = t.id", query). + Order("latest_build DESC NULLS LAST"). + Limit(perPage). + Offset(offset). + Find(&r). + Error + if err != nil { + return nil, count, err + } + case "name": + fallthrough + default: + err = e.client. + Table(constants.TableRepo). + Where("org = ?", org). + Where(filters). + Order("name"). + Limit(perPage). + Offset(offset). + Find(&r). + Error + if err != nil { + return nil, count, err + } + } + + // iterate through all query results + for _, repo := range *r { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := repo + + // decrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted repos + e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + repos = append(repos, tmp.ToLibrary()) + } + + return repos, count, nil +} diff --git a/database/repo/list_org_test.go b/database/repo/list_org_test.go new file mode 100644 index 000000000..fdfa80779 --- /dev/null +++ b/database/repo/list_org_test.go @@ -0,0 +1,175 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "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()) + + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("bar") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE org = $1`).WithArgs("foo").WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE org = $1 ORDER BY name LIMIT 10`).WithArgs("foo").WillReturnRows(_rows) + + // create expected latest count query result in mock + _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the latest count query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE org = $1`).WithArgs("foo").WillReturnRows(_rows) + + // create expected latest query result in mock + _rows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + + // ensure the mock expects the latest query + _mock.ExpectQuery(`SELECT repos.* FROM "repos" LEFT JOIN (SELECT repos.id, MAX(builds.created) AS latest_build FROM "builds" INNER JOIN repos repos ON builds.repo_id = repos.id WHERE repos.org = $1 GROUP BY "repos"."id") t on repos.id = t.id ORDER BY latest_build DESC NULLS LAST LIMIT 10`).WithArgs("foo").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&database.Build{}) + 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 + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildTwo).Crop()).Error + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + sort string + database *engine + want []*library.Repo + }{ + { + failure: false, + name: "postgres with name", + database: _postgres, + sort: "name", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "postgres with latest", + database: _postgres, + sort: "latest", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "sqlite with name", + database: _sqlite, + sort: "name", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "sqlite with latest", + database: _sqlite, + sort: "latest", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListReposForOrg("foo", test.sort, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListReposForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListReposForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListReposForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/list_test.go b/database/repo/list_test.go new file mode 100644 index 000000000..86b9968fe --- /dev/null +++ b/database/repo/list_test.go @@ -0,0 +1,111 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestRepo_Engine_ListRepos(t *testing.T) { + // setup types + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("bar") + _repoTwo.SetName("foo") + _repoTwo.SetFullName("bar/foo") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "repos"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "repos"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Repo + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Repo{_repoOne, _repoTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListRepos() + + if test.failure { + if err == nil { + t.Errorf("ListRepos for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListRepos for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListRepos for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/list_user.go b/database/repo/list_user.go new file mode 100644 index 000000000..a28a466aa --- /dev/null +++ b/database/repo/list_user.go @@ -0,0 +1,104 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListReposForUser gets a list of repos by user ID from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListReposForUser(u *library.User, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { + e.logger.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Tracef("listing repos for user %s from the database", u.GetName()) + + // variables to store query results and return values + count := int64(0) + r := new([]database.Repo) + repos := []*library.Repo{} + + // count the results + count, err := e.CountReposForUser(u, filters) + if err != nil { + return repos, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return repos, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + switch sortBy { + case "latest": + query := e.client. + Table(constants.TableBuild). + Select("repos.id, MAX(builds.created) AS latest_build"). + Joins("INNER JOIN repos repos ON builds.repo_id = repos.id"). + Where("repos.user_id = ?", u.GetID()). + Group("repos.id") + + err = e.client. + Table(constants.TableRepo). + Select("repos.*"). + Joins("LEFT JOIN (?) t on repos.id = t.id", query). + Order("latest_build DESC NULLS LAST"). + Limit(perPage). + Offset(offset). + Find(&r). + Error + if err != nil { + return nil, count, err + } + case "name": + fallthrough + default: + err = e.client. + Table(constants.TableRepo). + Where("user_id = ?", u.GetID()). + Where(filters). + Order("name"). + Limit(perPage). + Offset(offset). + Find(&r). + Error + if err != nil { + return nil, count, err + } + } + + // iterate through all query results + for _, repo := range *r { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := repo + + // decrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted repos + e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary + repos = append(repos, tmp.ToLibrary()) + } + + return repos, count, nil +} diff --git a/database/repo/list_user_test.go b/database/repo/list_user_test.go new file mode 100644 index 000000000..0e1cc8336 --- /dev/null +++ b/database/repo/list_user_test.go @@ -0,0 +1,180 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "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()) + + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("baz") + _repoTwo.SetOrg("bar") + _repoTwo.SetName("foo") + _repoTwo.SetFullName("bar/foo") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + + _user := new(library.User) + _user.SetID(1) + _user.SetName("foo") + _user.SetToken("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE user_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE user_id = $1 ORDER BY name LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + // create expected latest count query result in mock + _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the latest count query + _mock.ExpectQuery(`SELECT count(*) FROM "repos" WHERE user_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected latest query result in mock + _rows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + + // ensure the mock expects the latest query + _mock.ExpectQuery(`SELECT repos.* FROM "repos" LEFT JOIN (SELECT repos.id, MAX(builds.created) AS latest_build FROM "builds" INNER JOIN repos repos ON builds.repo_id = repos.id WHERE repos.user_id = $1 GROUP BY "repos"."id") t on repos.id = t.id ORDER BY latest_build DESC NULLS LAST LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repoOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateRepo(_repoTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&database.Build{}) + 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 + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildTwo).Crop()).Error + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + sort string + database *engine + want []*library.Repo + }{ + { + failure: false, + name: "postgres with name", + database: _postgres, + sort: "name", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "postgres with latest", + database: _postgres, + sort: "latest", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "sqlite with name", + database: _sqlite, + sort: "name", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + { + failure: false, + name: "sqlite with latest", + database: _sqlite, + sort: "latest", + want: []*library.Repo{_repoOne, _repoTwo}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListReposForUser(_user, test.sort, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListReposForUser for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListReposForUser for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListReposForUser for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/repo/opts.go b/database/repo/opts.go new file mode 100644 index 000000000..95957a598 --- /dev/null +++ b/database/repo/opts.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Repos. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Repos. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the repo engine + e.client = client + + return nil + } +} + +// 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 Repos. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the repo engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Repos. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the repo engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/repo/opts_test.go b/database/repo/opts_test.go new file mode 100644 index 000000000..78bfb826e --- /dev/null +++ b/database/repo/opts_test.go @@ -0,0 +1,210 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestRepo_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestRepo_EngineOpt_WithEncryptionKey(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + key string + want string + }{ + { + failure: false, + name: "encryption key set", + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + }, + { + failure: false, + name: "encryption key not set", + key: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithEncryptionKey(test.key)(e) + + if test.failure { + if err == nil { + t.Errorf("WithEncryptionKey for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithEncryptionKey returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.EncryptionKey, test.want) { + t.Errorf("WithEncryptionKey is %v, want %v", e.config.EncryptionKey, test.want) + } + }) + } +} + +func TestRepo_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestRepo_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/repo/repo.go b/database/repo/repo.go new file mode 100644 index 000000000..e0f768741 --- /dev/null +++ b/database/repo/repo.go @@ -0,0 +1,82 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the RepoService interface. + config struct { + // specifies the encryption key to use for the Repo engine + EncryptionKey string + // specifies to skip creating tables and indexes for the Repo engine + SkipCreation bool + } + + // engine represents the repo functionality that implements the RepoService interface. + engine struct { + // engine configuration settings used in repo functions + config *config + + // gorm.io/gorm database client used in repo functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in repo functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with repos in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Repo engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating repo database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of repos table and indexes in the database") + + return e, nil + } + + // create the repos table + err := e.CreateRepoTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) + } + + // create the indexes for the repos table + err = e.CreateRepoIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableRepo, err) + } + + return e, nil +} diff --git a/database/repo/repo_test.go b/database/repo/repo_test.go new file mode 100644 index 000000000..8729a56f7 --- /dev/null +++ b/database/repo/repo_test.go @@ -0,0 +1,215 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestRepo_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithEncryptionKey(test.key), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres repo engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite repo engine: %v", err) + } + + return _engine +} + +// testRepo is a test helper function to create a library +// Repo type with all fields set to their zero values. +func testRepo() *library.Repo { + return &library.Repo{ + ID: new(int64), + UserID: 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), + AllowPull: new(bool), + AllowPush: new(bool), + AllowDeploy: new(bool), + AllowTag: new(bool), + AllowComment: 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(v driver.Value) bool { + return true +} diff --git a/database/repo/service.go b/database/repo/service.go new file mode 100644 index 000000000..7695333ff --- /dev/null +++ b/database/repo/service.go @@ -0,0 +1,51 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "github.com/go-vela/types/library" +) + +// RepoService represents the Vela interface for repo +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type RepoService interface { + // Repo Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateRepoIndexes defines a function that creates the indexes for the repos table. + CreateRepoIndexes() error + // CreateRepoTable defines a function that creates the repos table. + CreateRepoTable(string) error + + // Repo Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountRepos defines a function that gets the count of all repos. + CountRepos() (int64, error) + // CountReposForOrg defines a function that gets the count of repos by org name. + CountReposForOrg(string, map[string]interface{}) (int64, error) + // CountReposForUser defines a function that gets the count of repos by user ID. + CountReposForUser(*library.User, map[string]interface{}) (int64, error) + // CreateRepo defines a function that creates a new repo. + CreateRepo(*library.Repo) error + // DeleteRepo defines a function that deletes an existing repo. + DeleteRepo(*library.Repo) error + // GetRepo defines a function that gets a repo by ID. + GetRepo(int64) (*library.Repo, error) + // GetRepoForOrg defines a function that gets a repo by org and repo name. + GetRepoForOrg(string, string) (*library.Repo, error) + // ListRepos defines a function that gets a list of all repos. + ListRepos() ([]*library.Repo, error) + // ListReposForOrg defines a function that gets a list of repos by org name. + ListReposForOrg(string, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) + // ListReposForUser defines a function that gets a list of repos by user ID. + ListReposForUser(*library.User, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) + // UpdateRepo defines a function that updates an existing repo. + UpdateRepo(*library.Repo) error +} diff --git a/database/repo/table.go b/database/repo/table.go new file mode 100644 index 000000000..fc55a4a56 --- /dev/null +++ b/database/repo/table.go @@ -0,0 +1,90 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import "github.com/go-vela/types/constants" + +const ( + // CreatePostgresTable represents a query to create the Postgres repos table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +repos ( + id SERIAL PRIMARY KEY, + user_id INTEGER, + hash VARCHAR(500), + org VARCHAR(250), + name VARCHAR(250), + full_name VARCHAR(500), + link VARCHAR(1000), + clone VARCHAR(1000), + branch VARCHAR(250), + build_limit INTEGER, + timeout INTEGER, + counter INTEGER, + visibility TEXT, + private BOOLEAN, + trusted BOOLEAN, + active BOOLEAN, + allow_pull BOOLEAN, + allow_push BOOLEAN, + allow_deploy BOOLEAN, + allow_tag BOOLEAN, + allow_comment BOOLEAN, + pipeline_type TEXT, + previous_name VARCHAR(100), + UNIQUE(full_name) +); +` + + // CreateSqliteTable represents a query to create the Sqlite repos table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +repos ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER, + hash TEXT, + org TEXT, + name TEXT, + full_name TEXT, + link TEXT, + clone TEXT, + branch TEXT, + build_limit INTEGER, + timeout INTEGER, + counter INTEGER, + visibility TEXT, + private BOOLEAN, + trusted BOOLEAN, + active BOOLEAN, + allow_pull BOOLEAN, + allow_push BOOLEAN, + allow_deploy BOOLEAN, + allow_tag BOOLEAN, + allow_comment BOOLEAN, + pipeline_type TEXT, + previous_name TEXT, + UNIQUE(full_name) +); +` +) + +// CreateRepoTable creates the repos table in the database. +func (e *engine) CreateRepoTable(driver string) error { + e.logger.Tracef("creating repos table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the repos table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the repos table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/repo/table_test.go b/database/repo/table_test.go new file mode 100644 index 000000000..7680c02d6 --- /dev/null +++ b/database/repo/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_CreateRepoTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateRepoTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateRepoTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateRepoTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/repo/update.go b/database/repo/update.go new file mode 100644 index 000000000..4c31791db --- /dev/null +++ b/database/repo/update.go @@ -0,0 +1,50 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create.go +package repo + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateRepo updates an existing repo in the database. +func (e *engine) UpdateRepo(r *library.Repo) error { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("creating repo %s in the database", r.GetFullName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#RepoFromLibrary + repo := database.RepoFromLibrary(r) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Validate + err := repo.Validate() + if err != nil { + return err + } + + // encrypt the fields for the repo + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt + err = repo.Encrypt(e.config.EncryptionKey) + if err != nil { + return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) + } + + // send query to the database + return e.client. + Table(constants.TableRepo). + Save(repo). + Error +} diff --git a/database/repo/update_test.go b/database/repo/update_test.go new file mode 100644 index 000000000..db29a91dd --- /dev/null +++ b/database/repo/update_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestRepo_Engine_UpdateRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + _repo.SetPreviousName("oldName") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "repos" +SET "user_id"=$1,"hash"=$2,"org"=$3,"name"=$4,"full_name"=$5,"link"=$6,"clone"=$7,"branch"=$8,"build_limit"=$9,"timeout"=$10,"counter"=$11,"visibility"=$12,"private"=$13,"trusted"=$14,"active"=$15,"allow_pull"=$16,"allow_push"=$17,"allow_deploy"=$18,"allow_tag"=$19,"allow_comment"=$20,"pipeline_type"=$21,"previous_name"=$22 +WHERE "id" = $23`). + WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateRepo(_repo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("UpdateRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateRepo for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/service.go b/database/service.go index 785f65742..649dc0056 100644 --- a/database/service.go +++ b/database/service.go @@ -6,6 +6,7 @@ package database import ( "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" "github.com/go-vela/types/library" ) @@ -119,38 +120,9 @@ type Service interface { // related to pipelines stored in the database. pipeline.PipelineService - // Repo Database Interface Functions - - // GetRepo defines a function that - // gets a repo by org and name. - GetRepo(string, string) (*library.Repo, error) - // GetRepoList defines a function that - // gets a list of all repos. - GetRepoList() ([]*library.Repo, error) - // GetOrgRepoList defines a function that - // gets a list of all repos by org excluding repos specified. - GetOrgRepoList(string, map[string]string, int, int, string) ([]*library.Repo, error) - // GetOrgRepoCount defines a function that - // gets the count of repos for an org. - GetOrgRepoCount(string, map[string]string) (int64, error) - // GetRepoCount defines a function that - // gets the count of repos. - GetRepoCount() (int64, error) - // GetUserRepoList defines a function - // that gets a list of repos by user ID. - GetUserRepoList(*library.User, int, int) ([]*library.Repo, error) - // GetUserRepoCount defines a function that - // gets the count of repos for a user. - GetUserRepoCount(*library.User) (int64, error) - // CreateRepo defines a function that - // creates a new repo. - CreateRepo(*library.Repo) error - // UpdateRepo defines a function that - // updates a repo. - UpdateRepo(*library.Repo) error - // DeleteRepo defines a function that - // deletes a repo by unique ID. - DeleteRepo(int64) error + // RepoService provides the interface for functionality + // related to repos stored in the database. + repo.RepoService // Secret Database Interface Functions diff --git a/database/sqlite/ddl/repo.go b/database/sqlite/ddl/repo.go deleted file mode 100644 index 2fcb723c1..000000000 --- a/database/sqlite/ddl/repo.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateRepoTable represents a query to - // create the repos table for Vela. - CreateRepoTable = ` -CREATE TABLE -IF NOT EXISTS -repos ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER, - hash TEXT, - org TEXT, - name TEXT, - full_name TEXT, - link TEXT, - clone TEXT, - branch TEXT, - build_limit INTEGER, - timeout INTEGER, - counter INTEGER, - visibility TEXT, - private BOOLEAN, - trusted BOOLEAN, - active BOOLEAN, - allow_pull BOOLEAN, - allow_push BOOLEAN, - allow_deploy BOOLEAN, - allow_tag BOOLEAN, - allow_comment BOOLEAN, - pipeline_type TEXT, - previous_name TEXT, - UNIQUE(full_name) -); -` - - // CreateRepoOrgNameIndex represents a query to create an - // index on the repos table for the org and name columns. - CreateRepoOrgNameIndex = ` -CREATE INDEX -IF NOT EXISTS -repos_org_name -ON repos (org, name); -` -) diff --git a/database/sqlite/dml/repo.go b/database/sqlite/dml/repo.go deleted file mode 100644 index 5a1f96cfe..000000000 --- a/database/sqlite/dml/repo.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListRepos represents a query to - // list all repos in the database. - ListRepos = ` -SELECT * -FROM repos; -` - - // ListUserRepos represents a query to list - // all repos for a user_id in the database. - ListUserRepos = ` -SELECT * -FROM repos -WHERE user_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectRepo represents a query to select a - // repo for an org and name in the database. - SelectRepo = ` -SELECT * -FROM repos -WHERE org = ? -AND name = ? -LIMIT 1; -` - - // SelectUserReposCount represents a query to select - // the count of repos for a user_id in the database. - SelectUserReposCount = ` -SELECT count(*) as count -FROM repos -WHERE user_id = ?; -` - - // SelectReposCount represents a query to select - // the count of repos in the database. - SelectReposCount = ` -SELECT count(*) as count -FROM repos; -` - - // DeleteRepo represents a query to - // remove a repo from the database. - DeleteRepo = ` -DELETE -FROM repos -WHERE id = ?; -` - - // ListReposByLastUpdate represents a query to list - // all repos in an org, ordered by latest activity. - // In this case, latest activity is synonymous with - // the created timestamp of the last build for the repo. - ListReposByLastUpdate = ` -SELECT r.* -FROM repos r LEFT JOIN ( - SELECT repos.id, MAX(builds.created) as latest_build - FROM builds INNER JOIN repos - ON builds.repo_id = repos.id - WHERE repos.org = ? - GROUP BY repos.id) t -ON r.id = t.id -ORDER BY latest_build DESC NULLS LAST -LIMIT ? -OFFSET ?; -` -) diff --git a/database/sqlite/repo.go b/database/sqlite/repo.go deleted file mode 100644 index 0bcac5983..000000000 --- a/database/sqlite/repo.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - "fmt" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetRepo gets a repo by org and name from the database. -func (c *client) GetRepo(org, name string) (*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - "repo": name, - }).Tracef("getting repo %s/%s from the database", org, name) - - // variable to store query results - r := new(database.Repo) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.SelectRepo, org, name). - Scan(r) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err := r.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %s/%s: %v", org, name, err) - - // return the unencrypted repo - return r.ToLibrary(), result.Error - } - - // return the decrypted repo - return r.ToLibrary(), result.Error -} - -// CreateRepo creates a new repo in the database. -// -//nolint:dupl // ignore similar code with update -func (c *client) CreateRepo(r *library.Repo) error { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("creating repo %s in the database", r.GetFullName()) - - // cast to database type - repo := database.RepoFromLibrary(r) - - // validate the necessary fields are populated - err := repo.Validate() - if err != nil { - return err - } - - // encrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt - err = repo.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableRepo). - Create(repo).Error -} - -// UpdateRepo updates a repo in the database. -// -//nolint:dupl // ignore similar code with create -func (c *client) UpdateRepo(r *library.Repo) error { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("updating repo %s in the database", r.GetFullName()) - - // cast to database type - repo := database.RepoFromLibrary(r) - - // validate the necessary fields are populated - err := repo.Validate() - if err != nil { - return err - } - - // encrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt - err = repo.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableRepo). - Save(repo).Error -} - -// DeleteRepo deletes a repo by unique ID from the database. -func (c *client) DeleteRepo(id int64) error { - c.Logger.Tracef("deleting repo %d in the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableRepo). - Exec(dml.DeleteRepo, id).Error -} diff --git a/database/sqlite/repo_count.go b/database/sqlite/repo_count.go deleted file mode 100644 index 8438db1ee..000000000 --- a/database/sqlite/repo_count.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetRepoCount gets a count of all repos from the database. -func (c *client) GetRepoCount() (int64, error) { - c.Logger.Trace("getting count of repos from the database") - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.SelectReposCount). - Pluck("count", &r).Error - - return r, err -} - -// GetOrgRepoCount gets a count of all repos for a specific org from the database. -func (c *client) GetOrgRepoCount(org string, filters map[string]string) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("getting count of repos for org %s from the database", org) - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Select("count(*)"). - Where("org = ?", org). - Where(filters). - Pluck("count", &r).Error - - return r, err -} - -// GetUserRepoCount gets a count of all repos for a specific user from the database. -func (c *client) GetUserRepoCount(u *library.User) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("getting count of repos for user %s in the database", u.GetName()) - - // variable to store query results - var r int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.SelectUserReposCount, u.GetID()). - Pluck("count", &r).Error - - return r, err -} diff --git a/database/sqlite/repo_count_test.go b/database/sqlite/repo_count_test.go deleted file mode 100644 index dbb4ac10e..000000000 --- a/database/sqlite/repo_count_test.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the repo table - err = _database.Sqlite.Exec(ddl.CreateRepoTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableRepo, err) - } -} - -func TestSqlite_Client_GetRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repos in the database - err := _database.CreateRepo(_repoOne) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - err = _database.CreateRepo(_repoTwo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - got, err := _database.GetRepoCount() - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetUserRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - _user := new(library.User) - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repos in the database - err := _database.CreateRepo(_repoOne) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - err = _database.CreateRepo(_repoTwo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - got, err := _database.GetUserRepoCount(_user) - - if test.failure { - if err == nil { - t.Errorf("GetUserRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgRepoCount(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 1, - }, - } - filters := map[string]string{} - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repos in the database - err := _database.CreateRepo(_repoOne) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - err = _database.CreateRepo(_repoTwo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - got, err := _database.GetOrgRepoCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgRepoCount_NonAdmin(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("foo/foo") - _repoTwo.SetVisibility("private") - - _repoThree := testRepo() - _repoThree.SetID(3) - _repoThree.SetUserID(1) - _repoThree.SetHash("baz") - _repoThree.SetOrg("bar") - _repoThree.SetName("foo") - _repoThree.SetFullName("bar/foo") - _repoThree.SetVisibility("private") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 1, - }, - } - filters := map[string]string{} - filters["visibility"] = "public" - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range []*library.Repo{_repoOne, _repoTwo, _repoThree} { - // create the repos in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetOrgRepoCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/repo_list.go b/database/sqlite/repo_list.go deleted file mode 100644 index 6b6ae6f55..000000000 --- a/database/sqlite/repo_list.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetRepoList gets a list of all repos from the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) GetRepoList() ([]*library.Repo, error) { - c.Logger.Trace("listing repos from the database") - - // variable to store query results - r := new([]database.Repo) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.ListRepos). - Scan(r).Error - if err != nil { - return nil, err - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} - -// GetOrgRepoList gets a list of all repos by org from the database. -func (c *client) GetOrgRepoList(org string, filters map[string]string, page, perPage int, sortBy string) ([]*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("listing repos for org %s from the database", org) - - // variable to store query results - r := new([]database.Repo) - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - switch sortBy { - case "latest": - err := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.ListReposByLastUpdate, org, perPage, offset). - Scan(r).Error - if err != nil { - return nil, err - } - default: - err := c.Sqlite. - Table(constants.TableRepo). - Where("org = ?", org). - Where(filters). - Order("name"). - Limit(perPage). - Offset(offset). - Scan(r).Error - if err != nil { - return nil, err - } - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err := tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} - -// GetUserRepoList gets a list of all repos by user ID from the database. -func (c *client) GetUserRepoList(u *library.User, page, perPage int) ([]*library.Repo, error) { - c.Logger.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Tracef("listing repos for user %s from the database", u.GetName()) - - // variable to store query results - r := new([]database.Repo) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableRepo). - Raw(dml.ListUserRepos, u.GetID(), perPage, offset). - Scan(r).Error - if err != nil { - return nil, err - } - - // variable we want to return - repos := []*library.Repo{} - // iterate through all query results - for _, repo := range *r { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := repo - - // decrypt the fields for the repo - // - // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted repos - c.Logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - repos = append(repos, tmp.ToLibrary()) - } - - return repos, nil -} diff --git a/database/sqlite/repo_list_test.go b/database/sqlite/repo_list_test.go deleted file mode 100644 index 882e5b3e1..000000000 --- a/database/sqlite/repo_list_test.go +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the repo table - err = _database.Sqlite.Exec(ddl.CreateRepoTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableRepo, err) - } -} - -func TestSqlite_Client_GetRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range test.want { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetRepoList() - - if test.failure { - if err == nil { - t.Errorf("GetRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("oldName") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne, _repoTwo}, - }, - } - filters := map[string]string{} - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range test.want { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgRepoList_NonAdmin(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("private") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoOne}, - }, - } - filters := map[string]string{} - filters["visibility"] = "public" - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range test.want { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "name") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgRepoList_LastUpdate(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("oldName") - - _repoThree := testRepo() - _repoThree.SetID(3) - _repoThree.SetUserID(1) - _repoThree.SetHash("baz") - _repoThree.SetOrg("foo") - _repoThree.SetName("bat") - _repoThree.SetFullName("foo/bat") - _repoThree.SetVisibility("public") - _repoThree.SetPipelineType("yaml") - _repoThree.SetPreviousName("") - - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetCreated(1) - _buildOne.SetNumber(1) - _buildOne.SetRepoID(2) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetCreated(2) - _buildTwo.SetNumber(1) - _buildTwo.SetRepoID(1) - - _buildThree := testBuild() - _buildThree.SetID(3) - _buildThree.SetCreated(3) - _buildThree.SetNumber(1) - _buildThree.SetRepoID(3) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - err = _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create build: %v", err) - } - - err = _database.CreateBuild(_buildThree) - if err != nil { - t.Errorf("unable to create build: %v", err) - } - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoThree, _repoOne, _repoTwo}, - }, - } - - filters := map[string]string{} - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range test.want { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetOrgRepoList("foo", filters, 1, 10, "latest") - - if test.failure { - if err == nil { - t.Errorf("GetOrgRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgRepoList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetUserRepoList(t *testing.T) { - // setup types - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - _repoOne.SetPipelineType("yaml") - _repoOne.SetPreviousName("") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("public") - _repoTwo.SetPipelineType("yaml") - _repoTwo.SetPreviousName("") - - _user := new(library.User) - _user.SetID(1) - _user.SetName("foo") - _user.SetToken("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Repo - }{ - { - failure: false, - want: []*library.Repo{_repoTwo, _repoOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range test.want { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetUserRepoList(_user, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetUserRepoList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetUserRepoList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetUserRepoList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/repo_test.go b/database/sqlite/repo_test.go deleted file mode 100644 index 2c0cb3081..000000000 --- a/database/sqlite/repo_test.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPipelineType("yaml") - _repo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Repo - }{ - { - failure: false, - want: _repo, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the repo in the database - err := _database.CreateRepo(test.want) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - got, err := _database.GetRepo("foo", "bar") - - // cleanup the repos table - _ = _database.Sqlite.Exec("DELETE FROM repos;") - - if test.failure { - if err == nil { - t.Errorf("GetRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepo returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepo is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - err := _database.CreateRepo(_repo) - - if test.failure { - if err == nil { - t.Errorf("CreateRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateRepo returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - err = _database.UpdateRepo(_repo) - - if test.failure { - if err == nil { - t.Errorf("UpdateRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateRepo returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteRepo(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _repo.SetPreviousName("") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err = _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - err := _database.DeleteRepo(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteRepo should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteRepo returned err: %v", err) - } - } -} - -// testRepo is a test helper function to create a -// library Repo type with all fields set to their -// zero values. -func testRepo() *library.Repo { - i64 := int64(0) - i := 0 - str := "" - b := false - - return &library.Repo{ - ID: &i64, - UserID: &i64, - Hash: &str, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - BuildLimit: &i64, - Timeout: &i64, - Counter: &i, - Visibility: &str, - Private: &b, - Trusted: &b, - Active: &b, - AllowPull: &b, - AllowPush: &b, - AllowDeploy: &b, - AllowTag: &b, - AllowComment: &b, - PreviousName: &str, - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 2369db0cd..5ac28bd89 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -9,6 +9,7 @@ import ( "time" "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/server/database/user" "github.com/go-vela/types/constants" @@ -44,6 +45,8 @@ type ( Logger *logrus.Entry // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService + // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService + repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService } @@ -239,12 +242,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) } - // create the repos table - err = c.Sqlite.Exec(ddl.CreateRepoTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) - } - // create the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTable).Error if err != nil { @@ -313,12 +310,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) } - // create the repos_org_name index for the repos table - err = c.Sqlite.Exec(ddl.CreateRepoOrgNameIndex).Error - if err != nil { - return fmt.Errorf("unable to create repos_org_name index for the %s table: %w", constants.TableRepo, err) - } - // create the secrets_type_org_repo index for the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { @@ -363,6 +354,19 @@ func createServices(c *client) error { return err } + // create the database agnostic repo service + // + // https://pkg.go.dev/github.com/go-vela/server/database/repo#New + c.RepoService, err = repo.New( + repo.WithClient(c.Sqlite), + repo.WithEncryptionKey(c.config.EncryptionKey), + repo.WithLogger(c.Logger), + repo.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/database/sqlite/sqlite_test.go b/database/sqlite/sqlite_test.go index 6b31f874a..48ff34902 100644 --- a/database/sqlite/sqlite_test.go +++ b/database/sqlite/sqlite_test.go @@ -7,6 +7,8 @@ package sqlite import ( "testing" "time" + + "github.com/go-vela/types/library" ) func TestSqlite_New(t *testing.T) { @@ -216,3 +218,38 @@ func TestSqlite_createServices(t *testing.T) { } } } + +// testRepo is a test helper function to create a +// library Repo type with all fields set to their +// zero values. +func testRepo() *library.Repo { + i64 := int64(0) + i := 0 + str := "" + b := false + + return &library.Repo{ + ID: &i64, + UserID: &i64, + Hash: &str, + Org: &str, + Name: &str, + FullName: &str, + Link: &str, + Clone: &str, + Branch: &str, + BuildLimit: &i64, + Timeout: &i64, + Counter: &i, + Visibility: &str, + Private: &b, + Trusted: &b, + Active: &b, + AllowPull: &b, + AllowPush: &b, + AllowDeploy: &b, + AllowTag: &b, + AllowComment: &b, + PreviousName: &str, + } +} diff --git a/database/user/get.go b/database/user/get.go index da8b1a0e7..d37275c80 100644 --- a/database/user/get.go +++ b/database/user/get.go @@ -21,8 +21,7 @@ func (e *engine) GetUser(id int64) (*library.User, error) { err := e.client. Table(constants.TableUser). Where("id = ?", id). - Limit(1). - Scan(u). + Take(u). Error if err != nil { return nil, err diff --git a/database/user/get_name.go b/database/user/get_name.go index 2244bfb86..4e8da5550 100644 --- a/database/user/get_name.go +++ b/database/user/get_name.go @@ -24,8 +24,7 @@ func (e *engine) GetUserForName(name string) (*library.User, error) { err := e.client. Table(constants.TableUser). Where("name = ?", name). - Limit(1). - Scan(u). + Take(u). Error if err != nil { return nil, err diff --git a/router/middleware/repo/repo.go b/router/middleware/repo/repo.go index 94d85a4c3..d8cc5447e 100644 --- a/router/middleware/repo/repo.go +++ b/router/middleware/repo/repo.go @@ -45,7 +45,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading repo %s/%s", o, rParam) - r, err := database.FromContext(c).GetRepo(o, rParam) + r, err := database.FromContext(c).GetRepoForOrg(o, rParam) if err != nil { retErr := fmt.Errorf("unable to read repo %s/%s: %w", o, rParam, err) util.HandleError(c, http.StatusNotFound, retErr) From f60ee1d0c15a2834148d66458cb9c8cb906fd666 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 27 Sep 2022 10:00:16 -0600 Subject: [PATCH 111/298] enhance(secrets): verify casing of orgs and repos in SCM before adding secret (#700) * enhance(secrets): verify casing and existence of orgs and repos in SCM before adding secret * fix some comments * add clarifying comments * ditch equalfold check since it will always be true at that point --- api/secret.go | 49 ++++++++++++ scm/github/org.go | 43 ++++++++++ scm/github/org_test.go | 131 +++++++++++++++++++++++++++++++ scm/github/repo.go | 20 +++++ scm/github/repo_test.go | 73 +++++++++++++++++ scm/github/testdata/get_org.json | 53 +++++++++++++ scm/service.go | 6 ++ 7 files changed, 375 insertions(+) create mode 100644 scm/github/org.go create mode 100644 scm/github/org_test.go create mode 100644 scm/github/testdata/get_org.json diff --git a/api/secret.go b/api/secret.go index bb35c80f6..46a9d5ea3 100644 --- a/api/secret.go +++ b/api/secret.go @@ -109,6 +109,55 @@ func CreateSecret(c *gin.Context) { } } + if strings.EqualFold(t, constants.SecretOrg) { + // retrieve org name from SCM + // + // SCM can be case insensitive, causing access retrieval to work + // but Org/Repo != org/repo in Vela. So this check ensures that + // what a user inputs matches the casing we expect in Vela since + // the SCM will have the source of truth for casing. + org, err := scm.FromContext(c).GetOrgName(u, o) + if err != nil { + retErr := fmt.Errorf("unable to retrieve organization %s", o) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate + if org != o { + retErr := fmt.Errorf("unable to retrieve organization %s. Did you mean %s?", o, org) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + + if strings.EqualFold(t, constants.SecretRepo) { + // retrieve repo name from SCM + // + // same story as org secret. SCM has accurate casing. + scmRepo, err := scm.FromContext(c).GetRepoName(u, o, n) + if err != nil { + retErr := fmt.Errorf("unable to retrieve repository %s/%s", o, n) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate + if scmRepo != n { + retErr := fmt.Errorf("unable to retrieve repository %s. Did you mean %s?", n, scmRepo) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields diff --git a/scm/github/org.go b/scm/github/org.go new file mode 100644 index 000000000..ef9e43ca4 --- /dev/null +++ b/scm/github/org.go @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package github + +import ( + "net/http" + + "github.com/sirupsen/logrus" + + "github.com/go-vela/types/library" +) + +// GetOrgName gets org name from Github. +func (c *client) GetOrgName(u *library.User, o string) (string, error) { + c.Logger.WithFields(logrus.Fields{ + "org": o, + "user": u.GetName(), + }).Tracef("retrieving org information for %s", o) + + // create GitHub OAuth client with user's token + client := c.newClientToken(u.GetToken()) + + // send an API call to get the org info + orgInfo, resp, err := client.Organizations.Get(ctx, o) + + orgName := orgInfo.GetLogin() + + // if org is not found, return the personal org + if resp.StatusCode == http.StatusNotFound { + user, _, err := client.Users.Get(ctx, "") + if err != nil { + return "", err + } + + orgName = user.GetLogin() + } else if err != nil { + return "", err + } + + return orgName, nil +} diff --git a/scm/github/org_test.go b/scm/github/org_test.go new file mode 100644 index 000000000..b0512f9b9 --- /dev/null +++ b/scm/github/org_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package github + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/gin-gonic/gin" + + "github.com/go-vela/types/library" +) + +func TestGithub_GetOrgName(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/orgs/:org", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/get_org.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + want := "github" + + client, _ := NewTest(s.URL) + + // run test + got, err := client.GetOrgName(u, "github") + + if resp.Code != http.StatusOK { + t.Errorf("GetOrgName returned %v, want %v", resp.Code, http.StatusOK) + } + + if err != nil { + t.Errorf("GetOrgName returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetOrgName is %v, want %v", got, want) + } +} + +func TestGithub_GetOrgName_Personal(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/user", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/user.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + want := "octocat" + + client, _ := NewTest(s.URL) + + // run test + got, err := client.GetOrgName(u, "octocat") + + if resp.Code != http.StatusOK { + t.Errorf("GetOrgName returned %v, want %v", resp.Code, http.StatusOK) + } + + if err != nil { + t.Errorf("GetOrgName returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetOrgName is %v, want %v", got, want) + } +} + +func TestGithub_GetOrgName_Fail(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/orgs/:org", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusNotFound) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + client, _ := NewTest(s.URL) + + // run test + _, err := client.GetOrgName(u, "octocat") + + if err == nil { + t.Error("GetOrgName should return error") + } +} diff --git a/scm/github/repo.go b/scm/github/repo.go index dc51768b2..9a5c7a36c 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -309,6 +309,26 @@ func (c *client) GetRepo(u *library.User, r *library.Repo) (*library.Repo, error return toLibraryRepo(*repo), nil } +// GetRepoName returns the name of the repository in the SCM. +func (c *client) GetRepoName(u *library.User, o string, r string) (string, error) { + c.Logger.WithFields(logrus.Fields{ + "org": o, + "repo": r, + "user": u.GetName(), + }).Tracef("retrieving repository information for %s/%s", o, r) + + // create GitHub OAuth client with user's token + client := c.newClientToken(u.GetToken()) + + // send an API call to get the repo info + repo, _, err := client.Repositories.Get(ctx, o, r) + if err != nil { + return "", err + } + + return repo.GetName(), nil +} + // ListUserRepos returns a list of all repos the user has access to. func (c *client) ListUserRepos(u *library.User) ([]*library.Repo, error) { c.Logger.WithFields(logrus.Fields{ diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index b9521a061..769870f34 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1013,6 +1013,79 @@ func TestGithub_GetRepo_Fail(t *testing.T) { } } +func TestGithub_GetRepoName(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:owner/:repo", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/get_repo.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + want := "Hello-World" + + client, _ := NewTest(s.URL) + + // run test + got, err := client.GetRepoName(u, "octocat", "Hello-World") + + if resp.Code != http.StatusOK { + t.Errorf("GetRepoName returned %v, want %v", resp.Code, http.StatusOK) + } + + if err != nil { + t.Errorf("GetRepoName returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetRepoName is %v, want %v", got, want) + } +} + +func TestGithub_GetRepoName_Fail(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:owner/:repo", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusNotFound) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + client, _ := NewTest(s.URL) + + // run test + _, err := client.GetRepoName(u, "octocat", "Hello-World") + + if err == nil { + t.Error("GetRepoName should return error") + } +} + func TestGithub_ListUserRepos(t *testing.T) { // setup context gin.SetMode(gin.TestMode) diff --git a/scm/github/testdata/get_org.json b/scm/github/testdata/get_org.json new file mode 100644 index 000000000..e43ba5655 --- /dev/null +++ b/scm/github/testdata/get_org.json @@ -0,0 +1,53 @@ +{ + "login": "github", + "id": 1, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjE=", + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "A great organization", + "name": "github", + "company": "GitHub", + "blog": "https://github.com/blog", + "location": "San Francisco", + "email": "octocat@github.com", + "twitter_username": "github", + "is_verified": true, + "has_organization_projects": true, + "has_repository_projects": true, + "public_repos": 2, + "public_gists": 1, + "followers": 20, + "following": 0, + "html_url": "https://github.com/octocat", + "created_at": "2008-01-14T04:33:35Z", + "updated_at": "2014-03-03T18:58:10Z", + "type": "Organization", + "total_private_repos": 100, + "owned_private_repos": 100, + "private_gists": 81, + "disk_usage": 10000, + "collaborators": 8, + "billing_email": "mona@github.com", + "plan": { + "name": "Medium", + "space": 400, + "private_repos": 20, + "filled_seats": 4, + "seats": 5 + }, + "default_repository_permission": "read", + "members_can_create_repositories": true, + "two_factor_requirement_enabled": true, + "members_allowed_repository_creation_type": "all", + "members_can_create_public_repositories": false, + "members_can_create_private_repositories": false, + "members_can_create_internal_repositories": false, + "members_can_create_pages": true, + "members_can_fork_private_repositories": false +} \ No newline at end of file diff --git a/scm/service.go b/scm/service.go index 75f3685bd..a0d55d564 100644 --- a/scm/service.go +++ b/scm/service.go @@ -111,6 +111,12 @@ type Service interface { // GetRepo defines a function that retrieves // details for a repo. GetRepo(*library.User, *library.Repo) (*library.Repo, error) + // GetRepoName defines a function that retrieves + // the name of the repo in the SCM. + GetRepoName(*library.User, string, string) (string, error) + // GetOrg defines a function that retrieves + // the name for an org in the SCM. + GetOrgName(*library.User, string) (string, error) // GetHTMLURL defines a function that retrieves // a repository file's html_url. GetHTMLURL(*library.User, string, string, string, string) (string, error) From fa289f3f37ab752bd761dd5b5f8b20c615ce7a15 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 27 Sep 2022 10:12:39 -0600 Subject: [PATCH 112/298] enhance(webhook): add extra debug logging at various points in workflow (#697) * enhance(webhook): add extra debug logging at various points in workflow * address capitalization consistency, and enhance some logs * adding string method to logged objects * censor build fields and remove string call Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/webhook.go | 22 ++++++++++++++++++++++ scm/github/repo.go | 1 + 2 files changed, 23 insertions(+) diff --git a/api/webhook.go b/api/webhook.go index b9046b38e..1df0171a2 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -131,6 +131,17 @@ func PostWebhook(c *gin.Context) { h, r, b := webhook.Hook, webhook.Repo, webhook.Build + logrus.Debugf("hook generated from SCM: %v", h) + logrus.Debugf("repo generated from SCM: %v", r) + + if b != nil { + logrus.Debugf(`build author: %s, + build branch: %s, + build commit: %s, + build ref: %s`, + b.GetAuthor(), b.GetBranch(), b.GetCommit(), b.GetRef()) + } + // check if build was parsed from webhook. // build will be nil on repository events, but // for renaming, we want to continue. @@ -273,6 +284,8 @@ func PostWebhook(c *gin.Context) { } // send API call to capture repo owner + logrus.Debugf("capturing owner of repository %s", r.GetFullName()) + u, err := database.FromContext(c).GetUser(r.GetUserID()) if err != nil { retErr := fmt.Errorf("%s: failed to get owner for %s: %w", baseErr, r.GetFullName(), err) @@ -301,6 +314,8 @@ func PostWebhook(c *gin.Context) { return } + logrus.Debugf("currently %d builds running on repo %s", builds, r.GetFullName()) + // check if the number of pending and running builds exceeds the limit for the repo if builds >= r.GetBuildLimit() { retErr := fmt.Errorf("%s: repo %s has exceeded the concurrent build limit of %d", baseErr, r.GetFullName(), r.GetBuildLimit()) @@ -313,8 +328,13 @@ func PostWebhook(c *gin.Context) { } // update fields in build object + logrus.Debugf("updating build number to %d", r.GetCounter()) b.SetNumber(r.GetCounter()) + + logrus.Debugf("updating parent number to %d", b.GetNumber()) b.SetParent(b.GetNumber()) + + logrus.Debug("updating status to pending") b.SetStatus(constants.StatusPending) // if this is a comment on a pull_request event @@ -388,6 +408,7 @@ func PostWebhook(c *gin.Context) { // failing to successfully process the request. This logic ensures we attempt our // best efforts to handle these cases gracefully. for i := 0; i < retryLimit; i++ { + logrus.Debugf("compilation loop - attempt %d", i+1) // check if we're on the first iteration of the loop if i > 0 { // incrementally sleep in between retries @@ -726,6 +747,7 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, // that repo to its new name in order to preserve it. It also updates the secrets // associated with that repo. func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) error { + logrus.Debugf("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) // get the old name of the repo previousName := r.GetPreviousName() // get the repo from the database that matches the old name diff --git a/scm/github/repo.go b/scm/github/repo.go index 9a5c7a36c..12a7bb855 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -25,6 +25,7 @@ func (c *client) ConfigBackoff(u *library.User, r *library.Repo, ref string) (da retryLimit := 5 for i := 0; i < retryLimit; i++ { + logrus.Debugf("Fetching config file - Attempt %d", i+1) // attempt to fetch the config data, err = c.Config(u, r, ref) From 8e8d0d456b0f57a978e996b85a20402841fabc5e Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Tue, 27 Sep 2022 11:15:49 -0500 Subject: [PATCH 113/298] chore: v0.15.0-rc1 prep (#703) --- database/postgres/secret_list.go | 2 -- database/sqlite/secret_list.go | 2 -- go.mod | 8 ++++---- go.sum | 17 ++++++++--------- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/database/postgres/secret_list.go b/database/postgres/secret_list.go index 2913f6eef..d8806a3b8 100644 --- a/database/postgres/secret_list.go +++ b/database/postgres/secret_list.go @@ -16,8 +16,6 @@ import ( ) // GetSecretList gets a list of all secrets from the database. -// -//nolint:dupl // ignore false positive of duplicate code func (c *client) GetSecretList() ([]*library.Secret, error) { c.Logger.Tracef("listing secrets from the database") diff --git a/database/sqlite/secret_list.go b/database/sqlite/secret_list.go index ef57da67f..7fdfb6e1e 100644 --- a/database/sqlite/secret_list.go +++ b/database/sqlite/secret_list.go @@ -16,8 +16,6 @@ import ( ) // GetSecretList gets a list of all secrets from the database. -// -//nolint:dupl // ignore false positive of duplicate code func (c *client) GetSecretList() ([]*library.Secret, error) { c.Logger.Tracef("listing secrets from the database") diff --git a/go.mod b/go.mod index 7b93f1fe5..fd91bc79c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.14.0 + github.com/go-vela/types v0.15.0-rc1 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 @@ -98,12 +98,12 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.6 // indirect + github.com/lib/pq v1.10.7 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/microcosm-cc/bluemonday v1.0.18 // indirect + github.com/microcosm-cc/bluemonday v1.0.20 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect @@ -126,7 +126,7 @@ require ( github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect - golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect diff --git a/go.sum b/go.sum index 9273a8434..787df48e3 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.14.0 h1:m75BdRfQm9PC4l/oHSgeplt8mqgau3JmqD3DN+KdePk= -github.com/go-vela/types v0.14.0/go.mod h1:Z/94BulwLbd+bSiPVJEUNdQxB1EP2JCYWaBsv/d65vs= +github.com/go-vela/types v0.15.0-rc1 h1:CTXplhQ7mc1yjbWiM6UbE9qPgGE4yBrPBKC0a/rkFDo= +github.com/go-vela/types v0.15.0-rc1/go.mod h1:hQSy2STPChcHk53RFWCEg0gnjHXop+/bVAPkiU9YIqo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= @@ -401,8 +401,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -424,8 +424,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= -github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= +github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -661,11 +661,10 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= From 93d38a93ae7f2c3fd335bb3136125bfe3c4d3bdf Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 29 Sep 2022 13:54:45 -0600 Subject: [PATCH 114/298] fix(webhook): more general error message for redelivery failure (#707) --- scm/github/webhook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index a9d42b464..257483d43 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -502,7 +502,7 @@ func (c *client) getDeliveryID(ctx context.Context, ghClient *github.Client, r * } // if not found, webhook was not recent enough for GitHub - err = fmt.Errorf("webhook not one of the 100 most recent deliveries") + err = fmt.Errorf("webhook no longer available to be redelivered") return 0, err } From 435f63fe7e4c895cd4ca9eefb1a324e64cbdda9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 08:35:08 -0500 Subject: [PATCH 115/298] fix(deps): update go.starlark.net digest to 5fccb4d (#705) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fd91bc79c..cbad817cc 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.16.3 - go.starlark.net v0.0.0-20220926145019-14b050677505 + go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 787df48e3..3addf5198 100644 --- a/go.sum +++ b/go.sum @@ -561,8 +561,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220926145019-14b050677505 h1:W0MibAL5BiEenQR+F/EF/a4HJhgLngHVvm6jbtUW0PM= -go.starlark.net v0.0.0-20220926145019-14b050677505/go.mod h1:qsNirHv+Awo5xHuNyQ/0niov6kDxdBs+bqpVMBCW77k= +go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d h1:aF+anaRVZu22kdETjLavnIn/cvD+arhmik6vMU3joW4= +go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From 0cc9a01119d49be608af567f7b527d6236b0f4dc Mon Sep 17 00:00:00 2001 From: rfigueroa <41128440+rfigueroa@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:13:29 -0500 Subject: [PATCH 116/298] fix(compiler): add template name to inline render (#691) --- api/pipeline/template.go | 3 +- compiler/engine.go | 2 +- compiler/native/compile.go | 6 +- compiler/native/compile_test.go | 236 ++++++++++++++++++ compiler/native/parse.go | 6 +- compiler/native/parse_test.go | 26 +- compiler/native/testdata/template_name.yml | 16 ++ .../native/testdata/template_name_inline.yml | 11 + .../testdata/template_name_template.yml | 8 + compiler/template/native/render.go | 6 +- compiler/template/native/render_test.go | 2 +- compiler/template/starlark/render.go | 4 +- compiler/template/starlark/render_test.go | 2 +- 13 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 compiler/native/testdata/template_name.yml create mode 100644 compiler/native/testdata/template_name_inline.yml create mode 100644 compiler/native/testdata/template_name_template.yml diff --git a/api/pipeline/template.go b/api/pipeline/template.go index 9992efde8..5529e3b74 100644 --- a/api/pipeline/template.go +++ b/api/pipeline/template.go @@ -20,6 +20,7 @@ import ( "github.com/go-vela/server/util" "github.com/go-vela/types" "github.com/go-vela/types/library" + "github.com/go-vela/types/yaml" "github.com/sirupsen/logrus" ) @@ -97,7 +98,7 @@ func GetTemplates(c *gin.Context) { compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) // parse the pipeline configuration - pipeline, _, err := compiler.Parse(p.GetData(), p.GetType(), map[string]interface{}{}) + pipeline, _, err := compiler.Parse(p.GetData(), p.GetType(), new(yaml.Template)) if err != nil { util.HandleError(c, http.StatusBadRequest, fmt.Errorf("unable to parse pipeline %s: %w", entry, err)) diff --git a/compiler/engine.go b/compiler/engine.go index 3fbc7d02c..9addf7a79 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -33,7 +33,7 @@ type Engine interface { // Parse defines a function that converts // an object to a yaml configuration. - Parse(interface{}, string, map[string]interface{}) (*yaml.Build, []byte, error) + Parse(interface{}, string, *yaml.Template) (*yaml.Build, []byte, error) // ParseRaw defines a function that converts // an object to a string. diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 709862e44..4b80e3365 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -42,7 +42,7 @@ type ModifyResponse struct { // Compile produces an executable pipeline from a yaml configuration. func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, error) { - p, data, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) + p, data, err := c.Parse(v, c.repo.GetPipelineType(), new(yaml.Template)) if err != nil { return nil, nil, err } @@ -106,7 +106,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err // CompileLite produces a partial of an executable pipeline from a yaml configuration. func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, *library.Pipeline, error) { - p, data, err := c.Parse(v, c.repo.GetPipelineType(), map[string]interface{}{}) + p, data, err := c.Parse(v, c.repo.GetPipelineType(), new(yaml.Template)) if err != nil { return nil, nil, err } @@ -226,7 +226,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu format = constants.PipelineTypeGo } - parsed, _, err := c.Parse(bytes, format, template.Variables) + parsed, _, err := c.Parse(bytes, format, template) if err != nil { return nil, err } diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 0a7d64d7c..d2d7df7ec 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -1082,6 +1082,242 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { } } +// Test evaluation of `vela "tempalate_name"` function. +func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + c := cli.NewContext(nil, set, nil) + + m := &types.Metadata{ + Database: &types.Database{ + Driver: "foo", + Host: "foo", + }, + Queue: &types.Queue{ + Channel: "foo", + Driver: "foo", + Host: "foo", + }, + Source: &types.Source{ + Driver: "foo", + Host: "foo", + }, + Vela: &types.Vela{ + Address: "foo", + WebAddress: "foo", + }, + } + + setupEnv := environment(nil, m, nil, nil) + + helloEnv := environment(nil, m, nil, nil) + helloEnv["HOME"] = "/root" + helloEnv["SHELL"] = "/bin/sh" + helloEnv["VELA_BUILD_SCRIPT"] = generateScriptPosix([]string{"echo sample"}) + + want := &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Template: false, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: setupEnv, + Image: "#init", + Name: "init", + Number: 1, + Pull: "not_present", + }, + &pipeline.Container{ + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: setupEnv, + Image: "target/vela-git:v0.5.1", + Name: "clone", + Number: 2, + Pull: "not_present", + }, + &pipeline.Container{ + ID: "step___0_sample_hello", + Directory: "/vela/src/foo//", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: helloEnv, + Image: "sample", + Name: "sample_hello", + Number: 3, + Pull: "not_present", + }, + }, + } + + // run test + yaml, err := os.ReadFile("testdata/template_name.yml") + if err != nil { + t.Errorf("Reading yaml file return err: %v", err) + } + + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } + + compiler.WithMetadata(m) + + got, _, err := compiler.Compile(yaml) + if err != nil { + t.Errorf("Compile returned err: %v", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Compile() mismatch (-want +got):\n%s", diff) + } +} + +// Test evaluation of `vela "tempalate_name"` function on a inline template. +func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName_Inline(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + c := cli.NewContext(nil, set, nil) + + m := &types.Metadata{ + Database: &types.Database{ + Driver: "foo", + Host: "foo", + }, + Queue: &types.Queue{ + Channel: "foo", + Driver: "foo", + Host: "foo", + }, + Source: &types.Source{ + Driver: "foo", + Host: "foo", + }, + Vela: &types.Vela{ + Address: "foo", + WebAddress: "foo", + }, + } + + setupEnv := environment(nil, m, nil, nil) + + helloEnv := environment(nil, m, nil, nil) + helloEnv["HOME"] = "/root" + helloEnv["SHELL"] = "/bin/sh" + helloEnv["VELA_BUILD_SCRIPT"] = generateScriptPosix([]string{"echo inline_templatename"}) + + want := &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Template: false, + Environment: []string{"steps", "services", "secrets"}, + }, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "step___0_init", + Directory: "/vela/src/foo//", + Environment: setupEnv, + Image: "#init", + Name: "init", + Number: 1, + Pull: "not_present", + }, + &pipeline.Container{ + ID: "step___0_clone", + Directory: "/vela/src/foo//", + Environment: setupEnv, + Image: "target/vela-git:v0.5.1", + Name: "clone", + Number: 2, + Pull: "not_present", + }, + &pipeline.Container{ + ID: "step___0_inline_templatename_hello", + Directory: "/vela/src/foo//", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: helloEnv, + Image: "inline_templatename", + Name: "inline_templatename_hello", + Number: 3, + Pull: "not_present", + }, + }, + } + + // run test + yaml, err := os.ReadFile("testdata/template_name_inline.yml") + if err != nil { + t.Errorf("Reading yaml file return err: %v", err) + } + + compiler, err := New(c) + if err != nil { + t.Errorf("Creating compiler returned err: %v", err) + } + + compiler.WithMetadata(m) + + got, _, err := compiler.Compile(yaml) + if err != nil { + t.Errorf("Compile returned err: %v", err) + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Compile() mismatch (-want +got):\n%s", diff) + } +} + func TestNative_Compile_InvalidType(t *testing.T) { // setup context gin.SetMode(gin.TestMode) diff --git a/compiler/native/parse.go b/compiler/native/parse.go index 1d9f1206b..b3ff020f4 100644 --- a/compiler/native/parse.go +++ b/compiler/native/parse.go @@ -42,7 +42,7 @@ func (c *client) ParseRaw(v interface{}) (string, error) { } // Parse converts an object to a yaml configuration. -func (c *client) Parse(v interface{}, pipelineType string, variables map[string]interface{}) (*types.Build, []byte, error) { +func (c *client) Parse(v interface{}, pipelineType string, template *types.Template) (*types.Build, []byte, error) { var ( p *types.Build raw []byte @@ -59,7 +59,7 @@ func (c *client) Parse(v interface{}, pipelineType string, variables map[string] // capture the raw pipeline configuration raw = []byte(parsedRaw) - p, err = native.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) + p, err = native.RenderBuild(template.Name, parsedRaw, c.EnvironmentBuild(), template.Variables) if err != nil { return nil, raw, err } @@ -73,7 +73,7 @@ func (c *client) Parse(v interface{}, pipelineType string, variables map[string] // capture the raw pipeline configuration raw = []byte(parsedRaw) - p, err = starlark.RenderBuild(parsedRaw, c.EnvironmentBuild(), variables) + p, err = starlark.RenderBuild(template.Name, parsedRaw, c.EnvironmentBuild(), template.Variables) if err != nil { return nil, raw, err } diff --git a/compiler/native/parse_test.go b/compiler/native/parse_test.go index bdd76f2e1..0bb5a0195 100644 --- a/compiler/native/parse_test.go +++ b/compiler/native/parse_test.go @@ -40,7 +40,7 @@ func TestNative_Parse_Metadata_Bytes(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -70,7 +70,7 @@ func TestNative_Parse_Metadata_File(t *testing.T) { defer f.Close() - got, _, err := client.Parse(f, "", map[string]interface{}{}) + got, _, err := client.Parse(f, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -85,7 +85,7 @@ func TestNative_Parse_Metadata_Invalid(t *testing.T) { client, _ := New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) // run test - got, _, err := client.Parse(nil, "", map[string]interface{}{}) + got, _, err := client.Parse(nil, "", new(yaml.Template)) if err == nil { t.Error("Parse should have returned err") @@ -109,7 +109,7 @@ func TestNative_Parse_Metadata_Path(t *testing.T) { } // run test - got, _, err := client.Parse("testdata/metadata.yml", "", map[string]interface{}{}) + got, _, err := client.Parse("testdata/metadata.yml", "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -137,7 +137,7 @@ func TestNative_Parse_Metadata_Reader(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(bytes.NewReader(b), "", map[string]interface{}{}) + got, _, err := client.Parse(bytes.NewReader(b), "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -165,7 +165,7 @@ func TestNative_Parse_Metadata_String(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(string(b), "", map[string]interface{}{}) + got, _, err := client.Parse(string(b), "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -212,7 +212,7 @@ func TestNative_Parse_Parameters(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -338,7 +338,7 @@ func TestNative_Parse_StagesPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -435,7 +435,7 @@ func TestNative_Parse_StepsPipeline(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) } @@ -498,7 +498,7 @@ func TestNative_Parse_Secrets(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -574,7 +574,7 @@ func TestNative_Parse_Stages(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -632,7 +632,7 @@ func TestNative_Parse_Steps(t *testing.T) { t.Errorf("Reading file returned err: %v", err) } - got, _, err := client.Parse(b, "", map[string]interface{}{}) + got, _, err := client.Parse(b, "", new(yaml.Template)) if err != nil { t.Errorf("Parse returned err: %v", err) @@ -906,7 +906,7 @@ func Test_client_Parse(t *testing.T) { } } - got, _, err := c.Parse(content, tt.args.pipelineType, map[string]interface{}{}) + got, _, err := c.Parse(content, tt.args.pipelineType, new(yaml.Template)) if (err != nil) != tt.wantErr { t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/native/testdata/template_name.yml b/compiler/native/testdata/template_name.yml new file mode 100644 index 000000000..652cdb2fd --- /dev/null +++ b/compiler/native/testdata/template_name.yml @@ -0,0 +1,16 @@ +--- +version: "1" + +metadata: + template: false + +templates: + - name: inline_templatename + source: github.example.com/github/octocat/template_name_template.yml + type: github + +steps: + - name: sample + template: + name: inline_templatename + diff --git a/compiler/native/testdata/template_name_inline.yml b/compiler/native/testdata/template_name_inline.yml new file mode 100644 index 000000000..f35801376 --- /dev/null +++ b/compiler/native/testdata/template_name_inline.yml @@ -0,0 +1,11 @@ +--- +version: "1" + +metadata: + template: false + render_inline: true + +templates: + - name: inline_templatename + source: github.example.com/github/octocat/template_name_template.yml + type: github diff --git a/compiler/native/testdata/template_name_template.yml b/compiler/native/testdata/template_name_template.yml new file mode 100644 index 000000000..3ff2c0262 --- /dev/null +++ b/compiler/native/testdata/template_name_template.yml @@ -0,0 +1,8 @@ +metadata: + template: true + +steps: + - name: hello + image: {{ vela "template_name" }} + commands: + - echo {{ vela "template_name" }} diff --git a/compiler/template/native/render.go b/compiler/template/native/render.go index 8066406ec..95389fd1d 100644 --- a/compiler/template/native/render.go +++ b/compiler/template/native/render.go @@ -65,11 +65,11 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM } // RenderBuild renders the templated build. -func RenderBuild(b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { +func RenderBuild(tmpl string, b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { buffer := new(bytes.Buffer) config := new(types.Build) - velaFuncs := funcHandler{envs: convertPlatformVars(envs, "")} + velaFuncs := funcHandler{envs: convertPlatformVars(envs, tmpl)} templateFuncMap := map[string]interface{}{ "vela": velaFuncs.returnPlatformVar, "toYaml": toYAML, @@ -85,7 +85,7 @@ func RenderBuild(b string, envs map[string]string, variables map[string]interfac // parse the template with Masterminds/sprig functions // // https://pkg.go.dev/github.com/Masterminds/sprig?tab=doc#TxtFuncMap - t, err := template.New("build").Funcs(sf).Funcs(templateFuncMap).Parse(b) + t, err := template.New(tmpl).Funcs(sf).Funcs(templateFuncMap).Parse(b) if err != nil { return nil, err } diff --git a/compiler/template/native/render_test.go b/compiler/template/native/render_test.go index 260b3c116..1380f6703 100644 --- a/compiler/template/native/render_test.go +++ b/compiler/template/native/render_test.go @@ -122,7 +122,7 @@ func TestNative_RenderBuild(t *testing.T) { t.Error(err) } - got, err := RenderBuild(string(sFile), map[string]string{ + got, err := RenderBuild("build", string(sFile), map[string]string{ "VELA_REPO_FULL_NAME": "octocat/hello-world", "VELA_BUILD_BRANCH": "master", }, map[string]interface{}{}) diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index e85eafd3a..dd30f073f 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -137,7 +137,7 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM // RenderBuild renders the templated build. // //nolint:lll // ignore function length due to input args -func RenderBuild(b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { +func RenderBuild(tmpl string, b string, envs map[string]string, variables map[string]interface{}) (*types.Build, error) { config := new(types.Build) thread := &starlark.Thread{Name: "templated-base"} @@ -170,7 +170,7 @@ func RenderBuild(b string, envs map[string]string, variables map[string]interfac } // load the platform provided vars into a starlark type - velaVars, err := convertPlatformVars(envs, "") + velaVars, err := convertPlatformVars(envs, tmpl) if err != nil { return nil, err } diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index b97de2c54..8749593c2 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -114,7 +114,7 @@ func TestNative_RenderBuild(t *testing.T) { t.Error(err) } - got, err := RenderBuild(string(sFile), map[string]string{ + got, err := RenderBuild("build", string(sFile), map[string]string{ "VELA_REPO_FULL_NAME": "octocat/hello-world", "VELA_BUILD_BRANCH": "master", }, map[string]interface{}{}) From 0e4c5891b5526bc18442d4662bb8ce29ddabdad0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:19:34 -0500 Subject: [PATCH 117/298] fix(deps): update deps (patch) (#709) --- go.mod | 18 +++++++++--------- go.sum | 48 ++++++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index cbad817cc..cf6b04bb7 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.23.0 - github.com/aws/aws-sdk-go v1.44.99 + github.com/aws/aws-sdk-go v1.44.109 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -34,10 +34,10 @@ require ( golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.9 + gorm.io/driver/postgres v1.3.10 gorm.io/driver/sqlite v1.3.6 - gorm.io/gorm v1.23.9 - k8s.io/apimachinery v0.25.0 + gorm.io/gorm v1.23.10 + k8s.io/apimachinery v0.25.2 ) require ( @@ -86,13 +86,13 @@ require ( github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.12.1 // indirect + github.com/jackc/pgconn v1.13.0 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.11.0 // indirect - github.com/jackc/pgx/v4 v4.16.1 // indirect + github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgx/v4 v4.17.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -125,7 +125,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect + golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index 3addf5198..7080a0406 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.99 h1:ITZ9q/fmH+Ksaz2TbyMU2d19vOOWs/hAlt8NbXAieHw= -github.com/aws/aws-sdk-go v1.44.99/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.109 h1:+Na5JPeS0kiEHoBp5Umcuuf+IDqXqD0lXnM920E31YI= +github.com/aws/aws-sdk-go v1.44.109/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -318,8 +318,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -335,26 +335,26 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -454,7 +454,7 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= @@ -527,16 +527,18 @@ github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= @@ -589,9 +591,9 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -661,6 +663,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= @@ -950,14 +953,15 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= -gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= +gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw= -gorm.io/gorm v1.23.9/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24= +gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -965,8 +969,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU= -k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0= +k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= +k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 23dfb84d1509e02a067198c80d1ec8164328eef1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:24:33 -0500 Subject: [PATCH 118/298] fix(deps): update module github.com/urfave/cli/v2 to v2.17.1 (#710) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cf6b04bb7..2226c8736 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 - github.com/urfave/cli/v2 v2.16.3 + github.com/urfave/cli/v2 v2.17.1 go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index 7080a0406..a16202a7f 100644 --- a/go.sum +++ b/go.sum @@ -543,8 +543,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk= -github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.17.1 h1:UzjDEw2dJQUE3iRaiNQ1VrVFbyAtKGH3VdkMoHA58V0= +github.com/urfave/cli/v2 v2.17.1/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 8c209674f7e699640497ebee454dd45433eb58f5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:30:30 -0600 Subject: [PATCH 119/298] fix(secret): check org casing for repo secret creation (#708) --- api/secret.go | 17 ++++++++++++++--- scm/github/repo.go | 8 ++++---- scm/github/repo_test.go | 19 ++++++++++++------- scm/service.go | 6 +++--- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/api/secret.go b/api/secret.go index 46a9d5ea3..c23bd7010 100644 --- a/api/secret.go +++ b/api/secret.go @@ -78,6 +78,8 @@ import ( // CreateSecret represents the API handler to // create a secret in the configured backend. +// +//nolint:funlen // suppress long function error func CreateSecret(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -136,10 +138,10 @@ func CreateSecret(c *gin.Context) { } if strings.EqualFold(t, constants.SecretRepo) { - // retrieve repo name from SCM + // retrieve org and repo name from SCM // // same story as org secret. SCM has accurate casing. - scmRepo, err := scm.FromContext(c).GetRepoName(u, o, n) + scmOrg, scmRepo, err := scm.FromContext(c).GetOrgAndRepoName(u, o, n) if err != nil { retErr := fmt.Errorf("unable to retrieve repository %s/%s", o, n) @@ -148,7 +150,16 @@ func CreateSecret(c *gin.Context) { return } - // check if casing is accurate + // check if casing is accurate for org entry + if scmOrg != o { + retErr := fmt.Errorf("unable to retrieve org %s. Did you mean %s?", o, scmOrg) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate for repo entry if scmRepo != n { retErr := fmt.Errorf("unable to retrieve repository %s. Did you mean %s?", n, scmRepo) diff --git a/scm/github/repo.go b/scm/github/repo.go index 12a7bb855..cbc858e39 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -310,8 +310,8 @@ func (c *client) GetRepo(u *library.User, r *library.Repo) (*library.Repo, error return toLibraryRepo(*repo), nil } -// GetRepoName returns the name of the repository in the SCM. -func (c *client) GetRepoName(u *library.User, o string, r string) (string, error) { +// GetOrgAndRepoName returns the name of the org and the repository in the SCM. +func (c *client) GetOrgAndRepoName(u *library.User, o string, r string) (string, string, error) { c.Logger.WithFields(logrus.Fields{ "org": o, "repo": r, @@ -324,10 +324,10 @@ func (c *client) GetRepoName(u *library.User, o string, r string) (string, error // send an API call to get the repo info repo, _, err := client.Repositories.Get(ctx, o, r) if err != nil { - return "", err + return "", "", err } - return repo.GetName(), nil + return repo.GetOwner().GetLogin(), repo.GetName(), nil } // ListUserRepos returns a list of all repos the user has access to. diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 769870f34..2d1d63ad9 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1013,7 +1013,7 @@ func TestGithub_GetRepo_Fail(t *testing.T) { } } -func TestGithub_GetRepoName(t *testing.T) { +func TestGithub_GetOrgAndRepoName(t *testing.T) { // setup context gin.SetMode(gin.TestMode) @@ -1035,12 +1035,13 @@ func TestGithub_GetRepoName(t *testing.T) { u.SetName("foo") u.SetToken("bar") - want := "Hello-World" + wantOrg := "octocat" + wantRepo := "Hello-World" client, _ := NewTest(s.URL) // run test - got, err := client.GetRepoName(u, "octocat", "Hello-World") + gotOrg, gotRepo, err := client.GetOrgAndRepoName(u, "octocat", "Hello-World") if resp.Code != http.StatusOK { t.Errorf("GetRepoName returned %v, want %v", resp.Code, http.StatusOK) @@ -1050,12 +1051,16 @@ func TestGithub_GetRepoName(t *testing.T) { t.Errorf("GetRepoName returned err: %v", err) } - if !reflect.DeepEqual(got, want) { - t.Errorf("GetRepoName is %v, want %v", got, want) + if !reflect.DeepEqual(gotOrg, wantOrg) { + t.Errorf("GetRepoName org is %v, want %v", gotOrg, wantOrg) + } + + if !reflect.DeepEqual(gotRepo, wantRepo) { + t.Errorf("GetRepoName repo is %v, want %v", gotRepo, wantRepo) } } -func TestGithub_GetRepoName_Fail(t *testing.T) { +func TestGithub_GetOrgAndRepoName_Fail(t *testing.T) { // setup context gin.SetMode(gin.TestMode) @@ -1079,7 +1084,7 @@ func TestGithub_GetRepoName_Fail(t *testing.T) { client, _ := NewTest(s.URL) // run test - _, err := client.GetRepoName(u, "octocat", "Hello-World") + _, _, err := client.GetOrgAndRepoName(u, "octocat", "Hello-World") if err == nil { t.Error("GetRepoName should return error") diff --git a/scm/service.go b/scm/service.go index a0d55d564..b6e2fa781 100644 --- a/scm/service.go +++ b/scm/service.go @@ -111,9 +111,9 @@ type Service interface { // GetRepo defines a function that retrieves // details for a repo. GetRepo(*library.User, *library.Repo) (*library.Repo, error) - // GetRepoName defines a function that retrieves - // the name of the repo in the SCM. - GetRepoName(*library.User, string, string) (string, error) + // GetOrgAndRepoName defines a function that retrieves + // the name of the org and repo in the SCM. + GetOrgAndRepoName(*library.User, string, string) (string, string, error) // GetOrg defines a function that retrieves // the name for an org in the SCM. GetOrgName(*library.User, string) (string, error) From 6af47f865572a533af96f3ad671ac11f85f07e50 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:43:36 -0500 Subject: [PATCH 120/298] chore: v0.15.0-rc2 (#711) --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 2226c8736..5bfe60fee 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.15.0-rc1 + github.com/go-vela/types v0.15.0-rc2 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 @@ -103,7 +103,7 @@ require ( github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/microcosm-cc/bluemonday v1.0.20 // indirect + github.com/microcosm-cc/bluemonday v1.0.21 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect @@ -126,7 +126,7 @@ require ( github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect + golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect diff --git a/go.sum b/go.sum index a16202a7f..4dcf1909e 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.15.0-rc1 h1:CTXplhQ7mc1yjbWiM6UbE9qPgGE4yBrPBKC0a/rkFDo= -github.com/go-vela/types v0.15.0-rc1/go.mod h1:hQSy2STPChcHk53RFWCEg0gnjHXop+/bVAPkiU9YIqo= +github.com/go-vela/types v0.15.0-rc2 h1:k+U3OAFmyfQw4Wg6YKXFBDzUKCtejJweNpOHChtRrgs= +github.com/go-vela/types v0.15.0-rc2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= @@ -424,8 +424,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y= -github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -666,8 +666,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= From d6e280a65c71d50e56bd565027f4c21c7ea4c6c9 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:32:28 -0500 Subject: [PATCH 121/298] chore: v0.15.0 release prep (#712) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5bfe60fee..12b9b6fb5 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.15.0-rc2 + github.com/go-vela/types v0.15.0 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 4dcf1909e..554c7d02d 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.15.0-rc2 h1:k+U3OAFmyfQw4Wg6YKXFBDzUKCtejJweNpOHChtRrgs= -github.com/go-vela/types v0.15.0-rc2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.15.0 h1:dlNWfcypxMHIDJU9doBbNRHidwZWq9dhYfbfMR29do8= +github.com/go-vela/types v0.15.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 9dbf815379db21c777285a9aa2de10cfbb9a03c6 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 7 Oct 2022 09:46:41 -0500 Subject: [PATCH 122/298] fix(actions): make sure to use latest Go version (#716) --- .github/workflows/build.yml | 1 + .github/workflows/prerelease.yml | 1 + .github/workflows/publish.yml | 1 + .github/workflows/reviewdog.yml | 2 ++ .github/workflows/spec.yml | 1 + .github/workflows/test.yml | 1 + .github/workflows/validate.yml | 1 + 7 files changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac9711453..7b3324deb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: build run: | diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 475429b48..24f8083f5 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -25,6 +25,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: setup run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9f234a8c7..b5324314e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -24,6 +24,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: build env: diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 5e2ccc811..e403fbb13 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -20,6 +20,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 @@ -43,6 +44,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: golangci-lint uses: reviewdog/action-golangci-lint@v2 diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index d5ea466ea..a41b868c0 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -21,6 +21,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: tags run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3a5e6141e..e976579af 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: test run: | diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 61ece7bed..f866fc839 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -21,6 +21,7 @@ jobs: # use version from go.mod file go-version-file: 'go.mod' cache: true + check-latest: true - name: tags run: | From b2dded375584e0168515c8b51a66f88c88238fd1 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 7 Oct 2022 10:26:09 -0500 Subject: [PATCH 123/298] chore: update deps (#718) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 12b9b6fb5..a7764619b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.15.0 + github.com/go-vela/types v0.15.1 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 554c7d02d..269b55458 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.15.0 h1:dlNWfcypxMHIDJU9doBbNRHidwZWq9dhYfbfMR29do8= -github.com/go-vela/types v0.15.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.15.1 h1:nQxfxoqxavuTYtvFJW4wK9UkkADN2VG6Z4ubvJ8PT1s= +github.com/go-vela/types v0.15.1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 24e0360059f02b56151d79f919346909f43cc9b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 05:53:31 +0000 Subject: [PATCH 124/298] fix(deps): update module gorm.io/driver/postgres to v1.4.1 (#714) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a7764619b..8e172d84a 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.3.10 + gorm.io/driver/postgres v1.4.1 gorm.io/driver/sqlite v1.3.6 gorm.io/gorm v1.23.10 k8s.io/apimachinery v0.25.2 diff --git a/go.sum b/go.sum index 269b55458..9473127f5 100644 --- a/go.sum +++ b/go.sum @@ -954,8 +954,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= -gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= +gorm.io/driver/postgres v1.4.1 h1:DutsKq2LK2Ag65q/+VygWth0/L4GAVOp+sCtg6WzZjs= +gorm.io/driver/postgres v1.4.1/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= From 1cc1eab4cf00ad2a84c91716752c4b5aa44ac5b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 02:22:18 +0000 Subject: [PATCH 125/298] fix(deps): update module gorm.io/driver/sqlite to v1.4.2 (#715) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 8e172d84a..047c2fcbe 100644 --- a/go.mod +++ b/go.mod @@ -35,8 +35,8 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.4.1 - gorm.io/driver/sqlite v1.3.6 - gorm.io/gorm v1.23.10 + gorm.io/driver/sqlite v1.4.2 + gorm.io/gorm v1.24.0 k8s.io/apimachinery v0.25.2 ) diff --git a/go.sum b/go.sum index 9473127f5..2cb8f3dd0 100644 --- a/go.sum +++ b/go.sum @@ -419,7 +419,7 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -956,12 +956,11 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.4.1 h1:DutsKq2LK2Ag65q/+VygWth0/L4GAVOp+sCtg6WzZjs= gorm.io/driver/postgres v1.4.1/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= -gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= -gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/driver/sqlite v1.4.2 h1:F6vYJcmR4Cnh0ErLyoY8JSfabBGyR0epIGuhgHJuNws= +gorm.io/driver/sqlite v1.4.2/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24= -gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74= +gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 05558ee99d70f7d6f83bed7c8f78ac0b35fa26f4 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Wed, 9 Nov 2022 09:50:11 -0600 Subject: [PATCH 126/298] Merge pull request from GHSA-5m7g-pj8w-7593 * fix(allowlist)!: modify repo allowlist behavior * setting allow pull to false on create repo endpoint by default Co-authored-by: ecrupper --- api/repo.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/repo.go b/api/repo.go index b1ee44035..b8e9725fd 100644 --- a/api/repo.go +++ b/api/repo.go @@ -153,8 +153,7 @@ func CreateRepo(c *gin.Context) { if !input.GetAllowPull() && !input.GetAllowPush() && !input.GetAllowDeploy() && !input.GetAllowTag() && !input.GetAllowComment() { - // default events to push and pull_request - r.SetAllowPull(true) + // default event to push r.SetAllowPush(true) } else { r.SetAllowComment(input.GetAllowComment()) @@ -1044,11 +1043,12 @@ func ChownRepo(c *gin.Context) { } // checkAllowlist is a helper function to ensure only repos in the -// allowlist are allowed to enable repos. If the allowlist is -// empty then any repo can be enabled. +// allowlist are allowed to enable repos. +// +// a single entry of '*' allows any repo to be enabled. func checkAllowlist(r *library.Repo, allowlist []string) bool { - // if the allowlist is not set or empty allow any repo to be enabled - if len(allowlist) == 0 { + // check if all repos are allowed to be enabled + if len(allowlist) == 1 && allowlist[0] == "*" { return true } From 04ff9e1fbfd92b032d2707cfa21632000550c226 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Wed, 9 Nov 2022 09:54:55 -0600 Subject: [PATCH 127/298] enhance(repo): allow platform admins to update repo.trusted (#724) --- api/repo.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/repo.go b/api/repo.go index b8e9725fd..ccb0ffa81 100644 --- a/api/repo.go +++ b/api/repo.go @@ -149,6 +149,14 @@ func CreateRepo(c *gin.Context) { r.SetVisibility(input.GetVisibility()) } + // fields restricted to platform admins + if u.GetAdmin() { + // trusted default is false + if input.GetTrusted() != r.GetTrusted() { + r.SetTrusted(input.GetTrusted()) + } + } + // set default events if no events are passed in if !input.GetAllowPull() && !input.GetAllowPush() && !input.GetAllowDeploy() && !input.GetAllowTag() && @@ -788,6 +796,14 @@ func UpdateRepo(c *gin.Context) { ) } + // fields restricted to platform admins + if u.GetAdmin() { + // trusted + if input.GetTrusted() != r.GetTrusted() { + r.SetTrusted(input.GetTrusted()) + } + } + // send API call to update the repo err = database.FromContext(c).UpdateRepo(r) if err != nil { From e972584299eb9989525aa62df9438d9bd60429f1 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Wed, 9 Nov 2022 10:15:35 -0600 Subject: [PATCH 128/298] chore(release): v0.16.0 release (#732) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 047c2fcbe..632a6d620 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.15.1 + github.com/go-vela/types v0.16.0 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 2cb8f3dd0..e124147a0 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.15.1 h1:nQxfxoqxavuTYtvFJW4wK9UkkADN2VG6Z4ubvJ8PT1s= -github.com/go-vela/types v0.15.1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.16.0 h1:YsgbnnOS7FPFA0dPRZCLH2ryCdya14qSi3MgJab6ixo= +github.com/go-vela/types v0.16.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From b6074fbca431f8f01db4e99e812e437515b5ffd3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 12:49:09 -0600 Subject: [PATCH 129/298] fix(deps): update go.starlark.net digest to acb66ad (#723) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 632a6d620..06e59bbc2 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.17.1 - go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d + go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index e124147a0..5d2da4501 100644 --- a/go.sum +++ b/go.sum @@ -563,8 +563,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d h1:aF+anaRVZu22kdETjLavnIn/cvD+arhmik6vMU3joW4= -go.starlark.net v0.0.0-20220928063852-5fccb4daaf6d/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= +go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 h1:5/KzhcSqd4UgY51l17r7C5g/JiE6DRw1Vq7VJfQHuMc= +go.starlark.net v0.0.0-20221028183056-acb66ad56dd2/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From f9e3663cbb676087d1081e56d017eb0b436003ab Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Wed, 9 Nov 2022 12:53:35 -0600 Subject: [PATCH 130/298] fix(actions): sudo make spec-install (#726) Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- .github/workflows/spec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index a41b868c0..e380b1fb7 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -29,7 +29,7 @@ jobs: - name: create spec run: | - make spec-install + sudo make spec-install make spec - name: upload spec From 1028fff78a0b627580c23162e434582cde7e29b3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 12:58:04 -0600 Subject: [PATCH 131/298] fix(deps): update deps (patch) (#728) --- go.mod | 24 +++++++++++----------- go.sum | 63 +++++++++++++++++++++++++++++++--------------------------- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index 06e59bbc2..cad1a1ff4 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.1.1 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/alicebob/miniredis/v2 v2.23.0 - github.com/aws/aws-sdk-go v1.44.109 + github.com/alicebob/miniredis/v2 v2.23.1 + github.com/aws/aws-sdk-go v1.44.133 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/hashicorp/vault/api v1.8.0 + github.com/hashicorp/vault/api v1.8.2 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.13.0 @@ -34,10 +34,10 @@ require ( golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.4.1 - gorm.io/driver/sqlite v1.4.2 - gorm.io/gorm v1.24.0 - k8s.io/apimachinery v0.25.2 + gorm.io/driver/postgres v1.4.5 + gorm.io/driver/sqlite v1.4.3 + gorm.io/gorm v1.24.1 + k8s.io/apimachinery v0.25.3 ) require ( @@ -71,7 +71,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v0.16.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-plugin v1.4.3 // indirect + github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect @@ -123,12 +123,12 @@ require ( github.com/spf13/cast v1.3.1 // indirect github.com/ugorji/go/codec v1.2.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect + github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect diff --git a/go.sum b/go.sum index 5d2da4501..8cd23156c 100644 --- a/go.sum +++ b/go.sum @@ -64,16 +64,16 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.23.0 h1:+lwAJYjvvdIVg6doFHuotFjueJ/7KY10xo/vm3X3Scw= -github.com/alicebob/miniredis/v2 v2.23.0/go.mod h1:XNqvJdQJv5mSuVMc0ynneafpnL/zv52acZ6kqeS0t88= +github.com/alicebob/miniredis/v2 v2.23.1 h1:jR6wZggBxwWygeXcdNyguCOCIjPsZyNUNlAkTx2fu0U= +github.com/alicebob/miniredis/v2 v2.23.1/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.109 h1:+Na5JPeS0kiEHoBp5Umcuuf+IDqXqD0lXnM920E31YI= -github.com/aws/aws-sdk-go v1.44.109/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.133 h1:+pWxt9nyKc0jf33rORBaQ93KPjYpmIIy3ozVXdJ82Oo= +github.com/aws/aws-sdk-go v1.44.133/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -259,7 +259,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -268,8 +267,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= -github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= +github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= +github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -295,8 +294,8 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.8.0 h1:7765sW1XBt+qf4XKIYE4ebY9qc/yi9V2/egzGSUNMZU= -github.com/hashicorp/vault/api v1.8.0/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E= +github.com/hashicorp/vault/api v1.8.2 h1:C7OL9YtOtwQbTKI9ogB0A1wffRbCN+rH/LLCHO3d8HM= +github.com/hashicorp/vault/api v1.8.2/go.mod h1:ML8aYzBIhY5m1MD1B2Q0JV89cC85YVH4t5kBaZiyVaE= github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZTIAhs= github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= @@ -356,7 +355,6 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= -github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -431,7 +429,6 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= @@ -551,10 +548,11 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 h1:k/gmLsJDWwWqbLCur2yWnJzwQEKRcAHXo6seXGuSwWw= -github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -591,6 +589,7 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -627,7 +626,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -666,8 +665,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU= -golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -691,6 +691,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -746,13 +747,16 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -760,8 +764,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -821,6 +826,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -854,7 +860,6 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -893,7 +898,6 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 h1:PYBmACG+YEv8uQPW0r1kJj8tR+gkF0UWq7iFdUezwEw= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -954,13 +958,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.4.1 h1:DutsKq2LK2Ag65q/+VygWth0/L4GAVOp+sCtg6WzZjs= -gorm.io/driver/postgres v1.4.1/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= -gorm.io/driver/sqlite v1.4.2 h1:F6vYJcmR4Cnh0ErLyoY8JSfabBGyR0epIGuhgHJuNws= -gorm.io/driver/sqlite v1.4.2/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= -gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.24.0 h1:j/CoiSm6xpRpmzbFJsQHYj+I8bGYWLXVHeYEyyKlF74= +gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= +gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= +gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= +gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -968,8 +973,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= -k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= +k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc= +k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 26796efcc3f26093716842d58b7ae97f8a862de5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 13:03:05 -0600 Subject: [PATCH 132/298] fix(deps): update module github.com/urfave/cli/v2 to v2.23.5 (#729) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cad1a1ff4..57c8c983a 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.13.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 - github.com/urfave/cli/v2 v2.17.1 + github.com/urfave/cli/v2 v2.23.5 go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index 8cd23156c..94908cb83 100644 --- a/go.sum +++ b/go.sum @@ -540,8 +540,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.17.1 h1:UzjDEw2dJQUE3iRaiNQ1VrVFbyAtKGH3VdkMoHA58V0= -github.com/urfave/cli/v2 v2.17.1/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw= +github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 6f494bbdc9a3c9ab01d12095f9dfa47a6f247e0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 13:08:28 -0600 Subject: [PATCH 133/298] fix(deps): update module github.com/prometheus/client_golang to v1.14.0 (#731) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 57c8c983a..53c8679cb 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/hashicorp/vault/api v1.8.2 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.13.0 + github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.2 github.com/urfave/cli/v2 v2.23.5 @@ -114,7 +114,7 @@ require ( github.com/oklog/run v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect - github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index 94908cb83..7074e1008 100644 --- a/go.sum +++ b/go.sum @@ -473,13 +473,14 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= From 60026ee501b700f7595d26ddcd0851a3570b6663 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 13:13:14 -0600 Subject: [PATCH 134/298] chore(deps): update postgres docker tag to v15 (#725) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7f9710d94..7e441fb9f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -125,7 +125,7 @@ services: # https://www.postgresql.org/ postgres: container_name: postgres - image: postgres:14-alpine + image: postgres:15-alpine networks: - vela environment: From c47375a69c01c3143f3ba37de89f6f5c9eed3f02 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Nov 2022 13:20:59 -0600 Subject: [PATCH 135/298] fix(deps): update module github.com/go-vela/types to v0.16.1 (#733) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 53c8679cb..7f60cecf5 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.16.0 + github.com/go-vela/types v0.16.1 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 7074e1008..86305caf5 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.16.0 h1:YsgbnnOS7FPFA0dPRZCLH2ryCdya14qSi3MgJab6ixo= -github.com/go-vela/types v0.16.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.16.1 h1:PGtOQ0AQLAFJ23wi6ns5JF1y68v4VjA/NbZs5HYZmhY= +github.com/go-vela/types v0.16.1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 48463869c079d7ccb98e96109d099614448b210c Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 15 Nov 2022 10:40:09 -0700 Subject: [PATCH 136/298] enhance(admin/api): remove collect all endpoints for DB resources (#734) --- api/admin/build.go | 39 --------------------------------------- api/admin/deployment.go | 20 -------------------- api/admin/hook.go | 39 --------------------------------------- api/admin/repo.go | 39 --------------------------------------- api/admin/secret.go | 39 --------------------------------------- api/admin/service.go | 39 --------------------------------------- api/admin/step.go | 39 --------------------------------------- api/admin/user.go | 39 --------------------------------------- router/admin.go | 8 -------- 9 files changed, 301 deletions(-) diff --git a/api/admin/build.go b/api/admin/build.go index c04a8cacd..28ca14ddf 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -20,45 +20,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/builds admin AdminAllBuilds -// -// Get all of the builds in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all builds from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Build" -// '500': -// description: Unable to retrieve all builds from the database -// schema: -// "$ref": "#/definitions/Error" - -// AllBuilds represents the API handler to -// captures all builds stored in the database. -func AllBuilds(c *gin.Context) { - logrus.Info("Admin: reading all builds") - - // send API call to capture all builds - b, err := database.FromContext(c).GetBuildList() - if err != nil { - retErr := fmt.Errorf("unable to capture all builds: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, b) -} - // swagger:operation GET /api/v1/admin/builds/queue admin AllBuildsQueue // // Get all of the running and pending builds in the database diff --git a/api/admin/deployment.go b/api/admin/deployment.go index 94fe009a2..063407b6d 100644 --- a/api/admin/deployment.go +++ b/api/admin/deployment.go @@ -10,26 +10,6 @@ import ( "github.com/gin-gonic/gin" ) -// swagger:operation GET /api/v1/admin/deployments admin AdminAllDeployments -// -// Get all of the deployments in the database (Not Implemented) -// -// --- -// produces: -// - application/json -// parameters: -// responses: -// '501': -// description: This endpoint is not implemented -// schema: -// type: string - -// AllDeployments represents the API handler to -// captures all deployments stored in the database. -func AllDeployments(c *gin.Context) { - c.JSON(http.StatusNotImplemented, "The server does not support the functionality required to fulfill the request.") -} - // swagger:operation PUT /api/v1/admin/deployment admin AdminUpdateDeployment // // Get All (Not Implemented) diff --git a/api/admin/hook.go b/api/admin/hook.go index d3ca8ade5..a680d598d 100644 --- a/api/admin/hook.go +++ b/api/admin/hook.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/hooks admin AdminAllHooks -// -// Get all of the webhooks stored in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all hooks from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Webhook" -// '500': -// description: Unable to retrieve all hooks -// schema: -// "$ref": "#/definitions/Error" - -// AllHooks represents the API handler to -// captures all hooks stored in the database. -func AllHooks(c *gin.Context) { - logrus.Info("Admin: reading all hooks") - - // send API call to capture all hooks - r, err := database.FromContext(c).GetHookList() - if err != nil { - retErr := fmt.Errorf("unable to capture all hooks: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, r) -} - // swagger:operation PUT /api/v1/admin/hook admin AdminUpdateHook // // Update a hook in the database diff --git a/api/admin/repo.go b/api/admin/repo.go index c48e98933..0f7327193 100644 --- a/api/admin/repo.go +++ b/api/admin/repo.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/repos admin AdminAllRepos -// -// Get all of the repos in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all repos from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Repo" -// '500': -// description: Unable to retrieve all repos from the database -// schema: -// "$ref": "#/definitions/Error" - -// AllRepos represents the API handler to -// captures all repos stored in the database. -func AllRepos(c *gin.Context) { - logrus.Info("Admin: reading all repos") - - // send API call to capture all repos - r, err := database.FromContext(c).ListRepos() - if err != nil { - retErr := fmt.Errorf("unable to capture all repos: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, r) -} - // swagger:operation PUT /api/v1/admin/repo admin AdminUpdateRepo // // Update a repo in the database diff --git a/api/admin/secret.go b/api/admin/secret.go index 8e613ea6a..d6df890d3 100644 --- a/api/admin/secret.go +++ b/api/admin/secret.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/secrets admin AdminAllSecrets -// -// Get all of the secrets in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all secrets from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Secret" -// '500': -// description: Unable to retrieve all secrets from the database -// schema: -// "$ref": "#/definitions/Error" - -// AllSecrets represents the API handler to -// captures all secrets stored in the database. -func AllSecrets(c *gin.Context) { - logrus.Info("Admin: reading all secrets") - - // send API call to capture all secrets - s, err := database.FromContext(c).GetSecretList() - if err != nil { - retErr := fmt.Errorf("unable to capture all secrets: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, s) -} - // swagger:operation PUT /api/v1/admin/secret admin AdminUpdateSecret // // Update a secret in the database diff --git a/api/admin/service.go b/api/admin/service.go index 240c346af..2cd295c4c 100644 --- a/api/admin/service.go +++ b/api/admin/service.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/services admin AdminAllServices -// -// Get all of the services in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all services from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Service" -// '500': -// description: Unable to retrieve all services from the database -// schema: -// "$ref": "#/definitions/Error" - -// AllServices represents the API handler to -// captures all services stored in the database. -func AllServices(c *gin.Context) { - logrus.Info("Admin: reading all services") - - // send API call to capture all services - s, err := database.FromContext(c).GetServiceList() - if err != nil { - retErr := fmt.Errorf("unable to capture all services: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, s) -} - // swagger:operation PUT /api/v1/admin/service admin AdminUpdateService // // Update a hook in the database diff --git a/api/admin/step.go b/api/admin/step.go index 816270c1d..5f03aff6b 100644 --- a/api/admin/step.go +++ b/api/admin/step.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/steps admin AdminAllSteps -// -// Get all of the steps in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all steps from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/Step" -// '500': -// description: Unable to retrieve all steps from the database -// schema: -// "$ref": "#/definitions/Error" - -// AllSteps represents the API handler to -// captures all steps stored in the database. -func AllSteps(c *gin.Context) { - logrus.Info("Admin: reading all steps") - - // send API call to capture all steps - s, err := database.FromContext(c).GetStepList() - if err != nil { - retErr := fmt.Errorf("unable to capture all steps: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, s) -} - // swagger:operation PUT /api/v1/admin/step admin AdminUpdateStep // // Update a step in the database diff --git a/api/admin/user.go b/api/admin/user.go index a176f30ed..f7ef70ba3 100644 --- a/api/admin/user.go +++ b/api/admin/user.go @@ -18,45 +18,6 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/admin/users admin AdminAllUsers -// -// Get all of the users in the database -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved all users from the database -// schema: -// type: array -// items: -// "$ref": "#/definitions/User" -// '500': -// description: Unable to retrieve all users from the database -// schema: -// type: string - -// AllUsers represents the API handler to -// captures all users stored in the database. -func AllUsers(c *gin.Context) { - logrus.Info("Admin: reading all users") - - // send API call to capture all users - u, err := database.FromContext(c).ListUsers() - if err != nil { - retErr := fmt.Errorf("unable to capture all users: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, u) -} - // swagger:operation PUT /api/v1/admin/user admin AdminUpdateUser // // Update a user in the database diff --git a/router/admin.go b/router/admin.go index f8c259795..86bda3501 100644 --- a/router/admin.go +++ b/router/admin.go @@ -35,36 +35,28 @@ func AdminHandlers(base *gin.RouterGroup) { _admin := base.Group("/admin", perm.MustPlatformAdmin()) { // Admin build endpoints - _admin.GET("/builds", admin.AllBuilds) _admin.GET("/builds/queue", admin.AllBuildsQueue) _admin.PUT("/build", admin.UpdateBuild) // Admin deployment endpoints - _admin.GET("/deployments", admin.AllDeployments) _admin.PUT("/deployment", admin.UpdateDeployment) // Admin hook endpoints - _admin.GET("/hooks", admin.AllHooks) _admin.PUT("/hook", admin.UpdateHook) // Admin repo endpoints - _admin.GET("/repos", admin.AllRepos) _admin.PUT("/repo", admin.UpdateRepo) // Admin secret endpoints - _admin.GET("/secrets", admin.AllSecrets) _admin.PUT("/secret", admin.UpdateSecret) // Admin service endpoints - _admin.GET("/services", admin.AllServices) _admin.PUT("/service", admin.UpdateService) // Admin step endpoints - _admin.GET("/steps", admin.AllSteps) _admin.PUT("/step", admin.UpdateStep) // Admin user endpoints - _admin.GET("/users", admin.AllUsers) _admin.PUT("/user", admin.UpdateUser) } // end of admin endpoints } From 4335e56f8e87c7f7ea82afcca436c5945730e4a6 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 15 Nov 2022 11:04:16 -0700 Subject: [PATCH 137/298] chore(release): v0.16.2 prep (#735) * chore(release): v0.16.2 prep * go mod tidy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7f60cecf5..4dfcb928a 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.16.1 + github.com/go-vela/types v0.16.2 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 86305caf5..993ccfd7c 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.16.1 h1:PGtOQ0AQLAFJ23wi6ns5JF1y68v4VjA/NbZs5HYZmhY= -github.com/go-vela/types v0.16.1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.16.2 h1:c2Kkj7OKv4sjPrsOBbnPSQqfsNpOFM2La7LfP+81EF0= +github.com/go-vela/types v0.16.2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 4fd6409e34c66ffd77a91c767aa0e966a75ca79e Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 9 Dec 2022 09:59:14 -0800 Subject: [PATCH 138/298] refactor(database): move worker logic into separate package (#692) --- api/build.go | 2 +- api/metrics.go | 2 +- api/worker.go | 8 +- database/postgres/ddl/worker.go | 33 -- database/postgres/dml/worker.go | 47 --- database/postgres/postgres.go | 29 +- database/postgres/postgres_test.go | 19 +- database/postgres/worker.go | 114 ------- database/postgres/worker_count.go | 26 -- database/postgres/worker_count_test.go | 82 ----- database/postgres/worker_list.go | 39 --- database/postgres/worker_list_test.go | 86 ----- database/postgres/worker_test.go | 316 ------------------ database/service.go | 27 +- database/sqlite/ddl/worker.go | 33 -- database/sqlite/dml/worker.go | 47 --- database/sqlite/sqlite.go | 27 +- database/sqlite/worker.go | 114 ------- database/sqlite/worker_count_test.go | 97 ------ database/sqlite/worker_list_test.go | 95 ------ database/sqlite/worker_test.go | 311 ----------------- .../worker_count.go => worker/count.go} | 15 +- database/worker/count_test.go | 93 ++++++ database/worker/create.go | 38 +++ database/worker/create_test.go | 73 ++++ database/worker/delete.go | 30 ++ database/worker/delete_test.go | 73 ++++ database/worker/get.go | 34 ++ database/worker/get_hostname.go | 37 ++ database/worker/get_hostname_test.go | 85 +++++ database/worker/get_test.go | 85 +++++ database/worker/index.go | 24 ++ database/worker/index_test.go | 59 ++++ .../{sqlite/worker_list.go => worker/list.go} | 39 ++- database/worker/list_test.go | 103 ++++++ database/worker/opts.go | 44 +++ database/worker/opts_test.go | 161 +++++++++ database/worker/service.go | 43 +++ database/worker/table.go | 60 ++++ database/worker/table_test.go | 59 ++++ database/worker/update.go | 38 +++ database/worker/update_test.go | 75 +++++ database/worker/worker.go | 80 +++++ database/worker/worker_test.go | 181 ++++++++++ router/middleware/executors/executors.go | 2 +- router/middleware/worker/worker.go | 2 +- 46 files changed, 1567 insertions(+), 1520 deletions(-) delete mode 100644 database/postgres/ddl/worker.go delete mode 100644 database/postgres/dml/worker.go delete mode 100644 database/postgres/worker.go delete mode 100644 database/postgres/worker_count.go delete mode 100644 database/postgres/worker_count_test.go delete mode 100644 database/postgres/worker_list.go delete mode 100644 database/postgres/worker_list_test.go delete mode 100644 database/postgres/worker_test.go delete mode 100644 database/sqlite/ddl/worker.go delete mode 100644 database/sqlite/dml/worker.go delete mode 100644 database/sqlite/worker.go delete mode 100644 database/sqlite/worker_count_test.go delete mode 100644 database/sqlite/worker_list_test.go delete mode 100644 database/sqlite/worker_test.go rename database/{sqlite/worker_count.go => worker/count.go} (53%) create mode 100644 database/worker/count_test.go create mode 100644 database/worker/create.go create mode 100644 database/worker/create_test.go create mode 100644 database/worker/delete.go create mode 100644 database/worker/delete_test.go create mode 100644 database/worker/get.go create mode 100644 database/worker/get_hostname.go create mode 100644 database/worker/get_hostname_test.go create mode 100644 database/worker/get_test.go create mode 100644 database/worker/index.go create mode 100644 database/worker/index_test.go rename database/{sqlite/worker_list.go => worker/list.go} (51%) create mode 100644 database/worker/list_test.go create mode 100644 database/worker/opts.go create mode 100644 database/worker/opts_test.go create mode 100644 database/worker/service.go create mode 100644 database/worker/table.go create mode 100644 database/worker/table_test.go create mode 100644 database/worker/update.go create mode 100644 database/worker/update_test.go create mode 100644 database/worker/worker.go create mode 100644 database/worker/worker_test.go diff --git a/api/build.go b/api/build.go index 6abb48fee..4e35b7d33 100644 --- a/api/build.go +++ b/api/build.go @@ -1638,7 +1638,7 @@ func CancelBuild(c *gin.Context) { } // retrieve the worker info - w, err := database.FromContext(c).GetWorker(b.GetHost()) + w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) if err != nil { retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/api/metrics.go b/api/metrics.go index edbe8ecdd..b5f6fe942 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -365,7 +365,7 @@ func recordGauges(c *gin.Context) { // worker_build_limit, active_worker_count, inactive_worker_count if q.WorkerBuildLimit || q.ActiveWorkerCount || q.InactiveWorkerCount { // send API call to capture the workers - workers, err := database.FromContext(c).GetWorkerList() + workers, err := database.FromContext(c).ListWorkers() if err != nil { logrus.Errorf("unable to get workers: %v", err) } diff --git a/api/worker.go b/api/worker.go index 6f5b65636..4951b182a 100644 --- a/api/worker.go +++ b/api/worker.go @@ -122,7 +122,7 @@ func GetWorkers(c *gin.Context) { "user": u.GetName(), }).Info("reading workers") - w, err := database.FromContext(c).GetWorkerList() + w, err := database.FromContext(c).ListWorkers() if err != nil { retErr := fmt.Errorf("unable to get workers: %w", err) @@ -174,7 +174,7 @@ func GetWorker(c *gin.Context) { "worker": w.GetHostname(), }).Infof("reading worker %s", w.GetHostname()) - w, err := database.FromContext(c).GetWorker(w.GetHostname()) + w, err := database.FromContext(c).GetWorkerForHostname(w.GetHostname()) if err != nil { retErr := fmt.Errorf("unable to get workers: %w", err) @@ -283,7 +283,7 @@ func UpdateWorker(c *gin.Context) { } // send API call to capture the updated worker - w, _ = database.FromContext(c).GetWorker(w.GetHostname()) + w, _ = database.FromContext(c).GetWorkerForHostname(w.GetHostname()) c.JSON(http.StatusOK, w) } @@ -329,7 +329,7 @@ func DeleteWorker(c *gin.Context) { }).Infof("deleting worker %s", w.GetHostname()) // send API call to remove the step - err := database.FromContext(c).DeleteWorker(w.GetID()) + err := database.FromContext(c).DeleteWorker(w) if err != nil { retErr := fmt.Errorf("unable to delete worker %s: %w", w.GetHostname(), err) diff --git a/database/postgres/ddl/worker.go b/database/postgres/ddl/worker.go deleted file mode 100644 index dd8658e7c..000000000 --- a/database/postgres/ddl/worker.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateWorkerTable represents a query to - // create the workers table for Vela. - CreateWorkerTable = ` -CREATE TABLE -IF NOT EXISTS -workers ( - id SERIAL PRIMARY KEY, - hostname VARCHAR(250), - address VARCHAR(250), - routes VARCHAR(1000), - active BOOLEAN, - last_checked_in INTEGER, - build_limit INTEGER, - UNIQUE(hostname) -); -` - - // CreateWorkerHostnameAddressIndex represents a query to create an - // index on the workers table for the hostname and address columns. - CreateWorkerHostnameAddressIndex = ` -CREATE INDEX -IF NOT EXISTS -workers_hostname_address -ON workers (hostname, address); -` -) diff --git a/database/postgres/dml/worker.go b/database/postgres/dml/worker.go deleted file mode 100644 index 3ac74fd2e..000000000 --- a/database/postgres/dml/worker.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListWorkers represents a query to - // list all workers in the database. - ListWorkers = ` -SELECT * -FROM workers; -` - - // SelectWorkersCount represents a query to select the - // count of workers in the database. - SelectWorkersCount = ` -SELECT count(*) as count -FROM workers; -` - - // SelectWorker represents a query to select a - // worker by hostname in the database. - SelectWorker = ` -SELECT * -FROM workers -WHERE hostname = ? -LIMIT 1; -` - - // SelectWorkerByAddress represents a query to select a - // worker by address in the database. - SelectWorkerByAddress = ` -SELECT * -FROM workers -WHERE address = ? -LIMIT 1; -` - - // DeleteWorker represents a query to - // remove a worker from the database. - DeleteWorker = ` -DELETE -FROM workers -WHERE id = ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 263b229a7..04d844675 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -13,6 +13,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -50,6 +51,8 @@ type ( repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService + // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService + worker.WorkerService } ) @@ -152,6 +155,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // create the new mock Postgres database client // @@ -268,12 +273,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } - // create the workers table - err = c.Postgres.Exec(ddl.CreateWorkerTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableWorker, err) - } - return nil } @@ -336,12 +335,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } - // create the workers_hostname_address index for the workers table - err = c.Postgres.Exec(ddl.CreateWorkerHostnameAddressIndex).Error - if err != nil { - return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %w", constants.TableWorker, err) - } - return nil } @@ -388,5 +381,17 @@ func createServices(c *client) error { return err } + // create the database agnostic worker service + // + // https://pkg.go.dev/github.com/go-vela/server/database/worker#New + c.WorkerService, err = worker.New( + worker.WithClient(c.Postgres), + worker.WithLogger(c.Logger), + worker.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + return nil } diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 53375a1e7..ec80173f1 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -14,6 +14,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" ) @@ -82,7 +83,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateWorkerTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the index queries _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -94,13 +94,19 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the worker queries + _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // setup the skip test database client _skipDatabase, _skipMock, err := NewTest() @@ -167,7 +173,6 @@ func TestPostgres_createTables(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateWorkerTable).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool @@ -215,7 +220,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateWorkerHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool @@ -253,13 +257,18 @@ func TestPostgres_createServices(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - // ensure the mock expects the index queries + // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the worker queries + _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool diff --git a/database/postgres/worker.go b/database/postgres/worker.go deleted file mode 100644 index 1d871f596..000000000 --- a/database/postgres/worker.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetWorker gets a worker by hostname from the database. -func (c *client) GetWorker(hostname string) (*library.Worker, error) { - c.Logger.WithFields(logrus.Fields{ - "worker": hostname, - }).Tracef("getting worker %s from the database", hostname) - - // variable to store query results - w := new(database.Worker) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableWorker). - Raw(dml.SelectWorker, hostname). - Scan(w) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return w.ToLibrary(), result.Error -} - -// GetWorker gets a worker by address from the database. -func (c *client) GetWorkerByAddress(address string) (*library.Worker, error) { - c.Logger.Tracef("getting worker by address %s from the database", address) - - // variable to store query results - w := new(database.Worker) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableWorker). - Raw(dml.SelectWorkerByAddress, address). - Scan(w) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return w.ToLibrary(), result.Error -} - -// CreateWorker creates a new worker in the database. -func (c *client) CreateWorker(w *library.Worker) error { - c.Logger.WithFields(logrus.Fields{ - "worker": w.GetHostname(), - }).Tracef("creating worker %s in the database", w.GetHostname()) - - // cast to database type - worker := database.WorkerFromLibrary(w) - - // validate the necessary fields are populated - err := worker.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableWorker). - Create(worker).Error -} - -// UpdateWorker updates a worker in the database. -func (c *client) UpdateWorker(w *library.Worker) error { - c.Logger.WithFields(logrus.Fields{ - "worker": w.GetHostname(), - }).Tracef("updating worker %s in the database", w.GetHostname()) - - // cast to database type - worker := database.WorkerFromLibrary(w) - - // validate the necessary fields are populated - err := worker.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableWorker). - Save(worker).Error -} - -// DeleteWorker deletes a worker by unique ID from the database. -func (c *client) DeleteWorker(id int64) error { - c.Logger.Tracef("deleting worker %d in the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableWorker). - Exec(dml.DeleteWorker, id).Error -} diff --git a/database/postgres/worker_count.go b/database/postgres/worker_count.go deleted file mode 100644 index d5f867988..000000000 --- a/database/postgres/worker_count.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" -) - -// GetWorkerCount gets a count of all workers from the database. -func (c *client) GetWorkerCount() (int64, error) { - c.Logger.Trace("getting count of workers from the database") - - // variable to store query results - var w int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableWorker). - Raw(dml.SelectWorkersCount). - Pluck("count", &w).Error - - return w, err -} diff --git a/database/postgres/worker_count_test.go b/database/postgres/worker_count_test.go deleted file mode 100644 index 61645f5ee..000000000 --- a/database/postgres/worker_count_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetWorkerCount(t *testing.T) { - // setup types - _workerOne := testWorker() - _workerOne.SetID(1) - _workerOne.SetHostname("worker_0") - _workerOne.SetAddress("localhost") - _workerOne.SetActive(true) - - _workerTwo := testWorker() - _workerTwo.SetID(2) - _workerTwo.SetHostname("worker_1") - _workerTwo.SetAddress("localhost") - _workerTwo.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectWorkersCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetWorkerCount() - - if test.failure { - if err == nil { - t.Errorf("GetWorkerCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/worker_list.go b/database/postgres/worker_list.go deleted file mode 100644 index 87bc66e7b..000000000 --- a/database/postgres/worker_list.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" -) - -// GetWorkerList gets a list of all workers from the database. -func (c *client) GetWorkerList() ([]*library.Worker, error) { - c.Logger.Trace("listing workers from the database") - - // variable to store query results - w := new([]database.Worker) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableWorker). - Raw(dml.ListWorkers). - Scan(w).Error - - // variable we want to return - workers := []*library.Worker{} - // iterate through all query results - for _, worker := range *w { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := worker - - // convert query result to library type - workers = append(workers, tmp.ToLibrary()) - } - - return workers, err -} diff --git a/database/postgres/worker_list_test.go b/database/postgres/worker_list_test.go deleted file mode 100644 index b6b3684cc..000000000 --- a/database/postgres/worker_list_test.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetWorkerList(t *testing.T) { - // setup types - _workerOne := testWorker() - _workerOne.SetID(1) - _workerOne.SetHostname("worker_0") - _workerOne.SetAddress("localhost") - _workerOne.SetActive(true) - - _workerTwo := testWorker() - _workerTwo.SetID(2) - _workerTwo.SetHostname("worker_1") - _workerTwo.SetAddress("localhost") - _workerTwo.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListWorkers).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}, - ).AddRow(1, "worker_0", "localhost", "{}", true, 0, 0). - AddRow(2, "worker_1", "localhost", "{}", true, 0, 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Worker - }{ - { - failure: false, - want: []*library.Worker{_workerOne, _workerTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetWorkerList() - - if test.failure { - if err == nil { - t.Errorf("GetWorkerList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/worker_test.go b/database/postgres/worker_test.go deleted file mode 100644 index dcc983203..000000000 --- a/database/postgres/worker_test.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - "gorm.io/gorm" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" -) - -func TestPostgres_Client_GetWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectWorker, "worker_0").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}, - ).AddRow(1, "worker_0", "localhost", "{}", true, 0, 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Worker - }{ - { - failure: false, - want: _worker, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetWorker("worker_0") - - if test.failure { - if err == nil { - t.Errorf("GetWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorker returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorker is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetWorkerByAddress(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectWorkerByAddress, "localhost").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}, - ).AddRow(1, "worker_0", "localhost", "{}", true, 0, 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Worker - }{ - { - failure: false, - want: _worker, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetWorkerByAddress("localhost") - - if test.failure { - if err == nil { - t.Errorf("GetWorkerByAddress should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerByAddress returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerByAddress is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "workers" ("hostname","address","routes","active","last_checked_in","build_limit","id") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`). - WithArgs("worker_0", "localhost", "{}", true, nil, nil, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateWorker(_worker) - - if test.failure { - if err == nil { - t.Errorf("CreateWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateWorker returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "workers" SET "hostname"=$1,"address"=$2,"routes"=$3,"active"=$4,"last_checked_in"=$5,"build_limit"=$6 WHERE "id" = $7`). - WithArgs("worker_0", "localhost", "{}", true, nil, nil, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateWorker(_worker) - - if test.failure { - if err == nil { - t.Errorf("UpdateWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateWorker returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteWorker(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteWorker, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteWorker(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteWorker returned err: %v", err) - } - } -} - -// testWorker is a test helper function to create a -// library Worker type with all fields set to their -// zero values. -func testWorker() *library.Worker { - i64 := int64(0) - str := "" - arr := []string{} - b := false - - return &library.Worker{ - ID: &i64, - Hostname: &str, - Address: &str, - Routes: &arr, - Active: &b, - LastCheckedIn: &i64, - BuildLimit: &i64, - } -} diff --git a/database/service.go b/database/service.go index 649dc0056..2191ec1c6 100644 --- a/database/service.go +++ b/database/service.go @@ -8,6 +8,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" ) @@ -216,27 +217,7 @@ type Service interface { // related to users stored in the database. user.UserService - // Worker Database Interface Functions - - // GetWorker defines a function that - // gets a worker by hostname. - GetWorker(string) (*library.Worker, error) - // GetWorkerByAddress defines a function that - // gets a worker by address. - GetWorkerByAddress(string) (*library.Worker, error) - // GetWorkerList defines a function that - // gets a list of all workers. - GetWorkerList() ([]*library.Worker, error) - // GetWorkerCount defines a function that - // gets the count of workers. - GetWorkerCount() (int64, error) - // CreateWorker defines a function that - // creates a new worker. - CreateWorker(*library.Worker) error - // UpdateWorker defines a function that - // updates a worker by unique ID. - UpdateWorker(*library.Worker) error - // DeleteWorker defines a function that - // deletes a worker by hostname. - DeleteWorker(int64) error + // WorkerService provides the interface for functionality + // related to workers stored in the database. + worker.WorkerService } diff --git a/database/sqlite/ddl/worker.go b/database/sqlite/ddl/worker.go deleted file mode 100644 index 0e5ba8f4a..000000000 --- a/database/sqlite/ddl/worker.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateWorkerTable represents a query to - // create the workers table for Vela. - CreateWorkerTable = ` -CREATE TABLE -IF NOT EXISTS -workers ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - hostname TEXT, - address TEXT, - routes TEXT, - active TEXT, - last_checked_in INTEGER, - build_limit INTEGER, - UNIQUE(hostname) -); -` - - // CreateWorkerHostnameAddressIndex represents a query to create an - // index on the workers table for the hostname and address columns. - CreateWorkerHostnameAddressIndex = ` -CREATE INDEX -IF NOT EXISTS -workers_hostname_address -ON workers (hostname, address); -` -) diff --git a/database/sqlite/dml/worker.go b/database/sqlite/dml/worker.go deleted file mode 100644 index 64967c9b9..000000000 --- a/database/sqlite/dml/worker.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListWorkers represents a query to - // list all workers in the database. - ListWorkers = ` -SELECT * -FROM workers; -` - - // SelectWorkersCount represents a query to select the - // count of workers in the database. - SelectWorkersCount = ` -SELECT count(*) as count -FROM workers; -` - - // SelectWorker represents a query to select a - // worker in the database. - SelectWorker = ` -SELECT * -FROM workers -WHERE hostname = ? -LIMIT 1; -` - - // SelectWorkerByAddress represents a query to select a - // worker by address in the database. - SelectWorkerByAddress = ` -SELECT * -FROM workers -WHERE address = ? -LIMIT 1; -` - - // DeleteWorker represents a query to - // remove a worker from the database. - DeleteWorker = ` -DELETE -FROM workers -WHERE id = ?; -` -) diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 5ac28bd89..1c2afcd2d 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -12,6 +12,7 @@ import ( "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -49,6 +50,8 @@ type ( repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService + // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService + worker.WorkerService } ) @@ -260,12 +263,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) } - // create the workers table - err = c.Sqlite.Exec(ddl.CreateWorkerTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableWorker, err) - } - return nil } @@ -328,12 +325,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) } - // create the workers_hostname_address index for the workers table - err = c.Sqlite.Exec(ddl.CreateWorkerHostnameAddressIndex).Error - if err != nil { - return fmt.Errorf("unable to create workers_hostname_address index for the %s table: %w", constants.TableWorker, err) - } - return nil } @@ -380,5 +371,17 @@ func createServices(c *client) error { return err } + // create the database agnostic worker service + // + // https://pkg.go.dev/github.com/go-vela/server/database/worker#New + c.WorkerService, err = worker.New( + worker.WithClient(c.Sqlite), + worker.WithLogger(c.Logger), + worker.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + return nil } diff --git a/database/sqlite/worker.go b/database/sqlite/worker.go deleted file mode 100644 index 25ad1392b..000000000 --- a/database/sqlite/worker.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetWorker gets a worker by hostname from the database. -func (c *client) GetWorker(hostname string) (*library.Worker, error) { - c.Logger.WithFields(logrus.Fields{ - "worker": hostname, - }).Tracef("getting worker %s from the database", hostname) - - // variable to store query results - w := new(database.Worker) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableWorker). - Raw(dml.SelectWorker, hostname). - Scan(w) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return w.ToLibrary(), result.Error -} - -// GetWorker gets a worker by address from the database. -func (c *client) GetWorkerByAddress(address string) (*library.Worker, error) { - c.Logger.Tracef("getting worker by address %s from the database", address) - - // variable to store query results - w := new(database.Worker) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableWorker). - Raw(dml.SelectWorkerByAddress, address). - Scan(w) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return w.ToLibrary(), result.Error -} - -// CreateWorker creates a new worker in the database. -func (c *client) CreateWorker(w *library.Worker) error { - c.Logger.WithFields(logrus.Fields{ - "worker": w.GetHostname(), - }).Tracef("creating worker %s in the database", w.GetHostname()) - - // cast to database type - worker := database.WorkerFromLibrary(w) - - // validate the necessary fields are populated - err := worker.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableWorker). - Create(worker).Error -} - -// UpdateWorker updates a worker in the database. -func (c *client) UpdateWorker(w *library.Worker) error { - c.Logger.WithFields(logrus.Fields{ - "worker": w.GetHostname(), - }).Tracef("updating worker %s in the database", w.GetHostname()) - - // cast to database type - worker := database.WorkerFromLibrary(w) - - // validate the necessary fields are populated - err := worker.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableWorker). - Save(worker).Error -} - -// DeleteWorker deletes a worker by unique ID from the database. -func (c *client) DeleteWorker(id int64) error { - c.Logger.Tracef("deleting worker %d in the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableWorker). - Exec(dml.DeleteWorker, id).Error -} diff --git a/database/sqlite/worker_count_test.go b/database/sqlite/worker_count_test.go deleted file mode 100644 index dbbdcfc18..000000000 --- a/database/sqlite/worker_count_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the worker table - err = _database.Sqlite.Exec(ddl.CreateWorkerTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableWorker, err) - } -} - -func TestSqlite_Client_GetWorkerCount(t *testing.T) { - // setup types - _workerOne := testWorker() - _workerOne.SetID(1) - _workerOne.SetHostname("worker_0") - _workerOne.SetAddress("localhost") - _workerOne.SetActive(true) - - _workerTwo := testWorker() - _workerTwo.SetID(2) - _workerTwo.SetHostname("worker_1") - _workerTwo.SetAddress("localhost") - _workerTwo.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the workers table - defer _database.Sqlite.Exec("delete from workers;") - - // create the workers in the database - err := _database.CreateWorker(_workerOne) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - - err = _database.CreateWorker(_workerTwo) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - - got, err := _database.GetWorkerCount() - - if test.failure { - if err == nil { - t.Errorf("GetWorkerCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/worker_list_test.go b/database/sqlite/worker_list_test.go deleted file mode 100644 index 72916385e..000000000 --- a/database/sqlite/worker_list_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the worker table - err = _database.Sqlite.Exec(ddl.CreateWorkerTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableWorker, err) - } -} - -func TestSqlite_Client_GetWorkerList(t *testing.T) { - // setup types - _workerOne := testWorker() - _workerOne.SetID(1) - _workerOne.SetHostname("worker_0") - _workerOne.SetAddress("localhost") - _workerOne.SetActive(true) - - _workerTwo := testWorker() - _workerTwo.SetID(2) - _workerTwo.SetHostname("worker_1") - _workerTwo.SetAddress("localhost") - _workerTwo.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Worker - }{ - { - failure: false, - want: []*library.Worker{_workerOne, _workerTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the workers table - defer _database.Sqlite.Exec("delete from workers;") - - for _, worker := range test.want { - // create the worker in the database - err := _database.CreateWorker(worker) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - } - - got, err := _database.GetWorkerList() - - if test.failure { - if err == nil { - t.Errorf("GetWorkerList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/worker_test.go b/database/sqlite/worker_test.go deleted file mode 100644 index 50c6087db..000000000 --- a/database/sqlite/worker_test.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Worker - }{ - { - failure: false, - want: _worker, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the worker in the database - err := _database.CreateWorker(test.want) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - } - - got, err := _database.GetWorker("worker_0") - - // cleanup the workers table - _ = _database.Sqlite.Exec("DELETE FROM workers;") - - if test.failure { - if err == nil { - t.Errorf("GetWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorker returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorker is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetWorkerByAddress(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Worker - }{ - { - failure: false, - want: _worker, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the worker in the database - err := _database.CreateWorker(test.want) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - } - - got, err := _database.GetWorkerByAddress("localhost") - - // cleanup the workers table - _ = _database.Sqlite.Exec("DELETE FROM workers;") - - if test.failure { - if err == nil { - t.Errorf("GetWorkerByAddress should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetWorkerByAddress returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetWorkerByAddress is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the workers table - defer _database.Sqlite.Exec("delete from workers;") - - err := _database.CreateWorker(_worker) - - if test.failure { - if err == nil { - t.Errorf("CreateWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateWorker returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the workers table - defer _database.Sqlite.Exec("delete from workers;") - - // create the worker in the database - err := _database.CreateWorker(_worker) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - - err = _database.UpdateWorker(_worker) - - if test.failure { - if err == nil { - t.Errorf("UpdateWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateWorker returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteWorker(t *testing.T) { - // setup types - _worker := testWorker() - _worker.SetID(1) - _worker.SetHostname("worker_0") - _worker.SetAddress("localhost") - _worker.SetActive(true) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the workers table - defer _database.Sqlite.Exec("delete from workers;") - - // create the worker in the database - err := _database.CreateWorker(_worker) - if err != nil { - t.Errorf("unable to create test worker: %v", err) - } - - err = _database.DeleteWorker(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteWorker should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteWorker returned err: %v", err) - } - } -} - -// testWorker is a test helper function to create a -// library Worker type with all fields set to their -// zero values. -func testWorker() *library.Worker { - i64 := int64(0) - str := "" - b := false - - var arr []string - - return &library.Worker{ - ID: &i64, - Hostname: &str, - Address: &str, - Routes: &arr, - Active: &b, - LastCheckedIn: &i64, - BuildLimit: &i64, - } -} diff --git a/database/sqlite/worker_count.go b/database/worker/count.go similarity index 53% rename from database/sqlite/worker_count.go rename to database/worker/count.go index 38b2cf7b9..8ac0f3eb5 100644 --- a/database/sqlite/worker_count.go +++ b/database/worker/count.go @@ -2,25 +2,24 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package sqlite +package worker import ( - "github.com/go-vela/server/database/sqlite/dml" "github.com/go-vela/types/constants" ) -// GetWorkerCount gets a count of all workers from the database. -func (c *client) GetWorkerCount() (int64, error) { - c.Logger.Trace("getting count of workers from the database") +// CountWorkers gets the count of all workers from the database. +func (e *engine) CountWorkers() (int64, error) { + e.logger.Tracef("getting count of all workers from the database") // variable to store query results var w int64 // send query to the database and store result in variable - err := c.Sqlite. + err := e.client. Table(constants.TableWorker). - Raw(dml.SelectWorkersCount). - Pluck("count", &w).Error + Count(&w). + Error return w, err } diff --git a/database/worker/count_test.go b/database/worker/count_test.go new file mode 100644 index 000000000..bd9d4c4ac --- /dev/null +++ b/database/worker/count_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_CountWorkers(t *testing.T) { + // setup types + _workerOne := testWorker() + _workerOne.SetID(1) + _workerOne.SetHostname("worker_0") + _workerOne.SetAddress("localhost") + _workerOne.SetActive(true) + + _workerTwo := testWorker() + _workerTwo.SetID(2) + _workerTwo.SetHostname("worker_1") + _workerTwo.SetAddress("localhost") + _workerTwo.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "workers"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_workerOne) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + err = _sqlite.CreateWorker(_workerTwo) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountWorkers() + + if test.failure { + if err == nil { + t.Errorf("CountWorkers for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountWorkers for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountWorkers for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/worker/create.go b/database/worker/create.go new file mode 100644 index 000000000..6c62b30b6 --- /dev/null +++ b/database/worker/create.go @@ -0,0 +1,38 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateWorker creates a new worker in the database. +func (e *engine) CreateWorker(w *library.Worker) error { + e.logger.WithFields(logrus.Fields{ + "worker": w.GetHostname(), + }).Tracef("creating worker %s in the database", w.GetHostname()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary + worker := database.WorkerFromLibrary(w) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Worker.Validate + err := worker.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableWorker). + Create(worker). + Error +} diff --git a/database/worker/create_test.go b/database/worker/create_test.go new file mode 100644 index 000000000..38c276d83 --- /dev/null +++ b/database/worker/create_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_CreateWorker(t *testing.T) { + // setup types + _worker := testWorker() + _worker.SetID(1) + _worker.SetHostname("worker_0") + _worker.SetAddress("localhost") + _worker.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "workers" +("hostname","address","routes","active","last_checked_in","build_limit","id") +VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`). + WithArgs("worker_0", "localhost", nil, true, nil, nil, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateWorker(_worker) + + if test.failure { + if err == nil { + t.Errorf("CreateWorker for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateWorker for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/worker/delete.go b/database/worker/delete.go new file mode 100644 index 000000000..a04ebb13e --- /dev/null +++ b/database/worker/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteWorker deletes an existing worker from the database. +func (e *engine) DeleteWorker(w *library.Worker) error { + e.logger.WithFields(logrus.Fields{ + "worker": w.GetHostname(), + }).Tracef("deleting worker %s from the database", w.GetHostname()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary + worker := database.WorkerFromLibrary(w) + + // send query to the database + return e.client. + Table(constants.TableWorker). + Delete(worker). + Error +} diff --git a/database/worker/delete_test.go b/database/worker/delete_test.go new file mode 100644 index 000000000..c8a9bd1be --- /dev/null +++ b/database/worker/delete_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_DeleteWorker(t *testing.T) { + // setup types + _worker := testWorker() + _worker.SetID(1) + _worker.SetHostname("worker_0") + _worker.SetAddress("localhost") + _worker.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "workers" WHERE "workers"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_worker) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteWorker(_worker) + + if test.failure { + if err == nil { + t.Errorf("DeleteWorker for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteWorker for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/worker/get.go b/database/worker/get.go new file mode 100644 index 000000000..dd2b07ecc --- /dev/null +++ b/database/worker/get.go @@ -0,0 +1,34 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetWorker gets a worker by ID from the database. +func (e *engine) GetWorker(id int64) (*library.Worker, error) { + e.logger.Tracef("getting worker %d from the database", id) + + // variable to store query results + w := new(database.Worker) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableWorker). + Where("id = ?", id). + Take(w). + Error + if err != nil { + return nil, err + } + + // return the worker + // + // https://pkg.go.dev/github.com/go-vela/types/database#Worker.ToLibrary + return w.ToLibrary(), nil +} diff --git a/database/worker/get_hostname.go b/database/worker/get_hostname.go new file mode 100644 index 000000000..6bcf42a2b --- /dev/null +++ b/database/worker/get_hostname.go @@ -0,0 +1,37 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetWorkerForHostname gets a worker by hostname from the database. +func (e *engine) GetWorkerForHostname(hostname string) (*library.Worker, error) { + e.logger.WithFields(logrus.Fields{ + "worker": hostname, + }).Tracef("getting worker %s from the database", hostname) + + // variable to store query results + w := new(database.Worker) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableWorker). + Where("hostname = ?", hostname). + Take(w). + Error + if err != nil { + return nil, err + } + + // return the worker + // + // https://pkg.go.dev/github.com/go-vela/types/database#Worker.ToLibrary + return w.ToLibrary(), nil +} diff --git a/database/worker/get_hostname_test.go b/database/worker/get_hostname_test.go new file mode 100644 index 000000000..833afdc15 --- /dev/null +++ b/database/worker/get_hostname_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestWorker_Engine_GetWorkerForName(t *testing.T) { + // setup types + _worker := testWorker() + _worker.SetID(1) + _worker.SetHostname("worker_0") + _worker.SetAddress("localhost") + _worker.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}). + AddRow(1, "worker_0", "localhost", nil, true, 0, 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "workers" WHERE hostname = $1 LIMIT 1`).WithArgs("worker_0").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_worker) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Worker + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _worker, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _worker, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetWorkerForHostname("worker_0") + + if test.failure { + if err == nil { + t.Errorf("GetWorkerForHostname for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetWorkerForHostname for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetWorkerForHostname for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/worker/get_test.go b/database/worker/get_test.go new file mode 100644 index 000000000..17fd03739 --- /dev/null +++ b/database/worker/get_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestWorker_Engine_GetWorker(t *testing.T) { + // setup types + _worker := testWorker() + _worker.SetID(1) + _worker.SetHostname("worker_0") + _worker.SetAddress("localhost") + _worker.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}). + AddRow(1, "worker_0", "localhost", nil, true, 0, 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "workers" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_worker) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Worker + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _worker, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _worker, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetWorker(1) + + if test.failure { + if err == nil { + t.Errorf("GetWorker for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetWorker for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetWorker for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/worker/index.go b/database/worker/index.go new file mode 100644 index 000000000..f8f01a4b6 --- /dev/null +++ b/database/worker/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +const ( + // CreateHostnameAddressIndex represents a query to create an + // index on the workers table for the hostname and address columns. + CreateHostnameAddressIndex = ` +CREATE INDEX +IF NOT EXISTS +workers_hostname_address +ON workers (hostname, address); +` +) + +// CreateWorkerIndexes creates the indexes for the workers table in the database. +func (e *engine) CreateWorkerIndexes() error { + e.logger.Tracef("creating indexes for workers table in the database") + + // create the hostname and address columns index for the workers table + return e.client.Exec(CreateHostnameAddressIndex).Error +} diff --git a/database/worker/index_test.go b/database/worker/index_test.go new file mode 100644 index 000000000..ead204e5c --- /dev/null +++ b/database/worker/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_CreateWorkerIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateWorkerIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateWorkerIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateWorkerIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/sqlite/worker_list.go b/database/worker/list.go similarity index 51% rename from database/sqlite/worker_list.go rename to database/worker/list.go index e16d99071..4ec11ef3d 100644 --- a/database/sqlite/worker_list.go +++ b/database/worker/list.go @@ -2,38 +2,53 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package sqlite +package worker import ( - "github.com/go-vela/server/database/sqlite/dml" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) -// GetWorkerList gets a list of all workers from the database. -func (c *client) GetWorkerList() ([]*library.Worker, error) { - c.Logger.Trace("listing workers from the database") +// ListWorkers gets a list of all workers from the database. +func (e *engine) ListWorkers() ([]*library.Worker, error) { + e.logger.Trace("listing all workers from the database") - // variable to store query results + // variables to store query results and return value + count := int64(0) w := new([]database.Worker) + workers := []*library.Worker{} + + // count the results + count, err := e.CountWorkers() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return workers, nil + } // send query to the database and store result in variable - err := c.Sqlite. + err = e.client. Table(constants.TableWorker). - Raw(dml.ListWorkers). - Scan(w).Error + Find(&w). + Error + if err != nil { + return nil, err + } - // variable we want to return - workers := []*library.Worker{} // iterate through all query results for _, worker := range *w { // https://golang.org/doc/faq#closures_and_goroutines tmp := worker // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Worker.ToLibrary workers = append(workers, tmp.ToLibrary()) } - return workers, err + return workers, nil } diff --git a/database/worker/list_test.go b/database/worker/list_test.go new file mode 100644 index 000000000..b44c9c3d9 --- /dev/null +++ b/database/worker/list_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestWorker_Engine_ListWorkers(t *testing.T) { + // setup types + _workerOne := testWorker() + _workerOne.SetID(1) + _workerOne.SetHostname("worker_0") + _workerOne.SetAddress("localhost") + _workerOne.SetActive(true) + + _workerTwo := testWorker() + _workerTwo.SetID(2) + _workerTwo.SetHostname("worker_1") + _workerTwo.SetAddress("localhost") + _workerTwo.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "workers"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}). + AddRow(1, "worker_0", "localhost", nil, true, 0, 0). + AddRow(2, "worker_1", "localhost", nil, true, 0, 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "workers"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_workerOne) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + err = _sqlite.CreateWorker(_workerTwo) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Worker + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Worker{_workerOne, _workerTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Worker{_workerOne, _workerTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListWorkers() + + if test.failure { + if err == nil { + t.Errorf("ListWorkers for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListWorkers for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListWorkers for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/worker/opts.go b/database/worker/opts.go new file mode 100644 index 000000000..c9891ba94 --- /dev/null +++ b/database/worker/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Workers. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Workers. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the worker engine + e.client = client + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Workers. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the worker engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Workers. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the worker engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/worker/opts_test.go b/database/worker/opts_test.go new file mode 100644 index 000000000..a0ebf6aa5 --- /dev/null +++ b/database/worker/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestWorker_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestWorker_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestWorker_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/worker/service.go b/database/worker/service.go new file mode 100644 index 000000000..b02c6f854 --- /dev/null +++ b/database/worker/service.go @@ -0,0 +1,43 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/library" +) + +// WorkerService represents the Vela interface for worker +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type WorkerService interface { + // Worker Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateWorkerIndexes defines a function that creates the indexes for the workers table. + CreateWorkerIndexes() error + // CreateWorkerTable defines a function that creates the workers table. + CreateWorkerTable(string) error + + // Worker Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountWorkers defines a function that gets the count of all workers. + CountWorkers() (int64, error) + // CreateWorker defines a function that creates a new worker. + CreateWorker(*library.Worker) error + // DeleteWorker defines a function that deletes an existing worker. + DeleteWorker(*library.Worker) error + // GetWorker defines a function that gets a worker by ID. + GetWorker(int64) (*library.Worker, error) + // GetWorkerForHostname defines a function that gets a worker by hostname. + GetWorkerForHostname(string) (*library.Worker, error) + // ListWorkers defines a function that gets a list of all workers. + ListWorkers() ([]*library.Worker, error) + // UpdateWorker defines a function that updates an existing worker. + UpdateWorker(*library.Worker) error +} diff --git a/database/worker/table.go b/database/worker/table.go new file mode 100644 index 000000000..5cecf109d --- /dev/null +++ b/database/worker/table.go @@ -0,0 +1,60 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres workers table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +workers ( + id SERIAL PRIMARY KEY, + hostname VARCHAR(250), + address VARCHAR(250), + routes VARCHAR(1000), + active BOOLEAN, + last_checked_in INTEGER, + build_limit INTEGER, + UNIQUE(hostname) +); +` + + // CreateSqliteTable represents a query to create the Sqlite workers table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +workers ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + hostname TEXT, + address TEXT, + routes TEXT, + active BOOLEAN, + last_checked_in INTEGER, + build_limit INTEGER, + UNIQUE(hostname) +); +` +) + +// CreateWorkerTable creates the workers table in the database. +func (e *engine) CreateWorkerTable(driver string) error { + e.logger.Tracef("creating workers table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the workers table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the workers table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/worker/table_test.go b/database/worker/table_test.go new file mode 100644 index 000000000..681a267f2 --- /dev/null +++ b/database/worker/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_CreateWorkerTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateWorkerTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateWorkerTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateWorkerTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/worker/update.go b/database/worker/update.go new file mode 100644 index 000000000..b0e475273 --- /dev/null +++ b/database/worker/update.go @@ -0,0 +1,38 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateWorker updates an existing worker in the database. +func (e *engine) UpdateWorker(w *library.Worker) error { + e.logger.WithFields(logrus.Fields{ + "worker": w.GetHostname(), + }).Tracef("updating worker %s in the database", w.GetHostname()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary + worker := database.WorkerFromLibrary(w) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Worker.Validate + err := worker.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableWorker). + Save(worker). + Error +} diff --git a/database/worker/update_test.go b/database/worker/update_test.go new file mode 100644 index 000000000..88644678a --- /dev/null +++ b/database/worker/update_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestWorker_Engine_UpdateWorker(t *testing.T) { + // setup types + _worker := testWorker() + _worker.SetID(1) + _worker.SetHostname("worker_0") + _worker.SetAddress("localhost") + _worker.SetActive(true) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "workers" +SET "hostname"=$1,"address"=$2,"routes"=$3,"active"=$4,"last_checked_in"=$5,"build_limit"=$6 +WHERE "id" = $7`). + WithArgs("worker_0", "localhost", nil, true, nil, nil, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateWorker(_worker) + if err != nil { + t.Errorf("unable to create test worker for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateWorker(_worker) + + if test.failure { + if err == nil { + t.Errorf("UpdateWorker for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateWorker for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/worker/worker.go b/database/worker/worker.go new file mode 100644 index 000000000..d870fb1ba --- /dev/null +++ b/database/worker/worker.go @@ -0,0 +1,80 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the WorkerService interface. + config struct { + // specifies to skip creating tables and indexes for the Worker engine + SkipCreation bool + } + + // engine represents the worker functionality that implements the WorkerService interface. + engine struct { + // engine configuration settings used in worker functions + config *config + + // gorm.io/gorm database client used in worker functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in worker functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with workers in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Worker engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating worker database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of workers table and indexes in the database") + + return e, nil + } + + // create the workers table + err := e.CreateWorkerTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableWorker, err) + } + + // create the indexes for the workers table + err = e.CreateWorkerIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableWorker, err) + } + + return e, nil +} diff --git a/database/worker/worker_test.go b/database/worker/worker_test.go new file mode 100644 index 000000000..48deabe54 --- /dev/null +++ b/database/worker/worker_test.go @@ -0,0 +1,181 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestWorker_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres worker engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite worker engine: %v", err) + } + + return _engine +} + +// testWorker is a test helper function to create a library +// Worker type with all fields set to their zero values. +func testWorker() *library.Worker { + return &library.Worker{ + ID: new(int64), + Hostname: new(string), + Address: new(string), + Routes: new([]string), + Active: new(bool), + BuildLimit: new(int64), + LastCheckedIn: new(int64), + } +} diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index acd115537..96155eacb 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -30,7 +30,7 @@ func Establish() gin.HandlerFunc { e := new([]library.Executor) b := build.Retrieve(c) // retrieve the worker - w, err := database.FromContext(c).GetWorker(b.GetHost()) + w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) if err != nil { retErr := fmt.Errorf("unable to get worker: %w", err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/router/middleware/worker/worker.go b/router/middleware/worker/worker.go index 2f68b811f..5afc8b3bf 100644 --- a/router/middleware/worker/worker.go +++ b/router/middleware/worker/worker.go @@ -33,7 +33,7 @@ func Establish() gin.HandlerFunc { logrus.Debugf("Reading worker %s", wParam) - w, err := database.FromContext(c).GetWorker(wParam) + w, err := database.FromContext(c).GetWorkerForHostname(wParam) if err != nil { retErr := fmt.Errorf("unable to read worker %s: %w", wParam, err) util.HandleError(c, http.StatusNotFound, retErr) From 754141ce5633d37ed9862512f4b37f07fa5faec8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 14:55:20 -0600 Subject: [PATCH 139/298] fix(deps): update module github.com/masterminds/semver/v3 to v3.2.0 (#737) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4dfcb928a..432de3767 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/Masterminds/semver/v3 v3.1.1 + github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/sprig/v3 v3.2.2 github.com/alicebob/miniredis/v2 v2.23.1 github.com/aws/aws-sdk-go v1.44.133 diff --git a/go.sum b/go.sum index 993ccfd7c..f07e5f591 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,9 @@ github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYI github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= From cdbba9c66389982b38c0e6a0d13dd1437bcd8019 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:09:12 -0600 Subject: [PATCH 140/298] fix(deps): update deps (patch) (#738) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 20 ++++++++++---------- go.sum | 40 +++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 432de3767..28ae25926 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,16 @@ require ( github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.0 - github.com/Masterminds/sprig/v3 v3.2.2 + github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.23.1 - github.com/aws/aws-sdk-go v1.44.133 + github.com/aws/aws-sdk-go v1.44.157 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.16.2 - github.com/golang-jwt/jwt/v4 v4.4.2 + github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 github.com/google/uuid v1.3.0 @@ -28,15 +28,15 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 - github.com/spf13/afero v1.9.2 - github.com/urfave/cli/v2 v2.23.5 + github.com/spf13/afero v1.9.3 + github.com/urfave/cli/v2 v2.23.6 go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.4.5 gorm.io/driver/sqlite v1.4.3 - gorm.io/gorm v1.24.1 + gorm.io/gorm v1.24.2 k8s.io/apimachinery v0.25.3 ) @@ -83,7 +83,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/vault/sdk v0.6.0 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect - github.com/huandu/xstrings v1.3.2 // indirect + github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.13.0 // indirect @@ -125,9 +125,9 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect + golang.org/x/crypto v0.3.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index f07e5f591..cdedec7a6 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy86 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -73,8 +73,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.133 h1:+pWxt9nyKc0jf33rORBaQ93KPjYpmIIy3ozVXdJ82Oo= -github.com/aws/aws-sdk-go v1.44.133/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.157 h1:JVBPpEWC8+yA7CbfAuTl/ZFFlHS3yoqWFqxFyTCISwg= +github.com/aws/aws-sdk-go v1.44.157/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -170,8 +170,8 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= -github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -301,9 +301,8 @@ github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZT github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= @@ -520,8 +519,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -542,8 +541,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw= -github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.23.6 h1:iWmtKD+prGo1nKUtLO0Wg4z9esfBM4rAV4QRLQiEmJ4= +github.com/urfave/cli/v2 v2.23.6/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -585,7 +584,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -593,8 +591,9 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -668,8 +667,9 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -752,13 +752,15 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -966,8 +968,8 @@ gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs= -gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0= +gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From bcbdbe1ac8f016d89fb8496c764ac49383f14d11 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 9 Dec 2022 21:13:35 +0000 Subject: [PATCH 141/298] chore: remove code of conduct in favor of global version (#736) --- .github/CODE_OF_CONDUCT.md | 74 -------------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 .github/CODE_OF_CONDUCT.md diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 11345c24d..000000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,74 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to make participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at -[TTS-OpenSource-Office@target.com](mailto:TTS-OpenSource-Office@target.com). All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org From 8f3d712c9b6660b74684d0276674c33e6eda752e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:17:06 -0600 Subject: [PATCH 142/298] chore(deps): update elgohr/publish-docker-github-action action to v5 (#739) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- .github/workflows/prerelease.yml | 4 ++-- .github/workflows/publish.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 24f8083f5..02f90d774 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -40,7 +40,7 @@ jobs: make build-static-ci - name: publish - uses: elgohr/Publish-Docker-Github-Action@v4 + uses: elgohr/Publish-Docker-Github-Action@v5 with: name: target/vela-server cache: true @@ -49,7 +49,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: publish-alpine - uses: elgohr/Publish-Docker-Github-Action@v4 + uses: elgohr/Publish-Docker-Github-Action@v5 with: name: target/vela-server cache: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b5324314e..a8ce50154 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,7 +34,7 @@ jobs: make build-static-ci - name: publish - uses: elgohr/Publish-Docker-Github-Action@v4 + uses: elgohr/Publish-Docker-Github-Action@v5 with: name: target/vela-server cache: true @@ -42,7 +42,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: publish-alpine - uses: elgohr/Publish-Docker-Github-Action@v4 + uses: elgohr/Publish-Docker-Github-Action@v5 with: name: target/vela-server cache: true From a7fa4cf9763e1d0d3f094cb382776b6ccc69e8de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:23:29 -0600 Subject: [PATCH 143/298] fix(deps): update module golang.org/x/oauth2 to v0.3.0 (#740) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 28ae25926..fddb8e75e 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.9.3 github.com/urfave/cli/v2 v2.23.6 go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 - golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 + golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.4.5 @@ -126,9 +126,9 @@ require ( github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.3.0 // indirect - golang.org/x/net v0.2.0 // indirect - golang.org/x/sys v0.2.0 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/net v0.3.0 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect diff --git a/go.sum b/go.sum index cdedec7a6..638e9dc78 100644 --- a/go.sum +++ b/go.sum @@ -668,8 +668,9 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -681,8 +682,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -753,8 +754,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -769,8 +771,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 7638451f96a73602f95e96636b95e4335ad25d1c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:31:27 -0600 Subject: [PATCH 144/298] fix(deps): update go.starlark.net digest to 3fd0dac (#741) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fddb8e75e..222bf8c24 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.3 github.com/urfave/cli/v2 v2.23.6 - go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 + go.starlark.net v0.0.0-20221205180719-3fd0dac74452 golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 638e9dc78..19ece10c4 100644 --- a/go.sum +++ b/go.sum @@ -562,8 +562,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20221028183056-acb66ad56dd2 h1:5/KzhcSqd4UgY51l17r7C5g/JiE6DRw1Vq7VJfQHuMc= -go.starlark.net v0.0.0-20221028183056-acb66ad56dd2/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= +go.starlark.net v0.0.0-20221205180719-3fd0dac74452 h1:JZtNuL6LPB+scU5yaQ6hqRlJFRiddZm2FwRt2AQqtHA= +go.starlark.net v0.0.0-20221205180719-3fd0dac74452/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From cd67f9a94ae415511abfc5c05438422759175f42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 15:37:39 -0600 Subject: [PATCH 145/298] fix(deps): update module k8s.io/apimachinery to v0.26.0 (#742) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 222bf8c24..244b19e50 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( gorm.io/driver/postgres v1.4.5 gorm.io/driver/sqlite v1.4.3 gorm.io/gorm v1.24.2 - k8s.io/apimachinery v0.25.3 + k8s.io/apimachinery v0.26.0 ) require ( @@ -126,7 +126,7 @@ require ( github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.3.0 // indirect - golang.org/x/net v0.3.0 // indirect + golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect @@ -135,5 +135,5 @@ require ( google.golang.org/grpc v1.41.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.70.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect ) diff --git a/go.sum b/go.sum index 19ece10c4..dc090f793 100644 --- a/go.sum +++ b/go.sum @@ -451,7 +451,7 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= @@ -669,8 +669,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= +golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -980,11 +980,11 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc= -k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= -k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= -k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg= +k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= From 9aa91f709cc318f5896ee90c558b4000caf81fcb Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 13 Dec 2022 12:17:24 -0700 Subject: [PATCH 146/298] feat(templates): support same-repo templates using build commit (#713) * feat(templates): support same-repo templates using build commit * rename to file and add t.run Co-authored-by: Easton Crupper Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- compiler/native/expand.go | 34 +++++++++++++++ compiler/native/expand_test.go | 76 +++++++++++++++++++++++++--------- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/compiler/native/expand.go b/compiler/native/expand.go index c4395d6dc..e17d03161 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -10,6 +10,7 @@ import ( "github.com/go-vela/types/constants" + "github.com/go-vela/server/compiler/registry" "github.com/go-vela/server/compiler/template/native" "github.com/go-vela/server/compiler/template/starlark" "github.com/spf13/afero" @@ -212,6 +213,39 @@ func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) { } } + case strings.EqualFold(tmpl.Type, "file"): + src := ®istry.Source{ + Org: c.repo.GetOrg(), + Repo: c.repo.GetName(), + Name: tmpl.Source, + Ref: c.build.GetCommit(), + } + + if !c.UsePrivateGithub { + logrus.WithFields(logrus.Fields{ + "org": src.Org, + "repo": src.Repo, + "path": src.Name, + }).Tracef("Using GitHub client to pull template") + + bytes, err = c.Github.Template(nil, src) + if err != nil { + return bytes, err + } + } else { + logrus.WithFields(logrus.Fields{ + "org": src.Org, + "repo": src.Repo, + "path": src.Name, + }).Tracef("Using authenticated GitHub client to pull template") + + // use private (authenticated) github instance to pull from + bytes, err = c.PrivateGithub.Template(c.user, src) + if err != nil { + return bytes, err + } + } + default: return bytes, fmt.Errorf("unsupported template type: %v", tmpl.Type) } diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index d4f9f8d7c..ae3fc32b7 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -11,6 +11,7 @@ import ( "reflect" "testing" + "github.com/go-vela/types/library" "github.com/go-vela/types/raw" "github.com/go-vela/types/yaml" "github.com/google/go-cmp/cmp" @@ -190,11 +191,40 @@ func TestNative_ExpandSteps(t *testing.T) { set.String("github-token", "", "doc") c := cli.NewContext(nil, set, nil) - tmpls := map[string]*yaml.Template{ - "gradle": { - Name: "gradle", - Source: "github.example.com/foo/bar/template.yml", - Type: "github", + testBuild := new(library.Build) + + testBuild.SetID(1) + testBuild.SetCommit("123abc456def") + + testRepo := new(library.Repo) + + testRepo.SetID(1) + testRepo.SetOrg("foo") + testRepo.SetName("bar") + + tests := []struct { + name string + tmpls map[string]*yaml.Template + }{ + { + name: "GitHub", + tmpls: map[string]*yaml.Template{ + "gradle": { + Name: "gradle", + Source: "github.example.com/foo/bar/template.yml", + Type: "github", + }, + }, + }, + { + name: "File", + tmpls: map[string]*yaml.Template{ + "gradle": { + Name: "gradle", + Source: "template.yml", + Type: "file", + }, + }, }, } @@ -287,25 +317,31 @@ func TestNative_ExpandSteps(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, tmpls) - if err != nil { - t.Errorf("ExpandSteps returned err: %v", err) - } + compiler.WithBuild(testBuild).WithRepo(testRepo) - if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { - t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) - } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls) + if err != nil { + t.Errorf("ExpandSteps_Type%s returned err: %v", test.name, err) + } - if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { - t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) - } + if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } - if diff := cmp.Diff(build.Services, wantServices); diff != "" { - t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) - } + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } - if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { - t.Errorf("ExpandSteps() mismatch (-want +got):\n%s", diff) + if diff := cmp.Diff(build.Services, wantServices); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + }) } } From 09e827e62f88a91a0a70a42cc74bbe28c27abc6f Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 13 Dec 2022 13:44:11 -0700 Subject: [PATCH 147/298] enhance(scm/webhook): handle default branch change and archived repo (#706) * enhance(scm/webhook): handle default branch change and archived repo * more description for what happened in response body Co-authored-by: Jordan Brockopp Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/webhook.go | 72 +++++++-- docker-compose.yml | 1 + .../testdata/hooks/repository_archived.json | 133 +++++++++++++++++ .../testdata/hooks/repository_edited.json | 138 ++++++++++++++++++ scm/github/webhook.go | 1 + scm/github/webhook_test.go | 128 ++++++++++++++++ 6 files changed, 461 insertions(+), 12 deletions(-) create mode 100644 scm/github/testdata/hooks/repository_archived.json create mode 100644 scm/github/testdata/hooks/repository_edited.json diff --git a/api/webhook.go b/api/webhook.go index 1df0171a2..adc220fd4 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -145,9 +145,7 @@ func PostWebhook(c *gin.Context) { // check if build was parsed from webhook. // build will be nil on repository events, but // for renaming, we want to continue. - if b == nil && - h.GetEvent() != constants.EventRepository && - h.GetEventAction() != constants.ActionRenamed { + if b == nil && h.GetEvent() != constants.EventRepository { // typically, this should only happen on a webhook // "ping" which gets sent when the webhook is created c.JSON(http.StatusOK, "no build to process") @@ -172,14 +170,66 @@ func PostWebhook(c *gin.Context) { }() if h.GetEvent() == constants.EventRepository { - err = renameRepository(h, r, c, m) - if err != nil { - util.HandleError(c, http.StatusBadRequest, err) - h.SetStatus(constants.StatusFailure) - h.SetError(err.Error()) - } + switch h.GetEventAction() { + // if action is rename, go through rename routine + case constants.ActionRenamed: + err = renameRepository(h, r, c, m) + if err != nil { + util.HandleError(c, http.StatusBadRequest, err) + h.SetStatus(constants.StatusFailure) + h.SetError(err.Error()) + } - return + c.JSON(http.StatusOK, fmt.Sprintf("no build to process, repository renamed from %s to %s", r.GetPreviousName(), r.GetFullName())) + + return + // if action is archived, unarchived, or edited, perform edits to relevant repo fields + case "archived", "unarchived", constants.ActionEdited: + // send call to get repository from database + dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + if err != nil { + retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusBadRequest, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + + var retMsg string + // the only edits to a repo that impact Vela are to these two fields + if !strings.EqualFold(dbRepo.GetBranch(), r.GetBranch()) { + retMsg = fmt.Sprintf("no build to process, repository default branch changed from %s to %s", dbRepo.GetBranch(), r.GetBranch()) + dbRepo.SetBranch(r.GetBranch()) + } + + if dbRepo.GetActive() != r.GetActive() { + retMsg = fmt.Sprintf("no build to process, repository changed active status from %t to %t", dbRepo.GetActive(), r.GetActive()) + dbRepo.SetActive(r.GetActive()) + } + + // update repo object in the database after applying edits + err = database.FromContext(c).UpdateRepo(dbRepo) + if err != nil { + retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + + c.JSON(http.StatusOK, retMsg) + + return + // all other repo event actions are skippable + default: + c.JSON(http.StatusOK, "no build to process") + + return + } } // send API call to capture parsed repo from webhook @@ -865,7 +915,5 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types } } - c.JSON(http.StatusOK, r) - return nil } diff --git a/docker-compose.yml b/docker-compose.yml index 7e441fb9f..c3b9501c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,6 +41,7 @@ services: VELA_ACCESS_TOKEN_DURATION: 60m VELA_DISABLE_WEBHOOK_VALIDATION: 'true' VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_REPO_ALLOWLIST: '*' env_file: - .env restart: always diff --git a/scm/github/testdata/hooks/repository_archived.json b/scm/github/testdata/hooks/repository_archived.json new file mode 100644 index 000000000..b9c0ff71b --- /dev/null +++ b/scm/github/testdata/hooks/repository_archived.json @@ -0,0 +1,133 @@ +{ + "action": "archived", + "repository": { + "id": 118, + "node_id": "MDEwOlJlcG9zaXRvcnkxMTg=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://octocoders.github.io/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World", + "forks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/forks", + "keys_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/events", + "assignees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/merges", + "archive_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T19:37:07Z", + "updated_at": "2019-05-15T19:38:25Z", + "pushed_at": "2019-05-15T19:38:23Z", + "git_url": "git://octocoders.github.io/Codertocat/Hello-World.git", + "ssh_url": "git@octocoders.github.io:Codertocat/Hello-World.git", + "clone_url": "https://octocoders.github.io/Codertocat/Hello-World.git", + "svn_url": "https://octocoders.github.io/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Ruby", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": true, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "master" + }, + "enterprise": { + "id": 1, + "slug": "github", + "name": "GitHub", + "node_id": "MDg6QnVzaW5lc3Mx", + "avatar_url": "https://octocoders.github.io/avatars/b/1?", + "description": null, + "website_url": null, + "html_url": "https://octocoders.github.io/businesses/github", + "created_at": "2019-05-14T19:31:12Z", + "updated_at": "2019-05-14T19:31:12Z" + }, + "sender": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 5, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uNQ==" + } +} \ No newline at end of file diff --git a/scm/github/testdata/hooks/repository_edited.json b/scm/github/testdata/hooks/repository_edited.json new file mode 100644 index 000000000..cb923aeaf --- /dev/null +++ b/scm/github/testdata/hooks/repository_edited.json @@ -0,0 +1,138 @@ +{ + "action": "edited", + "changes": { + "default_branch": { + "from": "not-main" + } + }, + "repository": { + "id": 118, + "node_id": "MDEwOlJlcG9zaXRvcnkxMTg=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://octocoders.github.io/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World", + "forks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/forks", + "keys_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/events", + "assignees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/merges", + "archive_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T19:37:07Z", + "updated_at": "2019-05-15T19:38:25Z", + "pushed_at": "2019-05-15T19:38:23Z", + "git_url": "git://octocoders.github.io/Codertocat/Hello-World.git", + "ssh_url": "git@octocoders.github.io:Codertocat/Hello-World.git", + "clone_url": "https://octocoders.github.io/Codertocat/Hello-World.git", + "svn_url": "https://octocoders.github.io/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Ruby", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "main" + }, + "enterprise": { + "id": 1, + "slug": "github", + "name": "GitHub", + "node_id": "MDg6QnVzaW5lc3Mx", + "avatar_url": "https://octocoders.github.io/avatars/b/1?", + "description": null, + "website_url": null, + "html_url": "https://octocoders.github.io/businesses/github", + "created_at": "2019-05-14T19:31:12Z", + "updated_at": "2019-05-14T19:31:12Z" + }, + "sender": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 5, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uNQ==" + } +} \ No newline at end of file diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 257483d43..2bf7c7b8b 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -450,6 +450,7 @@ func (c *client) processRepositoryEvent(h *library.Hook, payload *github.Reposit r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) + r.SetActive(!repo.GetArchived()) // if action is renamed, then get the previous name from payload if payload.GetAction() == "renamed" { diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 9d902d6ff..437299070 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -967,6 +967,7 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") wantRepo := new(library.Repo) + wantRepo.SetActive(true) wantRepo.SetOrg("Codertocat") wantRepo.SetName("Hello-World") wantRepo.SetFullName("Codertocat/Hello-World") @@ -993,6 +994,132 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { } } +func TestGitHub_ProcessWebhook_RepositoryArchived(t *testing.T) { + // setup router + s := httptest.NewServer(http.NotFoundHandler()) + defer s.Close() + + // setup request + body, err := os.Open("testdata/hooks/repository_archived.json") + if err != nil { + t.Errorf("unable to open file: %v", err) + } + + defer body.Close() + + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) + request.Header.Set("Content-Type", "application/json") + request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") + request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") + request.Header.Set("X-GitHub-Event", "repository") + + // setup client + client, _ := NewTest(s.URL) + + // run test + wantHook := new(library.Hook) + wantHook.SetNumber(1) + wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) + wantHook.SetCreated(time.Now().UTC().Unix()) + wantHook.SetHost("github.com") + wantHook.SetEvent(constants.EventRepository) + wantHook.SetEventAction("archived") + wantHook.SetBranch("master") + wantHook.SetStatus(constants.StatusSuccess) + wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") + + wantRepo := new(library.Repo) + wantRepo.SetActive(false) + wantRepo.SetOrg("Codertocat") + wantRepo.SetName("Hello-World") + wantRepo.SetFullName("Codertocat/Hello-World") + wantRepo.SetLink("https://octocoders.github.io/Codertocat/Hello-World") + wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") + wantRepo.SetBranch("master") + wantRepo.SetPrivate(false) + + want := &types.Webhook{ + Comment: "", + Hook: wantHook, + Repo: wantRepo, + } + + got, err := client.ProcessWebhook(request) + + if err != nil { + t.Errorf("ProcessWebhook returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("ProcessWebhook is %v, want %v", got, want) + } +} + +func TestGitHub_ProcessWebhook_RepositoryEdited(t *testing.T) { + // setup router + s := httptest.NewServer(http.NotFoundHandler()) + defer s.Close() + + // setup request + body, err := os.Open("testdata/hooks/repository_edited.json") + if err != nil { + t.Errorf("unable to open file: %v", err) + } + + defer body.Close() + + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) + request.Header.Set("Content-Type", "application/json") + request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") + request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") + request.Header.Set("X-GitHub-Event", "repository") + + // setup client + client, _ := NewTest(s.URL) + + // run test + wantHook := new(library.Hook) + wantHook.SetNumber(1) + wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) + wantHook.SetCreated(time.Now().UTC().Unix()) + wantHook.SetHost("github.com") + wantHook.SetEvent(constants.EventRepository) + wantHook.SetEventAction(constants.ActionEdited) + wantHook.SetBranch("main") + wantHook.SetStatus(constants.StatusSuccess) + wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") + + wantRepo := new(library.Repo) + wantRepo.SetActive(true) + wantRepo.SetOrg("Codertocat") + wantRepo.SetName("Hello-World") + wantRepo.SetFullName("Codertocat/Hello-World") + wantRepo.SetLink("https://octocoders.github.io/Codertocat/Hello-World") + wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") + wantRepo.SetBranch("main") + wantRepo.SetPrivate(false) + + want := &types.Webhook{ + Comment: "", + Hook: wantHook, + Repo: wantRepo, + } + + got, err := client.ProcessWebhook(request) + + if err != nil { + t.Errorf("ProcessWebhook returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("ProcessWebhook is %v, want %v", got, want) + } +} + func TestGitHub_ProcessWebhook_Repository(t *testing.T) { // setup router s := httptest.NewServer(http.NotFoundHandler()) @@ -1030,6 +1157,7 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") wantRepo := new(library.Repo) + wantRepo.SetActive(true) wantRepo.SetOrg("Codertocat") wantRepo.SetName("Hello-World") wantRepo.SetFullName("Codertocat/Hello-World") From 6253d20df022656a92e0ae2e14902bc1e7fac539 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 14 Dec 2022 10:41:14 -0700 Subject: [PATCH 148/298] feat(api/build): add endpoint to get build by id (#646) * feat(api/build): add endpoint to get build by id * separating platform admin check into admin router group * fixing api spec * fix some comments * linter went crazy for some reason * so many linter errors * pluralize path and fix some linter stuff * add back accidentally deleted tests * change perm requirement from write to read for repo * fix perm level check * chore(release): v0.16.2 prep * appease linter overlord * fix router grouping to avoid conflicts * update comments and change admin func to GetBuildByID * remove admin endpoint in favor of admin check in normal endpoint Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: Jordan Brockopp Co-authored-by: Kelly Merrick --- api/build.go | 102 +++++++++++++++++++++++++++++++- compiler/context_test.go | 6 +- database/postgres/build.go | 25 ++++++++ database/postgres/build_test.go | 68 +++++++++++++++++++++ database/postgres/dml/build.go | 9 +++ database/postgres/hook.go | 2 + database/service.go | 3 + database/sqlite/build.go | 25 ++++++++ database/sqlite/build_test.go | 64 ++++++++++++++++++++ database/sqlite/dml/build.go | 9 +++ database/sqlite/hook.go | 2 + router/admin.go | 27 ++++----- router/router.go | 3 + router/search.go | 26 ++++++++ scm/github/github_test.go | 4 +- 15 files changed, 352 insertions(+), 23 deletions(-) create mode 100644 router/search.go diff --git a/api/build.go b/api/build.go index 4e35b7d33..c31c5d5c2 100644 --- a/api/build.go +++ b/api/build.go @@ -411,6 +411,105 @@ func skipEmptyBuild(p *pipeline.Build) string { return "" } +// swagger:operation GET /api/v1/search/builds/{id} builds GetBuildByID +// +// Get a single build by its id in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: id +// description: build id +// required: true +// type: number +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved build +// schema: +// "$ref": "#/definitions/Build" +// '400': +// description: Unable to retrieve the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the build +// schema: +// "$ref": "#/definitions/Error" + +// 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 *library.Repo + ) + + // Capture user from middleware + u := user.Retrieve(c) + + // Parse build ID from path + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + + if err != nil { + retErr := fmt.Errorf("unable to parse build id: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": id, + "user": u.GetName(), + }).Infof("reading build %d", id) + + // Get build from database + b, err = database.FromContext(c).GetBuildByID(id) + if err != nil { + retErr := fmt.Errorf("unable to get build: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // Get repo from database using repo ID field from build + r, err = database.FromContext(c).GetRepo(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(u, u.GetToken(), r.GetOrg(), r.GetName()) + if err != nil { + logrus.Errorf("unable to get user %s access level for repo %s", u.GetName(), r.GetFullName()) + } + + // Ensure that user has at least read access to repo to return the build + if perm == "none" && !u.GetAdmin() { + retErr := fmt.Errorf("unable to retrieve build %d: user does not have read access to repo %s", id, r.GetFullName()) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + c.JSON(http.StatusOK, b) +} + // swagger:operation GET /api/v1/repos/{org}/{repo}/builds builds GetBuilds // // Get builds from the configured backend @@ -793,8 +892,7 @@ func GetOrgBuilds(c *gin.Context) { logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) } // Only show public repos to non-admins - // - //nolint:goconst // ignore admin constant + //nolint:goconst // ignore need for constant if perm != "admin" { filters["visibility"] = constants.VisibilityPublic } diff --git a/compiler/context_test.go b/compiler/context_test.go index 20ef576a2..e5b340de6 100644 --- a/compiler/context_test.go +++ b/compiler/context_test.go @@ -22,7 +22,7 @@ func TestCompiler_FromContext(t *testing.T) { want Engine }{ { - //nolint: staticcheck, revive // ignore using string with context value + //nolint:staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, _engine), want: _engine, }, @@ -31,7 +31,7 @@ func TestCompiler_FromContext(t *testing.T) { want: nil, }, { - //nolint: staticcheck, revive // ignore using string with context value + //nolint:staticcheck, revive // ignore using string with context value context: context.WithValue(context.Background(), key, "foo"), want: nil, }, @@ -92,7 +92,7 @@ func TestCompiler_WithContext(t *testing.T) { // setup types var _engine Engine - //nolint: staticcheck, revive // ignore using string with context value + //nolint:staticcheck, revive // ignore using string with context value want := context.WithValue(context.Background(), key, _engine) // run test diff --git a/database/postgres/build.go b/database/postgres/build.go index 69e898d90..3e5849e64 100644 --- a/database/postgres/build.go +++ b/database/postgres/build.go @@ -44,7 +44,32 @@ func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { return b.ToLibrary(), result.Error } +// GetBuildByID gets a build by id from the database. +func (c *client) GetBuildByID(id int64) (*library.Build, error) { + c.Logger.WithFields(logrus.Fields{ + "build": id, + }).Tracef("getting build %d from the database", id) + + // variable to store query result + b := new(database.Build) + + // send query to the database and store result in variable + result := c.Postgres. + Table(constants.TableBuild). + Raw(dml.SelectBuildByID, id). + Scan(b) + + // check if the query returned a record not found error or no rows were returned + if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { + return nil, gorm.ErrRecordNotFound + } + + return b.ToLibrary(), result.Error +} + // GetLastBuild gets the last build by repo ID from the database. +// +//nolint:dupl // ignore similar code with hook func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/postgres/build_test.go b/database/postgres/build_test.go index b490ee6a1..06d6238b2 100644 --- a/database/postgres/build_test.go +++ b/database/postgres/build_test.go @@ -93,6 +93,74 @@ func TestPostgres_Client_GetBuild(t *testing.T) { } } +func TestPostgres_Client_GetBuildByID(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + // setup the test database client + _database, _mock, err := NewTest() + if err != nil { + t.Errorf("unable to create new postgres test database: %v", err) + } + + defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() + + // capture the current expected SQL query + // + // https://gorm.io/docs/sql_builder.html#DryRun-Mode + _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildByID, 1).Statement + + // create expected return in mock + _rows := sqlmock.NewRows( + []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", "timestamp"}, + ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // ensure the mock expects the query for test case 1 + _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) + // ensure the mock expects the error for test case 2 + _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) + + // setup tests + tests := []struct { + failure bool + want *library.Build + }{ + { + failure: false, + want: _build, + }, + { + failure: true, + want: nil, + }, + } + + // run tests + for _, test := range tests { + got, err := _database.GetBuildByID(1) + + if test.failure { + if err == nil { + t.Errorf("GetBuildByID should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("GetBuildByID returned err: %v", err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetBuildByID is %v, want %v", got, test.want) + } + } +} + func TestPostgres_Client_GetLastBuild(t *testing.T) { // setup types _build := testBuild() diff --git a/database/postgres/dml/build.go b/database/postgres/dml/build.go index 115e7f0a5..9080157c6 100644 --- a/database/postgres/dml/build.go +++ b/database/postgres/dml/build.go @@ -10,6 +10,15 @@ const ( ListBuilds = ` SELECT * FROM builds; +` + + // SelectBuildByID represents a query to select + // a build for its id in the database. + SelectBuildByID = ` +SELECT * +FROM builds +WHERE id = ? +LIMIT 1; ` // SelectRepoBuild represents a query to select diff --git a/database/postgres/hook.go b/database/postgres/hook.go index 5994e5e20..3292d9d7a 100644 --- a/database/postgres/hook.go +++ b/database/postgres/hook.go @@ -45,6 +45,8 @@ func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { } // GetLastHook gets the last hook by repo ID from the database. +// +//nolint:dupl // ignore similar code with build func (c *client) GetLastHook(r *library.Repo) (*library.Hook, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/service.go b/database/service.go index 2191ec1c6..b6c4b140c 100644 --- a/database/service.go +++ b/database/service.go @@ -26,6 +26,9 @@ type Service interface { // GetBuild defines a function that // gets a build by number and repo ID. GetBuild(int, *library.Repo) (*library.Build, error) + // GetBuildByID defines a function that + // gets a build by its id. + GetBuildByID(int64) (*library.Build, error) // GetLastBuild defines a function that // gets the last build ran by repo ID. GetLastBuild(*library.Repo) (*library.Build, error) diff --git a/database/sqlite/build.go b/database/sqlite/build.go index b32f85f53..a0c47067d 100644 --- a/database/sqlite/build.go +++ b/database/sqlite/build.go @@ -44,7 +44,32 @@ func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { return b.ToLibrary(), result.Error } +// GetBuildByID gets a build by its ID from the database. +func (c *client) GetBuildByID(id int64) (*library.Build, error) { + c.Logger.WithFields(logrus.Fields{ + "build": id, + }).Tracef("getting build %d from the database", id) + + // variable to store query result + b := new(database.Build) + + // send query to the database and store result in variable + result := c.Sqlite. + Table(constants.TableBuild). + Raw(dml.SelectBuildByID, id). + Scan(b) + + // check if the query returned a record not found error or no rows were returned + if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { + return nil, gorm.ErrRecordNotFound + } + + return b.ToLibrary(), result.Error +} + // GetLastBuild gets the last build by repo ID from the database. +// +//nolint:dupl // ignore similar code with hook func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/sqlite/build_test.go b/database/sqlite/build_test.go index c275ae6c7..a0e8eb8c1 100644 --- a/database/sqlite/build_test.go +++ b/database/sqlite/build_test.go @@ -84,6 +84,70 @@ func TestSqlite_Client_GetBuild(t *testing.T) { } } +func TestSqlite_Client_GetBuildByID(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + // setup the test database client + _database, err := NewTest() + if err != nil { + t.Errorf("unable to create new sqlite test database: %v", err) + } + + defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + want *library.Build + }{ + { + failure: false, + want: _build, + }, + { + failure: true, + want: nil, + }, + } + + // run tests + for _, test := range tests { + if test.want != nil { + // create the build in the database + err := _database.CreateBuild(test.want) + if err != nil { + t.Errorf("unable to create test build: %v", err) + } + } + + got, err := _database.GetBuildByID(1) + + // cleanup the builds table + _ = _database.Sqlite.Exec("DELETE FROM builds;") + + if test.failure { + if err == nil { + t.Errorf("GetBuildByID should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("GetBuildByID returned err: %v", err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetBuildByID is %v, want %v", got, test.want) + } + } +} + func TestSqlite_Client_GetLastBuild(t *testing.T) { // setup types _build := testBuild() diff --git a/database/sqlite/dml/build.go b/database/sqlite/dml/build.go index ff8863e8c..fa9f94453 100644 --- a/database/sqlite/dml/build.go +++ b/database/sqlite/dml/build.go @@ -10,6 +10,15 @@ const ( ListBuilds = ` SELECT * FROM builds; +` + + // SelectBuildByID represents a query to select + // a build for its id in the database. + SelectBuildByID = ` +SELECT * +FROM builds +WHERE id = ? +LIMIT 1; ` // SelectRepoBuild represents a query to select diff --git a/database/sqlite/hook.go b/database/sqlite/hook.go index 517a08c06..0dda61b79 100644 --- a/database/sqlite/hook.go +++ b/database/sqlite/hook.go @@ -45,6 +45,8 @@ func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { } // GetLastHook gets the last hook by repo ID from the database. +// +//nolint:dupl // ignore similar code with build func (c *client) GetLastHook(r *library.Repo) (*library.Hook, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/router/admin.go b/router/admin.go index 86bda3501..f3dbb680f 100644 --- a/router/admin.go +++ b/router/admin.go @@ -13,50 +13,45 @@ import ( // AdminHandlers is a function that extends the provided base router group // with the API handlers for admin functionality. // -// GET /api/v1/admin/builds // GET /api/v1/admin/builds/queue +// GET /api/v1/admin/build/:id // PUT /api/v1/admin/build -// GET /api/v1/admin/deployments // PUT /api/v1/admin/deployment -// GET /api/v1/admin/hooks // PUT /api/v1/admin/hook -// GET /api/v1/admin/repos // PUT /api/v1/admin/repo -// GET /api/v1/admin/secrets // PUT /api/v1/admin/secret -// GET /api/v1/admin/services // PUT /api/v1/admin/service -// GET /api/v1/admin/steps // PUT /api/v1/admin/step -// GET /api/v1/admin/users // PUT /api/v1/admin/user. func AdminHandlers(base *gin.RouterGroup) { // Admin endpoints _admin := base.Group("/admin", perm.MustPlatformAdmin()) { - // Admin build endpoints + // Admin build queue endpoint _admin.GET("/builds/queue", admin.AllBuildsQueue) + + // Admin build endpoint _admin.PUT("/build", admin.UpdateBuild) - // Admin deployment endpoints + // Admin deployment endpoint _admin.PUT("/deployment", admin.UpdateDeployment) - // Admin hook endpoints + // Admin hook endpoint _admin.PUT("/hook", admin.UpdateHook) - // Admin repo endpoints + // Admin repo endpoint _admin.PUT("/repo", admin.UpdateRepo) - // Admin secret endpoints + // Admin secret endpoint _admin.PUT("/secret", admin.UpdateSecret) - // Admin service endpoints + // Admin service endpoint _admin.PUT("/service", admin.UpdateService) - // Admin step endpoints + // Admin step endpoint _admin.PUT("/step", admin.UpdateStep) - // Admin user endpoints + // Admin user endpoint _admin.PUT("/user", admin.UpdateUser) } // end of admin endpoints } diff --git a/router/router.go b/router/router.go index 402f4eb93..9b33c700f 100644 --- a/router/router.go +++ b/router/router.go @@ -114,6 +114,9 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // Source code management endpoints ScmHandlers(baseAPI) + // Search endpoints + SearchHandlers(baseAPI) + // Secret endpoints SecretHandlers(baseAPI) diff --git a/router/search.go b/router/search.go new file mode 100644 index 000000000..2aaaec699 --- /dev/null +++ b/router/search.go @@ -0,0 +1,26 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package router + +import ( + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" +) + +// SearchHandlers is a function that extends the provided base router group +// with the API handlers for resource search functionality. +// +// GET /api/v1/search/builds/:id . +func SearchHandlers(base *gin.RouterGroup) { + // Search endpoints + search := base.Group("/search") + { + // Build endpoint + build := search.Group("/builds") + { + build.GET("/:id", api.GetBuildByID) + } + } // end of search endpoints +} diff --git a/scm/github/github_test.go b/scm/github/github_test.go index 4f8016463..118f3be02 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -76,12 +76,12 @@ func TestGithub_newClientToken(t *testing.T) { // run test got := client.newClientToken("foobar") - //nolint: staticcheck // ignore false positive + //nolint:staticcheck // ignore false positive if got == nil { t.Errorf("newClientToken is nil, want %v", want) } - //nolint: staticcheck // ignore false positive + //nolint:staticcheck // ignore false positive if !reflect.DeepEqual(got.BaseURL, want.BaseURL) { t.Errorf("newClientToken BaseURL is %v, want %v", got.BaseURL, want.BaseURL) } From 60dd8d7386dcb91e42ef00911c23d9edb24a73ee Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Wed, 14 Dec 2022 14:23:08 -0600 Subject: [PATCH 149/298] chore(release): dependency updates for v0.17.0-rc1 (#745) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 244b19e50..a12ec9b5c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.16.2 + github.com/go-vela/types v0.17.0-rc1 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index dc090f793..94ce3f7af 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.16.2 h1:c2Kkj7OKv4sjPrsOBbnPSQqfsNpOFM2La7LfP+81EF0= -github.com/go-vela/types v0.16.2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.17.0-rc1 h1:OnQByNmqWssqpfe9RNai7d9V1KfMJGfamymnsqFAaC0= +github.com/go-vela/types v0.17.0-rc1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From 8c8bdfbf08f0fda5d4a993f5b3b8ccde3da550e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 09:52:58 -0600 Subject: [PATCH 150/298] fix(deps): update deps (patch) (#746) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a12ec9b5c..b98360ea0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.23.1 - github.com/aws/aws-sdk-go v1.44.157 + github.com/aws/aws-sdk-go v1.44.161 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.3 - github.com/urfave/cli/v2 v2.23.6 + github.com/urfave/cli/v2 v2.23.7 go.starlark.net v0.0.0-20221205180719-3fd0dac74452 golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index 94ce3f7af..f6e64fd9c 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.157 h1:JVBPpEWC8+yA7CbfAuTl/ZFFlHS3yoqWFqxFyTCISwg= -github.com/aws/aws-sdk-go v1.44.157/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.161 h1:uZdZJ30mlbaU2wsrd/wzibrX01cbgKE2t486TtRjeHs= +github.com/aws/aws-sdk-go v1.44.161/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -541,8 +541,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.23.6 h1:iWmtKD+prGo1nKUtLO0Wg4z9esfBM4rAV4QRLQiEmJ4= -github.com/urfave/cli/v2 v2.23.6/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY= +github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 903804fa87a226e352db03197dcf5ebcc4dc44af Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Fri, 16 Dec 2022 10:13:48 -0600 Subject: [PATCH 151/298] chore(release): v0.17.0-rc2 (#747) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index b98360ea0..dadf5a9bf 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.17.0-rc1 + github.com/go-vela/types v0.17.0-rc2 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 @@ -129,7 +129,7 @@ require ( golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect - golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect google.golang.org/grpc v1.41.0 // indirect diff --git a/go.sum b/go.sum index f6e64fd9c..6f33c9431 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.17.0-rc1 h1:OnQByNmqWssqpfe9RNai7d9V1KfMJGfamymnsqFAaC0= -github.com/go-vela/types v0.17.0-rc1/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.17.0-rc2 h1:Rrh7GzgT2QzTOLedD8T5mT0lvh/FxFhO3Zh5/b9STGQ= +github.com/go-vela/types v0.17.0-rc2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= @@ -777,8 +777,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= From 74d2a68088ba20d6a91646277d98fbccb3caf641 Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Fri, 16 Dec 2022 15:27:57 -0600 Subject: [PATCH 152/298] chore(release): update dependencies for v0.17.0 (#748) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dadf5a9bf..86e17605d 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.17.0-rc2 + github.com/go-vela/types v0.17.0 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index 6f33c9431..ab2291f6f 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.17.0-rc2 h1:Rrh7GzgT2QzTOLedD8T5mT0lvh/FxFhO3Zh5/b9STGQ= -github.com/go-vela/types v0.17.0-rc2/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.17.0 h1:nvKBbNO8BSiLtYPMScT0XWosGqEWX85UKSkkclb2DVA= +github.com/go-vela/types v0.17.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= From f76146b7255292cee2ad4d36bdb407425aac856b Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 14 Feb 2023 11:49:18 -0600 Subject: [PATCH 153/298] refactor(database): move hook logic into separate package (#721) * feat(database): add user engine * chore(database): remove old user logic * refactor(database): restructure DDL functions * chore: updates for database user engine * feat(database): add repo engine * chore: save work * fix: Scan() -> Take() * fix: sort by for listing repos * feat(database): add worker engine * chore(database): remove old worker logic * chore: updates for database worker engine * fix: issues from merge conflict * chore: address linter feedback * chore: address linter feedback v2 * feat(database): add hook engine * chore: remove Limit(1) with Take() * chore(database): remove old hook logic * chore: updates for database hook engine * refactor(database/worker): name of index * chore: address linter feedback * fix: unintended changes * chore: update tests for unintended changes --- api/admin/hook.go | 4 +- api/hook.go | 28 +- api/webhook.go | 6 +- database/hook/count.go | 25 ++ .../hook_count.go => hook/count_repo.go} | 16 +- database/hook/count_repo_test.go | 104 ++++++ database/hook/count_test.go | 97 +++++ database/hook/create.go | 38 ++ database/hook/create_test.go | 75 ++++ database/hook/delete.go | 30 ++ database/hook/delete_test.go | 75 ++++ database/hook/get.go | 34 ++ database/hook/get_repo.go | 40 ++ database/hook/get_repo_test.go | 94 +++++ database/hook/get_test.go | 87 +++++ database/hook/hook.go | 80 ++++ database/hook/hook_test.go | 218 +++++++++++ database/hook/index.go | 24 ++ database/hook/index_test.go | 59 +++ database/hook/last_repo.go | 49 +++ database/hook/last_repo_test.go | 94 +++++ database/hook/list.go | 54 +++ database/hook/list_repo.go | 65 ++++ database/hook/list_repo_test.go | 114 ++++++ database/hook/list_test.go | 107 ++++++ database/hook/opts.go | 44 +++ database/hook/opts_test.go | 161 ++++++++ database/hook/service.go | 49 +++ database/hook/table.go | 74 ++++ database/hook/table_test.go | 59 +++ database/hook/update.go | 38 ++ database/hook/update_test.go | 77 ++++ database/postgres/build.go | 4 - database/postgres/ddl/hook.go | 40 -- database/postgres/dml/hook.go | 61 ---- database/postgres/hook.go | 124 ------- database/postgres/hook_count.go | 31 -- database/postgres/hook_count_test.go | 91 ----- database/postgres/hook_list.go | 72 ---- database/postgres/hook_list_test.go | 170 --------- database/postgres/hook_test.go | 345 ------------------ database/postgres/postgres.go | 29 +- database/postgres/postgres_test.go | 11 +- database/service.go | 30 +- database/sqlite/build.go | 4 - database/sqlite/ddl/hook.go | 40 -- database/sqlite/dml/hook.go | 61 ---- database/sqlite/hook.go | 124 ------- database/sqlite/hook_count_test.go | 108 ------ database/sqlite/hook_list.go | 72 ---- database/sqlite/hook_list_test.go | 176 --------- database/sqlite/hook_test.go | 340 ----------------- database/sqlite/sqlite.go | 27 +- 53 files changed, 2129 insertions(+), 1950 deletions(-) create mode 100644 database/hook/count.go rename database/{sqlite/hook_count.go => hook/count_repo.go} (62%) create mode 100644 database/hook/count_repo_test.go create mode 100644 database/hook/count_test.go create mode 100644 database/hook/create.go create mode 100644 database/hook/create_test.go create mode 100644 database/hook/delete.go create mode 100644 database/hook/delete_test.go create mode 100644 database/hook/get.go create mode 100644 database/hook/get_repo.go create mode 100644 database/hook/get_repo_test.go create mode 100644 database/hook/get_test.go create mode 100644 database/hook/hook.go create mode 100644 database/hook/hook_test.go create mode 100644 database/hook/index.go create mode 100644 database/hook/index_test.go create mode 100644 database/hook/last_repo.go create mode 100644 database/hook/last_repo_test.go create mode 100644 database/hook/list.go create mode 100644 database/hook/list_repo.go create mode 100644 database/hook/list_repo_test.go create mode 100644 database/hook/list_test.go create mode 100644 database/hook/opts.go create mode 100644 database/hook/opts_test.go create mode 100644 database/hook/service.go create mode 100644 database/hook/table.go create mode 100644 database/hook/table_test.go create mode 100644 database/hook/update.go create mode 100644 database/hook/update_test.go delete mode 100644 database/postgres/ddl/hook.go delete mode 100644 database/postgres/dml/hook.go delete mode 100644 database/postgres/hook.go delete mode 100644 database/postgres/hook_count.go delete mode 100644 database/postgres/hook_count_test.go delete mode 100644 database/postgres/hook_list.go delete mode 100644 database/postgres/hook_list_test.go delete mode 100644 database/postgres/hook_test.go delete mode 100644 database/sqlite/ddl/hook.go delete mode 100644 database/sqlite/dml/hook.go delete mode 100644 database/sqlite/hook.go delete mode 100644 database/sqlite/hook_count_test.go delete mode 100644 database/sqlite/hook_list.go delete mode 100644 database/sqlite/hook_list_test.go delete mode 100644 database/sqlite/hook_test.go diff --git a/api/admin/hook.go b/api/admin/hook.go index a680d598d..322142d27 100644 --- a/api/admin/hook.go +++ b/api/admin/hook.go @@ -9,12 +9,10 @@ import ( "fmt" "net/http" + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) diff --git a/api/hook.go b/api/hook.go index 29a1ffae9..1787f9975 100644 --- a/api/hook.go +++ b/api/hook.go @@ -91,7 +91,7 @@ func CreateHook(c *gin.Context) { } // send API call to capture the last hook for the repo - lastHook, err := database.FromContext(c).GetLastHook(r) + lastHook, err := database.FromContext(c).LastHookForRepo(r) if err != nil { retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) @@ -125,7 +125,7 @@ func CreateHook(c *gin.Context) { } // send API call to capture the created webhook - h, _ := database.FromContext(c).GetHook(input.GetNumber(), r) + h, _ := database.FromContext(c).GetHookForRepo(r, input.GetNumber()) c.JSON(http.StatusCreated, h) } @@ -224,18 +224,8 @@ func GetHooks(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) - // send API call to capture the total number of webhooks for the repo - t, err := database.FromContext(c).GetRepoHookCount(r) - if err != nil { - retErr := fmt.Errorf("unable to get hooks count for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // send API call to capture the list of steps for the build - h, err := database.FromContext(c).GetRepoHookList(r, page, perPage) + h, t, err := database.FromContext(c).ListHooksForRepo(r, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get hooks for repo %s: %w", r.GetFullName(), err) @@ -326,7 +316,7 @@ func GetHook(c *gin.Context) { } // send API call to capture the webhook - h, err := database.FromContext(c).GetHook(number, r) + h, err := database.FromContext(c).GetHookForRepo(r, number) if err != nil { retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) @@ -430,7 +420,7 @@ func UpdateHook(c *gin.Context) { } // send API call to capture the webhook - h, err := database.FromContext(c).GetHook(number, r) + h, err := database.FromContext(c).GetHookForRepo(r, number) if err != nil { retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) @@ -486,7 +476,7 @@ func UpdateHook(c *gin.Context) { } // send API call to capture the updated user - h, _ = database.FromContext(c).GetHook(h.GetNumber(), r) + h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) c.JSON(http.StatusOK, h) } @@ -565,7 +555,7 @@ func DeleteHook(c *gin.Context) { } // send API call to capture the webhook - h, err := database.FromContext(c).GetHook(number, r) + h, err := database.FromContext(c).GetHookForRepo(r, number) if err != nil { retErr := fmt.Errorf("unable to get hook %s: %w", hook, err) @@ -575,7 +565,7 @@ func DeleteHook(c *gin.Context) { } // send API call to remove the webhook - err = database.FromContext(c).DeleteHook(h.GetID()) + err = database.FromContext(c).DeleteHook(h) if err != nil { retErr := fmt.Errorf("unable to delete hook %s: %w", hook, err) @@ -662,7 +652,7 @@ func RedeliverHook(c *gin.Context) { } // send API call to capture the webhook - h, err := database.FromContext(c).GetHook(number, r) + h, err := database.FromContext(c).GetHookForRepo(r, number) if err != nil { retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) diff --git a/api/webhook.go b/api/webhook.go index adc220fd4..d624e22dc 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -249,7 +249,7 @@ func PostWebhook(c *gin.Context) { h.SetRepoID(r.GetID()) // send API call to capture the last hook for the repo - lastHook, err := database.FromContext(c).GetLastHook(r) + lastHook, err := database.FromContext(c).LastHookForRepo(r) if err != nil { retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -280,7 +280,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the created webhook - h, _ = database.FromContext(c).GetHook(h.GetNumber(), r) + h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) // verify the webhook from the source control provider if c.Value("webhookvalidation").(bool) { @@ -835,7 +835,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types h.SetRepoID(r.GetID()) // send API call to capture the last hook for the repo - lastHook, err := database.FromContext(c).GetLastHook(dbR) + lastHook, err := database.FromContext(c).LastHookForRepo(dbR) if err != nil { retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/database/hook/count.go b/database/hook/count.go new file mode 100644 index 000000000..a1a9689f8 --- /dev/null +++ b/database/hook/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" +) + +// CountHooks gets the count of all hooks from the database. +func (e *engine) CountHooks() (int64, error) { + e.logger.Tracef("getting count of all hooks from the database") + + // variable to store query results + var h int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableHook). + Count(&h). + Error + + return h, err +} diff --git a/database/sqlite/hook_count.go b/database/hook/count_repo.go similarity index 62% rename from database/sqlite/hook_count.go rename to database/hook/count_repo.go index 793ec10b8..eb6d6763b 100644 --- a/database/sqlite/hook_count.go +++ b/database/hook/count_repo.go @@ -2,18 +2,17 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package sqlite +package hook import ( - "github.com/go-vela/server/database/sqlite/dml" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) -// GetRepoHookCount gets the count of webhooks by repo ID from the database. -func (c *client) GetRepoHookCount(r *library.Repo) (int64, error) { - c.Logger.WithFields(logrus.Fields{ +// CountHooksForRepo gets the count of hooks by repo ID from the database. +func (e *engine) CountHooksForRepo(r *library.Repo) (int64, error) { + e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), }).Tracef("getting count of hooks for repo %s from the database", r.GetFullName()) @@ -22,10 +21,11 @@ func (c *client) GetRepoHookCount(r *library.Repo) (int64, error) { var h int64 // send query to the database and store result in variable - err := c.Sqlite. + err := e.client. Table(constants.TableHook). - Raw(dml.SelectRepoHookCount, r.GetID()). - Pluck("count", &h).Error + Where("repo_id = ?", r.GetID()). + Count(&h). + Error return h, err } diff --git a/database/hook/count_repo_test.go b/database/hook/count_repo_test.go new file mode 100644 index 000000000..83fe35dab --- /dev/null +++ b/database/hook/count_repo_test.go @@ -0,0 +1,104 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_CountHooksForRepo(t *testing.T) { + // setup types + _hookOne := testHook() + _hookOne.SetID(1) + _hookOne.SetRepoID(1) + _hookOne.SetBuildID(1) + _hookOne.SetNumber(1) + _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) + + _hookTwo := testHook() + _hookTwo.SetID(2) + _hookTwo.SetRepoID(2) + _hookTwo.SetBuildID(2) + _hookTwo.SetNumber(2) + _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "hooks" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hookOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateHook(_hookTwo) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountHooksForRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("CountHooksForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountHooksForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountHooksForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/count_test.go b/database/hook/count_test.go new file mode 100644 index 000000000..6e4df9df4 --- /dev/null +++ b/database/hook/count_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_CountHooks(t *testing.T) { + // setup types + _hookOne := testHook() + _hookOne.SetID(1) + _hookOne.SetRepoID(1) + _hookOne.SetBuildID(1) + _hookOne.SetNumber(1) + _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) + + _hookTwo := testHook() + _hookTwo.SetID(2) + _hookTwo.SetRepoID(1) + _hookTwo.SetBuildID(2) + _hookTwo.SetNumber(2) + _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "hooks"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hookOne) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + err = _sqlite.CreateHook(_hookTwo) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountHooks() + + if test.failure { + if err == nil { + t.Errorf("CountHooks for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountHooks for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountHooks for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/create.go b/database/hook/create.go new file mode 100644 index 000000000..ce3745da3 --- /dev/null +++ b/database/hook/create.go @@ -0,0 +1,38 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateHook creates a new hook in the database. +func (e *engine) CreateHook(h *library.Hook) error { + e.logger.WithFields(logrus.Fields{ + "hook": h.GetNumber(), + }).Tracef("creating hook %d in the database", h.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#HookFromLibrary + hook := database.HookFromLibrary(h) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.Validate + err := hook.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableHook). + Create(hook). + Error +} diff --git a/database/hook/create_test.go b/database/hook/create_test.go new file mode 100644 index 000000000..1fd03f2b9 --- /dev/null +++ b/database/hook/create_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_CreateHook(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "hooks" +("repo_id","build_id","number","source_id","created","host","event","event_action","branch","error","status","link","webhook_id","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateHook(_hook) + + if test.failure { + if err == nil { + t.Errorf("CreateHook for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateHook for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/hook/delete.go b/database/hook/delete.go new file mode 100644 index 000000000..d4e688f1c --- /dev/null +++ b/database/hook/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteHook deletes an existing hook from the database. +func (e *engine) DeleteHook(h *library.Hook) error { + e.logger.WithFields(logrus.Fields{ + "hook": h.GetNumber(), + }).Tracef("deleting hook %d in the database", h.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#HookFromLibrary + hook := database.HookFromLibrary(h) + + // send query to the database + return e.client. + Table(constants.TableHook). + Delete(hook). + Error +} diff --git a/database/hook/delete_test.go b/database/hook/delete_test.go new file mode 100644 index 000000000..e5deab7ad --- /dev/null +++ b/database/hook/delete_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_DeleteHook(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "hooks" WHERE "hooks"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hook) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteHook(_hook) + + if test.failure { + if err == nil { + t.Errorf("DeleteHook for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteHook for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/hook/get.go b/database/hook/get.go new file mode 100644 index 000000000..13547669c --- /dev/null +++ b/database/hook/get.go @@ -0,0 +1,34 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetHook gets a hook by ID from the database. +func (e *engine) GetHook(id int64) (*library.Hook, error) { + e.logger.Tracef("getting hook %d from the database", id) + + // variable to store query results + h := new(database.Hook) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableHook). + Where("id = ?", id). + Take(h). + Error + if err != nil { + return nil, err + } + + // return the hook + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.ToLibrary + return h.ToLibrary(), nil +} diff --git a/database/hook/get_repo.go b/database/hook/get_repo.go new file mode 100644 index 000000000..4c7e3b857 --- /dev/null +++ b/database/hook/get_repo.go @@ -0,0 +1,40 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetHookForRepo gets a hook by repo ID and number from the database. +func (e *engine) GetHookForRepo(r *library.Repo, number int) (*library.Hook, error) { + e.logger.WithFields(logrus.Fields{ + "hook": number, + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting hook %s/%d from the database", r.GetFullName(), number) + + // variable to store query results + h := new(database.Hook) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableHook). + Where("repo_id = ?", r.GetID()). + Where("number = ?", number). + Take(h). + Error + if err != nil { + return nil, err + } + + // return the hook + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.ToLibrary + return h.ToLibrary(), nil +} diff --git a/database/hook/get_repo_test.go b/database/hook/get_repo_test.go new file mode 100644 index 000000000..eb1103cad --- /dev/null +++ b/database/hook/get_repo_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestHook_Engine_GetHookForRepo(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}). + AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "hooks" WHERE repo_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hook) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Hook + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _hook, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _hook, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetHookForRepo(_repo, 1) + + if test.failure { + if err == nil { + t.Errorf("GetHookForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetHookForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetHookForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/get_test.go b/database/hook/get_test.go new file mode 100644 index 000000000..79e8a9856 --- /dev/null +++ b/database/hook/get_test.go @@ -0,0 +1,87 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestHook_Engine_GetHook(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, + ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "hooks" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hook) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Hook + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _hook, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _hook, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetHook(1) + + if test.failure { + if err == nil { + t.Errorf("GetHook for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetHook for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetHook for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/hook.go b/database/hook/hook.go new file mode 100644 index 000000000..279bc3d2a --- /dev/null +++ b/database/hook/hook.go @@ -0,0 +1,80 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the HookService interface. + config struct { + // specifies to skip creating tables and indexes for the Hook engine + SkipCreation bool + } + + // engine represents the hook functionality that implements the HookService interface. + engine struct { + // engine configuration settings used in hook functions + config *config + + // gorm.io/gorm database client used in hook functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in hook functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with hooks in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Hook engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating hook database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of hooks table and indexes in the database") + + return e, nil + } + + // create the hooks table + err := e.CreateHookTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableHook, err) + } + + // create the indexes for the hooks table + err = e.CreateHookIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableHook, err) + } + + return e, nil +} diff --git a/database/hook/hook_test.go b/database/hook/hook_test.go new file mode 100644 index 000000000..e8d3130cc --- /dev/null +++ b/database/hook/hook_test.go @@ -0,0 +1,218 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestHook_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres hook engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite hook engine: %v", err) + } + + 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() *library.Repo { + return &library.Repo{ + ID: new(int64), + UserID: 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), + AllowPull: new(bool), + AllowPush: new(bool), + AllowDeploy: new(bool), + AllowTag: new(bool), + AllowComment: new(bool), + } +} diff --git a/database/hook/index.go b/database/hook/index.go new file mode 100644 index 000000000..b81fd29f5 --- /dev/null +++ b/database/hook/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +const ( + // CreateRepoIDIndex represents a query to create an + // index on the hooks table for the repo_id column. + CreateRepoIDIndex = ` +CREATE INDEX +IF NOT EXISTS +hooks_repo_id +ON hooks (repo_id); +` +) + +// CreateHookIndexes creates the indexes for the hooks table in the database. +func (e *engine) CreateHookIndexes() error { + e.logger.Tracef("creating indexes for hooks table in the database") + + // create the hostname and address columns index for the hooks table + return e.client.Exec(CreateRepoIDIndex).Error +} diff --git a/database/hook/index_test.go b/database/hook/index_test.go new file mode 100644 index 000000000..06ab40a95 --- /dev/null +++ b/database/hook/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_CreateHookIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateHookIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateHookIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateHookIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/hook/last_repo.go b/database/hook/last_repo.go new file mode 100644 index 000000000..22c3ef992 --- /dev/null +++ b/database/hook/last_repo.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "errors" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// LastHookForRepo gets the last hook by repo ID from the database. +func (e *engine) LastHookForRepo(r *library.Repo) (*library.Hook, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting last hook for repo %s from the database", r.GetFullName()) + + // variable to store query results + h := new(database.Hook) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableHook). + Where("repo_id = ?", r.GetID()). + Order("number DESC"). + Take(h). + Error + if err != nil { + // check if the query returned a record not found error + if errors.Is(err, gorm.ErrRecordNotFound) { + // the record will not exist if it is a new repo + return nil, nil + } + + return nil, err + } + + // return the hook + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.ToLibrary + return h.ToLibrary(), nil +} diff --git a/database/hook/last_repo_test.go b/database/hook/last_repo_test.go new file mode 100644 index 000000000..c7efeab75 --- /dev/null +++ b/database/hook/last_repo_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestHook_Engine_LastHookForRepo(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}). + AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "hooks" WHERE repo_id = $1 ORDER BY number DESC LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hook) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Hook + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _hook, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _hook, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.LastHookForRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("LastHookForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("LastHookForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("LastHookForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/list.go b/database/hook/list.go new file mode 100644 index 000000000..1152738e6 --- /dev/null +++ b/database/hook/list.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListHooks gets a list of all hooks from the database. +func (e *engine) ListHooks() ([]*library.Hook, error) { + e.logger.Trace("listing all hooks from the database") + + // variables to store query results and return value + count := int64(0) + h := new([]database.Hook) + hooks := []*library.Hook{} + + // count the results + count, err := e.CountHooks() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return hooks, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableHook). + Find(&h). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, hook := range *h { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := hook + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.ToLibrary + hooks = append(hooks, tmp.ToLibrary()) + } + + return hooks, nil +} diff --git a/database/hook/list_repo.go b/database/hook/list_repo.go new file mode 100644 index 000000000..1060f5863 --- /dev/null +++ b/database/hook/list_repo.go @@ -0,0 +1,65 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListHooksForRepo gets a list of hooks by repo ID from the database. +func (e *engine) ListHooksForRepo(r *library.Repo, page, perPage int) ([]*library.Hook, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("listing hooks for repo %s from the database", r.GetFullName()) + + // variables to store query results and return value + count := int64(0) + h := new([]database.Hook) + hooks := []*library.Hook{} + + // count the results + count, err := e.CountHooksForRepo(r) + if err != nil { + return nil, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return hooks, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableHook). + Where("repo_id = ?", r.GetID()). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&h). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, hook := range *h { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := hook + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.ToLibrary + hooks = append(hooks, tmp.ToLibrary()) + } + + return hooks, count, nil +} diff --git a/database/hook/list_repo_test.go b/database/hook/list_repo_test.go new file mode 100644 index 000000000..709de156e --- /dev/null +++ b/database/hook/list_repo_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestHook_Engine_ListHooksForRepo(t *testing.T) { + // setup types + _hookOne := testHook() + _hookOne.SetID(1) + _hookOne.SetRepoID(1) + _hookOne.SetBuildID(1) + _hookOne.SetNumber(1) + _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) + + _hookTwo := testHook() + _hookTwo.SetID(2) + _hookTwo.SetRepoID(1) + _hookTwo.SetBuildID(2) + _hookTwo.SetNumber(2) + _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "hooks" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). + AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "hooks" WHERE repo_id = $1 ORDER BY id DESC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hookOne) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + err = _sqlite.CreateHook(_hookTwo) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Hook + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Hook{_hookTwo, _hookOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Hook{_hookTwo, _hookOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListHooksForRepo(_repo, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListHooksForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListHooksForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListHooksForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/list_test.go b/database/hook/list_test.go new file mode 100644 index 000000000..ba0784213 --- /dev/null +++ b/database/hook/list_test.go @@ -0,0 +1,107 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestHook_Engine_ListHooks(t *testing.T) { + // setup types + _hookOne := testHook() + _hookOne.SetID(1) + _hookOne.SetRepoID(1) + _hookOne.SetBuildID(1) + _hookOne.SetNumber(1) + _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookOne.SetWebhookID(1) + + _hookTwo := testHook() + _hookTwo.SetID(2) + _hookTwo.SetRepoID(1) + _hookTwo.SetBuildID(2) + _hookTwo.SetNumber(2) + _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hookTwo.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "hooks"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}). + AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). + AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "hooks"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hookOne) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + err = _sqlite.CreateHook(_hookTwo) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Hook + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Hook{_hookOne, _hookTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Hook{_hookOne, _hookTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListHooks() + + if test.failure { + if err == nil { + t.Errorf("ListHooks for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListHooks for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListHooks for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/hook/opts.go b/database/hook/opts.go new file mode 100644 index 000000000..e88e92da7 --- /dev/null +++ b/database/hook/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Hooks. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Hooks. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the hook engine + e.client = client + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Hooks. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the hook engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Hooks. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the hook engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/hook/opts_test.go b/database/hook/opts_test.go new file mode 100644 index 000000000..81946c8f4 --- /dev/null +++ b/database/hook/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestHook_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestHook_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestHook_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/hook/service.go b/database/hook/service.go new file mode 100644 index 000000000..99a389fef --- /dev/null +++ b/database/hook/service.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/library" +) + +// HookService represents the Vela interface for hook +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type HookService interface { + // Hook Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateHookIndexes defines a function that creates the indexes for the hooks table. + CreateHookIndexes() error + // CreateHookTable defines a function that creates the hooks table. + CreateHookTable(string) error + + // Hook Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountHooks defines a function that gets the count of all hooks. + CountHooks() (int64, error) + // CountHooksForRepo defines a function that gets the count of hooks by repo ID. + CountHooksForRepo(*library.Repo) (int64, error) + // CreateHook defines a function that creates a new hook. + CreateHook(*library.Hook) error + // DeleteHook defines a function that deletes an existing hook. + DeleteHook(*library.Hook) error + // GetHook defines a function that gets a hook by ID. + GetHook(int64) (*library.Hook, error) + // GetHookForRepo defines a function that gets a hook by repo ID and number. + GetHookForRepo(*library.Repo, int) (*library.Hook, error) + // LastHookForRepo defines a function that gets the last hook by repo ID. + LastHookForRepo(*library.Repo) (*library.Hook, error) + // ListHooks defines a function that gets a list of all hooks. + ListHooks() ([]*library.Hook, error) + // ListHooksForRepo defines a function that gets a list of hooks by repo ID. + ListHooksForRepo(*library.Repo, int, int) ([]*library.Hook, int64, error) + // UpdateHook defines a function that updates an existing hook. + UpdateHook(*library.Hook) error +} diff --git a/database/hook/table.go b/database/hook/table.go new file mode 100644 index 000000000..9be4616c4 --- /dev/null +++ b/database/hook/table.go @@ -0,0 +1,74 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres hooks table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +hooks ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id VARCHAR(250), + created INTEGER, + host VARCHAR(250), + event VARCHAR(250), + event_action VARCHAR(250), + branch VARCHAR(500), + error VARCHAR(500), + status VARCHAR(250), + link VARCHAR(1000), + webhook_id INTEGER, + UNIQUE(repo_id, number) +); +` + + // CreateSqliteTable represents a query to create the Sqlite hooks table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +hooks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + source_id TEXT, + created INTEGER, + host TEXT, + event TEXT, + event_action TEXT, + branch TEXT, + error TEXT, + status TEXT, + link TEXT, + webhook_id INTEGER, + UNIQUE(repo_id, build_id) +); +` +) + +// CreateHookTable creates the hooks table in the database. +func (e *engine) CreateHookTable(driver string) error { + e.logger.Tracef("creating hooks table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the hooks table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the hooks table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/hook/table_test.go b/database/hook/table_test.go new file mode 100644 index 000000000..915621718 --- /dev/null +++ b/database/hook/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_CreateHookTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateHookTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateHookTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateHookTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/hook/update.go b/database/hook/update.go new file mode 100644 index 000000000..cfc746303 --- /dev/null +++ b/database/hook/update.go @@ -0,0 +1,38 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateHook updates an existing hook in the database. +func (e *engine) UpdateHook(h *library.Hook) error { + e.logger.WithFields(logrus.Fields{ + "hook": h.GetNumber(), + }).Tracef("updating hook %d in the database", h.GetNumber()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#HookFromLibrary + hook := database.HookFromLibrary(h) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Hook.Validate + err := hook.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableHook). + Save(hook). + Error +} diff --git a/database/hook/update_test.go b/database/hook/update_test.go new file mode 100644 index 000000000..a1f0d8de2 --- /dev/null +++ b/database/hook/update_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestHook_Engine_UpdateHook(t *testing.T) { + // setup types + _hook := testHook() + _hook.SetID(1) + _hook.SetRepoID(1) + _hook.SetBuildID(1) + _hook.SetNumber(1) + _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + _hook.SetWebhookID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "hooks" +SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"event_action"=$8,"branch"=$9,"error"=$10,"status"=$11,"link"=$12,"webhook_id"=$13 +WHERE "id" = $14`). + WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateHook(_hook) + if err != nil { + t.Errorf("unable to create test hook for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateHook(_hook) + + if test.failure { + if err == nil { + t.Errorf("UpdateHook for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateHook for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/postgres/build.go b/database/postgres/build.go index 3e5849e64..c8b7b66df 100644 --- a/database/postgres/build.go +++ b/database/postgres/build.go @@ -18,8 +18,6 @@ import ( ) // GetBuild gets a build by number and repo ID from the database. -// -//nolint:dupl // ignore similar code with hook func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "build": number, @@ -68,8 +66,6 @@ func (c *client) GetBuildByID(id int64) (*library.Build, error) { } // GetLastBuild gets the last build by repo ID from the database. -// -//nolint:dupl // ignore similar code with hook func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/postgres/ddl/hook.go b/database/postgres/ddl/hook.go deleted file mode 100644 index e0c67a38e..000000000 --- a/database/postgres/ddl/hook.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateHookTable represents a query to - // create the hooks table for Vela. - CreateHookTable = ` -CREATE TABLE -IF NOT EXISTS -hooks ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id VARCHAR(250), - created INTEGER, - host VARCHAR(250), - event VARCHAR(250), - event_action VARCHAR(250), - branch VARCHAR(500), - error VARCHAR(500), - status VARCHAR(250), - link VARCHAR(1000), - webhook_id INTEGER, - UNIQUE(repo_id, number) -); -` - - // CreateHookRepoIDIndex represents a query to create an - // index on the hooks table for the repo_id column. - CreateHookRepoIDIndex = ` -CREATE INDEX -IF NOT EXISTS -hooks_repo_id -ON hooks (repo_id); -` -) diff --git a/database/postgres/dml/hook.go b/database/postgres/dml/hook.go deleted file mode 100644 index b06d79ad5..000000000 --- a/database/postgres/dml/hook.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListHooks represents a query to - // list all webhooks in the database. - ListHooks = ` -SELECT * -FROM hooks; -` - - // ListRepoHooks represents a query to list - // all webhooks for a repo_id in the database. - ListRepoHooks = ` -SELECT * -FROM hooks -WHERE repo_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectRepoHookCount represents a query to select - // the count of webhooks for a repo_id in the database. - SelectRepoHookCount = ` -SELECT count(*) as count -FROM hooks -WHERE repo_id = ?; -` - - // SelectRepoHook represents a query to select - // a webhook for a repo_id in the database. - SelectRepoHook = ` -SELECT * -FROM hooks -WHERE repo_id = ? -AND number = ? -LIMIT 1; -` - - // SelectLastRepoHook represents a query to select - // the last hook for a repo_id in the database. - SelectLastRepoHook = ` -SELECT * -FROM hooks -WHERE repo_id = ? -ORDER BY number DESC -LIMIT 1; -` - - // DeleteHook represents a query to - // remove a webhook from the database. - DeleteHook = ` -DELETE -FROM hooks -WHERE id = ?; -` -) diff --git a/database/postgres/hook.go b/database/postgres/hook.go deleted file mode 100644 index 3292d9d7a..000000000 --- a/database/postgres/hook.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetHook gets a hook by number and repo ID from the database. -// -//nolint:dupl // ignore similar code with build -func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "hook": number, - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting hook %s/%d from the database", r.GetFullName(), number) - - // variable to store query results - h := new(database.Hook) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableHook). - Raw(dml.SelectRepoHook, r.GetID(), number). - Scan(h) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return h.ToLibrary(), result.Error -} - -// GetLastHook gets the last hook by repo ID from the database. -// -//nolint:dupl // ignore similar code with build -func (c *client) GetLastHook(r *library.Repo) (*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting last hook for repo %s from the database", r.GetFullName()) - - // variable to store query results - h := new(database.Hook) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableHook). - Raw(dml.SelectLastRepoHook, r.GetID()). - Scan(h) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return h.ToLibrary(), result.Error -} - -// CreateHook creates a new hook in the database. -func (c *client) CreateHook(h *library.Hook) error { - c.Logger.WithFields(logrus.Fields{ - "hook": h.GetNumber(), - }).Tracef("creating hook %d in the database", h.GetNumber()) - - // cast to database type - hook := database.HookFromLibrary(h) - - // validate the necessary fields are populated - err := hook.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableHook). - Create(hook).Error -} - -// UpdateHook updates a hook in the database. -func (c *client) UpdateHook(h *library.Hook) error { - c.Logger.WithFields(logrus.Fields{ - "hook": h.GetNumber(), - }).Tracef("updating hook %d in the database", h.GetNumber()) - - // cast to database type - hook := database.HookFromLibrary(h) - - // validate the necessary fields are populated - err := hook.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableHook). - Save(hook).Error -} - -// DeleteHook deletes a hook by unique ID from the database. -func (c *client) DeleteHook(id int64) error { - c.Logger.Tracef("deleting hook %d in the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableHook). - Exec(dml.DeleteHook, id).Error -} diff --git a/database/postgres/hook_count.go b/database/postgres/hook_count.go deleted file mode 100644 index 7d65f873e..000000000 --- a/database/postgres/hook_count.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetRepoHookCount gets the count of webhooks by repo ID from the database. -func (c *client) GetRepoHookCount(r *library.Repo) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting count of hooks for repo %s from the database", r.GetFullName()) - - // variable to store query results - var h int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableHook). - Raw(dml.SelectRepoHookCount, r.GetID()). - Pluck("count", &h).Error - - return h, err -} diff --git a/database/postgres/hook_count_test.go b/database/postgres/hook_count_test.go deleted file mode 100644 index 77943483e..000000000 --- a/database/postgres/hook_count_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetRepoHookCount(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepoHookCount, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetRepoHookCount(_repo) - - if test.failure { - if err == nil { - t.Errorf("GetRepoHookCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoHookCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoHookCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/hook_list.go b/database/postgres/hook_list.go deleted file mode 100644 index c46867fec..000000000 --- a/database/postgres/hook_list.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetHookList gets a list of all hooks from the database. -func (c *client) GetHookList() ([]*library.Hook, error) { - c.Logger.Trace("listing hooks from the database") - - // variable to store query results - h := new([]database.Hook) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableHook). - Raw(dml.ListHooks). - Scan(h).Error - - // variable we want to return - hooks := []*library.Hook{} - // iterate through all query results - for _, hook := range *h { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := hook - - // convert query result to library type - hooks = append(hooks, tmp.ToLibrary()) - } - - return hooks, err -} - -// GetRepoHookList gets a list of hooks by repo ID from the database. -func (c *client) GetRepoHookList(r *library.Repo, page, perPage int) ([]*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("listing hooks for repo %s from the database", r.GetFullName()) - - // variable to store query results - h := new([]database.Hook) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableHook). - Raw(dml.ListRepoHooks, r.GetID(), perPage, offset). - Scan(h).Error - - // variable we want to return - hooks := []*library.Hook{} - // iterate through all query results - for _, hook := range *h { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := hook - - // convert query result to library type - hooks = append(hooks, tmp.ToLibrary()) - } - - return hooks, err -} diff --git a/database/postgres/hook_list_test.go b/database/postgres/hook_list_test.go deleted file mode 100644 index a48b73cdd..000000000 --- a/database/postgres/hook_list_test.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetHookList(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookOne.SetWebhookID(1) - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookTwo.SetWebhookID(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListHooks).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Hook - }{ - { - failure: false, - want: []*library.Hook{_hookOne, _hookTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetHookList() - - if test.failure { - if err == nil { - t.Errorf("GetHookList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetHookList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetHookList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetRepoHookList(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookOne.SetWebhookID(1) - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookTwo.SetWebhookID(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListRepoHooks, 1, 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1). - AddRow(2, 1, 2, 2, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Hook - }{ - { - failure: false, - want: []*library.Hook{_hookOne, _hookTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetRepoHookList(_repo, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetRepoHookList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoHookList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoHookList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/hook_test.go b/database/postgres/hook_test.go deleted file mode 100644 index 3d7098953..000000000 --- a/database/postgres/hook_test.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetHook(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepoHook, 1, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Hook - }{ - { - failure: false, - want: _hook, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetHook(1, _repo) - - if test.failure { - if err == nil { - t.Errorf("GetHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetHook returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetHook is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetLastHook(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectLastRepoHook, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "source_id", "created", "host", "event", "event_action", "branch", "error", "status", "link", "webhook_id"}, - ).AddRow(1, 1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", 0, "", "", "", "", "", "", "", 1) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Hook - }{ - { - failure: false, - want: _hook, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetLastHook(_repo) - - if test.failure { - if err == nil { - t.Errorf("GetLastHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastHook returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastHook is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateHook(t *testing.T) { - // setup types - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "hooks" ("repo_id","build_id","number","source_id","created","host","event","event_action","branch","error","status","link","webhook_id","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateHook(_hook) - - if test.failure { - if err == nil { - t.Errorf("CreateHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateHook returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateHook(t *testing.T) { - // setup types - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "hooks" SET "repo_id"=$1,"build_id"=$2,"number"=$3,"source_id"=$4,"created"=$5,"host"=$6,"event"=$7,"event_action"=$8,"branch"=$9,"error"=$10,"status"=$11,"link"=$12,"webhook_id"=$13 WHERE "id" = $14`). - WithArgs(1, 1, 1, "c8da1302-07d6-11ea-882f-4893bca275b8", nil, nil, nil, nil, nil, nil, nil, nil, 1, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateHook(_hook) - - if test.failure { - if err == nil { - t.Errorf("UpdateHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateHook returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteHook(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.DeleteHook, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteHook(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteHook returned err: %v", err) - } - } -} - -// testHook is a test helper function to create a -// library Hook type with all fields set to their -// zero values. -func testHook() *library.Hook { - i := 0 - i64 := int64(0) - str := "" - - return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - EventAction: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, - WebhookID: &i64, - } -} diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 04d844675..a4793ca56 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -9,6 +9,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" @@ -45,6 +46,8 @@ type ( Postgres *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService + hook.HookService // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService @@ -149,6 +152,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { return nil, nil, err } + _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -243,12 +248,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the hooks table - err = c.Postgres.Exec(ddl.CreateHookTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableHook, err) - } - // create the logs table err = c.Postgres.Exec(ddl.CreateLogTable).Error if err != nil { @@ -305,12 +304,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the hooks_repo_id index for the hooks table - err = c.Postgres.Exec(ddl.CreateHookRepoIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %w", constants.TableHook, err) - } - // create the logs_build_id index for the logs table err = c.Postgres.Exec(ddl.CreateLogBuildIDIndex).Error if err != nil { @@ -342,6 +335,18 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error + // create the database agnostic hook service + // + // https://pkg.go.dev/github.com/go-vela/server/database/hook#New + c.HookService, err = hook.New( + hook.WithClient(c.Postgres), + hook.WithLogger(c.Logger), + hook.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic pipeline service // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index ec80173f1..d00c540f3 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" @@ -78,7 +79,6 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateHookTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -89,12 +89,14 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the hook queries + _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -168,7 +170,6 @@ func TestPostgres_createTables(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateHookTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -215,7 +216,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateHookRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -257,6 +257,9 @@ func TestPostgres_createServices(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() + // ensure the mock expects the hook queries + _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/service.go b/database/service.go index b6c4b140c..01ab1cf58 100644 --- a/database/service.go +++ b/database/service.go @@ -5,6 +5,7 @@ package database import ( + "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" @@ -72,32 +73,9 @@ type Service interface { // deletes a build by unique ID. DeleteBuild(int64) error - // Hook Database Interface Functions - - // GetHook defines a function that - // gets a webhook by number and repo ID. - GetHook(int, *library.Repo) (*library.Hook, error) - // GetLastHook defines a function that - // gets the last hook by repo ID. - GetLastHook(*library.Repo) (*library.Hook, error) - // GetHookList defines a function that gets - // a list of all webhooks. - GetHookList() ([]*library.Hook, error) - // GetRepoHookList defines a function that - // gets a list of webhooks by repo ID. - GetRepoHookList(*library.Repo, int, int) ([]*library.Hook, error) - // GetRepoHookCount defines a function that - // gets the count of webhooks by repo ID. - GetRepoHookCount(*library.Repo) (int64, error) - // CreateHook defines a function that - // creates a new webhook. - CreateHook(*library.Hook) error - // UpdateHook defines a function that - // updates a webhook. - UpdateHook(*library.Hook) error - // DeleteHook defines a function that - // deletes a webhook by unique ID. - DeleteHook(int64) error + // HookService provides the interface for functionality + // related to hooks stored in the database. + hook.HookService // Log Database Interface Functions diff --git a/database/sqlite/build.go b/database/sqlite/build.go index a0c47067d..974f619b0 100644 --- a/database/sqlite/build.go +++ b/database/sqlite/build.go @@ -18,8 +18,6 @@ import ( ) // GetBuild gets a build by number and repo ID from the database. -// -//nolint:dupl // ignore similar code with hook func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "build": number, @@ -68,8 +66,6 @@ func (c *client) GetBuildByID(id int64) (*library.Build, error) { } // GetLastBuild gets the last build by repo ID from the database. -// -//nolint:dupl // ignore similar code with hook func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), diff --git a/database/sqlite/ddl/hook.go b/database/sqlite/ddl/hook.go deleted file mode 100644 index 4e320132e..000000000 --- a/database/sqlite/ddl/hook.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateHookTable represents a query to - // create the hooks table for Vela. - CreateHookTable = ` -CREATE TABLE -IF NOT EXISTS -hooks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - source_id TEXT, - created INTEGER, - host TEXT, - event TEXT, - event_action TEXT, - branch TEXT, - error TEXT, - status TEXT, - link TEXT, - webhook_id INTEGER, - UNIQUE(repo_id, build_id) -); -` - - // CreateHookRepoIDIndex represents a query to create an - // index on the hooks table for the repo_id column. - CreateHookRepoIDIndex = ` -CREATE INDEX -IF NOT EXISTS -hooks_repo_id -ON hooks (repo_id); -` -) diff --git a/database/sqlite/dml/hook.go b/database/sqlite/dml/hook.go deleted file mode 100644 index b06d79ad5..000000000 --- a/database/sqlite/dml/hook.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListHooks represents a query to - // list all webhooks in the database. - ListHooks = ` -SELECT * -FROM hooks; -` - - // ListRepoHooks represents a query to list - // all webhooks for a repo_id in the database. - ListRepoHooks = ` -SELECT * -FROM hooks -WHERE repo_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectRepoHookCount represents a query to select - // the count of webhooks for a repo_id in the database. - SelectRepoHookCount = ` -SELECT count(*) as count -FROM hooks -WHERE repo_id = ?; -` - - // SelectRepoHook represents a query to select - // a webhook for a repo_id in the database. - SelectRepoHook = ` -SELECT * -FROM hooks -WHERE repo_id = ? -AND number = ? -LIMIT 1; -` - - // SelectLastRepoHook represents a query to select - // the last hook for a repo_id in the database. - SelectLastRepoHook = ` -SELECT * -FROM hooks -WHERE repo_id = ? -ORDER BY number DESC -LIMIT 1; -` - - // DeleteHook represents a query to - // remove a webhook from the database. - DeleteHook = ` -DELETE -FROM hooks -WHERE id = ?; -` -) diff --git a/database/sqlite/hook.go b/database/sqlite/hook.go deleted file mode 100644 index 0dda61b79..000000000 --- a/database/sqlite/hook.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetHook gets a hook by number and repo ID from the database. -// -//nolint:dupl // ignore similar code with build -func (c *client) GetHook(number int, r *library.Repo) (*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "hook": number, - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting hook %s/%d from the database", r.GetFullName(), number) - - // variable to store query results - h := new(database.Hook) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableHook). - Raw(dml.SelectRepoHook, r.GetID(), number). - Scan(h) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return h.ToLibrary(), result.Error -} - -// GetLastHook gets the last hook by repo ID from the database. -// -//nolint:dupl // ignore similar code with build -func (c *client) GetLastHook(r *library.Repo) (*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting last hook for repo %s from the database", r.GetFullName()) - - // variable to store query results - h := new(database.Hook) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableHook). - Raw(dml.SelectLastRepoHook, r.GetID()). - Scan(h) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return h.ToLibrary(), result.Error -} - -// CreateHook creates a new hook in the database. -func (c *client) CreateHook(h *library.Hook) error { - c.Logger.WithFields(logrus.Fields{ - "hook": h.GetNumber(), - }).Tracef("creating hook %d in the database", h.GetNumber()) - - // cast to database type - hook := database.HookFromLibrary(h) - - // validate the necessary fields are populated - err := hook.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableHook). - Create(hook).Error -} - -// UpdateHook updates a hook in the database. -func (c *client) UpdateHook(h *library.Hook) error { - c.Logger.WithFields(logrus.Fields{ - "hook": h.GetNumber(), - }).Tracef("updating hook %d in the database", h.GetNumber()) - - // cast to database type - hook := database.HookFromLibrary(h) - - // validate the necessary fields are populated - err := hook.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableHook). - Save(hook).Error -} - -// DeleteHook deletes a hook by unique ID from the database. -func (c *client) DeleteHook(id int64) error { - c.Logger.Tracef("deleting hook %d in the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableHook). - Exec(dml.DeleteHook, id).Error -} diff --git a/database/sqlite/hook_count_test.go b/database/sqlite/hook_count_test.go deleted file mode 100644 index c640b9610..000000000 --- a/database/sqlite/hook_count_test.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the hook table - err = _database.Sqlite.Exec(ddl.CreateHookTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableHook, err) - } -} - -func TestSqlite_Client_GetRepoHookCount(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookOne.SetWebhookID(1) - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookTwo.SetWebhookID(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - // create the hooks in the database - err := _database.CreateHook(_hookOne) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - - err = _database.CreateHook(_hookTwo) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - - got, err := _database.GetRepoHookCount(_repo) - - if test.failure { - if err == nil { - t.Errorf("GetRepoHookCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoHookCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoHookCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/hook_list.go b/database/sqlite/hook_list.go deleted file mode 100644 index ca388254b..000000000 --- a/database/sqlite/hook_list.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetHookList gets a list of all hooks from the database. -func (c *client) GetHookList() ([]*library.Hook, error) { - c.Logger.Trace("listing hooks from the database") - - // variable to store query results - h := new([]database.Hook) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableHook). - Raw(dml.ListHooks). - Scan(h).Error - - // variable we want to return - hooks := []*library.Hook{} - // iterate through all query results - for _, hook := range *h { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := hook - - // convert query result to library type - hooks = append(hooks, tmp.ToLibrary()) - } - - return hooks, err -} - -// GetRepoHookList gets a list of hooks by repo ID from the database. -func (c *client) GetRepoHookList(r *library.Repo, page, perPage int) ([]*library.Hook, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("listing hooks for repo %s from the database", r.GetFullName()) - - // variable to store query results - h := new([]database.Hook) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableHook). - Raw(dml.ListRepoHooks, r.GetID(), perPage, offset). - Scan(h).Error - - // variable we want to return - hooks := []*library.Hook{} - // iterate through all query results - for _, hook := range *h { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := hook - - // convert query result to library type - hooks = append(hooks, tmp.ToLibrary()) - } - - return hooks, err -} diff --git a/database/sqlite/hook_list_test.go b/database/sqlite/hook_list_test.go deleted file mode 100644 index 9c4784193..000000000 --- a/database/sqlite/hook_list_test.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the hook table - err = _database.Sqlite.Exec(ddl.CreateHookTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableHook, err) - } -} - -func TestSqlite_Client_GetHookList(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookOne.SetWebhookID(1) - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookTwo.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Hook - }{ - { - failure: false, - want: []*library.Hook{_hookOne, _hookTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - for _, hook := range test.want { - // create the hook in the database - err := _database.CreateHook(hook) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - } - - got, err := _database.GetHookList() - - if test.failure { - if err == nil { - t.Errorf("GetHookList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetHookList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetHookList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetRepoHookList(t *testing.T) { - // setup types - _hookOne := testHook() - _hookOne.SetID(1) - _hookOne.SetRepoID(1) - _hookOne.SetBuildID(1) - _hookOne.SetNumber(1) - _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookOne.SetWebhookID(1) - - _hookTwo := testHook() - _hookTwo.SetID(2) - _hookTwo.SetRepoID(1) - _hookTwo.SetBuildID(2) - _hookTwo.SetNumber(2) - _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hookTwo.SetWebhookID(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Hook - }{ - { - failure: false, - want: []*library.Hook{_hookTwo, _hookOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - for _, hook := range test.want { - // create the hook in the database - err := _database.CreateHook(hook) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - } - - got, err := _database.GetRepoHookList(_repo, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetRepoHookList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoHookList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoHookList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/hook_test.go b/database/sqlite/hook_test.go deleted file mode 100644 index a577db4f1..000000000 --- a/database/sqlite/hook_test.go +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetHook(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Hook - }{ - { - failure: false, - want: _hook, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the hook in the database - err := _database.CreateHook(test.want) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - } - - got, err := _database.GetHook(1, _repo) - - // cleanup the hooks table - _ = _database.Sqlite.Exec("DELETE FROM hooks;") - - if test.failure { - if err == nil { - t.Errorf("GetHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetHook returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetHook is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetLastHook(t *testing.T) { - // setup types - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Hook - }{ - { - failure: false, - want: _hook, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the hook in the database - err := _database.CreateHook(test.want) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - } - - got, err := _database.GetLastHook(_repo) - - // cleanup the hooks table - _ = _database.Sqlite.Exec("DELETE FROM hooks;") - - if test.failure { - if err == nil { - t.Errorf("GetLastHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastHook returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastHook is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateHook(t *testing.T) { - // setup types - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - err := _database.CreateHook(_hook) - - if test.failure { - if err == nil { - t.Errorf("CreateHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateHook returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateHook(t *testing.T) { - // setup types - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - // create the hook in the database - err := _database.CreateHook(_hook) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - - err = _database.UpdateHook(_hook) - - if test.failure { - if err == nil { - t.Errorf("UpdateHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateHook returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteHook(t *testing.T) { - // setup types - _hook := testHook() - _hook.SetID(1) - _hook.SetRepoID(1) - _hook.SetBuildID(1) - _hook.SetNumber(1) - _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") - _hook.SetWebhookID(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the hooks table - defer _database.Sqlite.Exec("delete from hooks;") - - // create the hook in the database - err := _database.CreateHook(_hook) - if err != nil { - t.Errorf("unable to create test hook: %v", err) - } - - err = _database.DeleteHook(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteHook should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteHook returned err: %v", err) - } - } -} - -// testHook is a test helper function to create a -// library Hook type with all fields set to their -// zero values. -func testHook() *library.Hook { - i := 0 - i64 := int64(0) - str := "" - - return &library.Hook{ - ID: &i64, - RepoID: &i64, - BuildID: &i64, - Number: &i, - SourceID: &str, - Created: &i64, - Host: &str, - Event: &str, - EventAction: &str, - Branch: &str, - Error: &str, - Status: &str, - Link: &str, - WebhookID: &i64, - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 1c2afcd2d..d89a0ee2f 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/sqlite/ddl" @@ -44,6 +45,8 @@ type ( Sqlite *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService + hook.HookService // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService @@ -233,12 +236,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the hooks table - err = c.Sqlite.Exec(ddl.CreateHookTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableHook, err) - } - // create the logs table err = c.Sqlite.Exec(ddl.CreateLogTable).Error if err != nil { @@ -295,12 +292,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the hooks_repo_id index for the hooks table - err = c.Sqlite.Exec(ddl.CreateHookRepoIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create hooks_repo_id index for the %s table: %w", constants.TableHook, err) - } - // create the logs_build_id index for the logs table err = c.Sqlite.Exec(ddl.CreateLogBuildIDIndex).Error if err != nil { @@ -332,6 +323,18 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error + // create the database agnostic hook service + // + // https://pkg.go.dev/github.com/go-vela/server/database/hook#New + c.HookService, err = hook.New( + hook.WithClient(c.Sqlite), + hook.WithLogger(c.Logger), + hook.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic pipeline service // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New From 204a90605a83fe2e6f55a87f1d90a06d6e4251fb Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Mon, 20 Feb 2023 16:10:50 -0600 Subject: [PATCH 154/298] enhance(repo): customizable default events for new repos (#758) * chore: add another test case for substitute * show failing behavior * refactor both substitute tests * remove todo * address feedback * add import that goland removed * goimports * enhance(repo): customizable default events for new repos * remove default push * goimports --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> Co-authored-by: Jordan Brockopp --- api/repo.go | 17 ++++++- cmd/vela-server/main.go | 6 +++ cmd/vela-server/server.go | 1 + cmd/vela-server/validate.go | 13 +++++ router/middleware/default_repo_events.go | 18 +++++++ router/middleware/default_repo_events_test.go | 49 +++++++++++++++++++ 6 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 router/middleware/default_repo_events.go create mode 100644 router/middleware/default_repo_events_test.go diff --git a/api/repo.go b/api/repo.go index ccb0ffa81..375bb11fa 100644 --- a/api/repo.go +++ b/api/repo.go @@ -77,6 +77,7 @@ func CreateRepo(c *gin.Context) { defaultBuildLimit := c.Value("defaultBuildLimit").(int64) defaultTimeout := c.Value("defaultTimeout").(int64) maxBuildLimit := c.Value("maxBuildLimit").(int64) + defaultRepoEvents := c.Value("defaultRepoEvents").([]string) // capture body from API request input := new(library.Repo) @@ -161,8 +162,20 @@ func CreateRepo(c *gin.Context) { if !input.GetAllowPull() && !input.GetAllowPush() && !input.GetAllowDeploy() && !input.GetAllowTag() && !input.GetAllowComment() { - // default event to push - r.SetAllowPush(true) + for _, event := range defaultRepoEvents { + switch event { + case constants.EventPull: + r.SetAllowPull(true) + case constants.EventPush: + r.SetAllowPush(true) + case constants.EventDeploy: + r.SetAllowDeploy(true) + case constants.EventTag: + r.SetAllowTag(true) + case constants.EventComment: + r.SetAllowComment(true) + } + } } else { r.SetAllowComment(input.GetAllowComment()) r.SetAllowDeploy(input.GetAllowDeploy()) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index f011261d4..0dbe038fa 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -112,6 +112,12 @@ func main() { Usage: "override default build timeout (minutes)", Value: constants.BuildTimeoutDefault, }, + &cli.StringSliceFlag{ + EnvVars: []string{"VELA_DEFAULT_REPO_EVENTS"}, + Name: "default-repo-events", + Usage: "override default events for newly activated repositories", + Value: cli.NewStringSlice(constants.EventPush), + }, // Security Flags &cli.DurationFlag{ EnvVars: []string{"VELA_ACCESS_TOKEN_DURATION", "ACCESS_TOKEN_DURATION"}, diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 114639501..d12338b2a 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -100,6 +100,7 @@ func server(c *cli.Context) error { middleware.WebhookValidation(!c.Bool("vela-disable-webhook-validation")), middleware.SecureCookie(c.Bool("vela-enable-secure-cookie")), middleware.Worker(c.Duration("worker-active-interval")), + middleware.DefaultRepoEvents(c.StringSlice("default-repo-events")), ) addr, err := url.Parse(c.String("server-addr")) diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index 70b06d90d..a29b4dcf1 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -6,6 +6,7 @@ package main import ( "fmt" + "github.com/go-vela/types/constants" "strings" "github.com/sirupsen/logrus" @@ -78,6 +79,18 @@ func validateCore(c *cli.Context) error { return fmt.Errorf("max-build-limit (VELA_MAX_BUILD_LIMIT) flag must be greater than 0") } + for _, event := range c.StringSlice("default-repo-events") { + switch event { + case constants.EventPull: + case constants.EventPush: + case constants.EventDeploy: + case constants.EventTag: + case constants.EventComment: + default: + return fmt.Errorf("default-repo-events (VELA_DEFAULT_REPO_EVENTS) has the unsupported value of %s", event) + } + } + return nil } diff --git a/router/middleware/default_repo_events.go b/router/middleware/default_repo_events.go new file mode 100644 index 000000000..65e5ed5b0 --- /dev/null +++ b/router/middleware/default_repo_events.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +// DefaultRepoEvents is a middleware function that attaches the defaultRepoEvents +// to enable the server to override the default repo event. +func DefaultRepoEvents(defaultRepoEvents []string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("defaultRepoEvents", defaultRepoEvents) + c.Next() + } +} diff --git a/router/middleware/default_repo_events_test.go b/router/middleware/default_repo_events_test.go new file mode 100644 index 000000000..83cfc1703 --- /dev/null +++ b/router/middleware/default_repo_events_test.go @@ -0,0 +1,49 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/go-vela/types/constants" + + "github.com/gin-gonic/gin" +) + +func TestMiddleware_DefaultRepoEvents(t *testing.T) { + // setup types + var got []string + + want := []string{constants.EventPush} + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil) + + // setup mock server + engine.Use(DefaultRepoEvents(want)) + engine.GET("/health", func(c *gin.Context) { + got = c.Value("defaultRepoEvents").([]string) + + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("DefaultRepoEvents returned %v, want %v", resp.Code, http.StatusOK) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("DefaultRepoEvents is %v, want %v", got, want) + } +} From 343d53ec6be882b0c8e0ea734623d70a789982fc Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:19:32 -0600 Subject: [PATCH 155/298] feat(clone-image): make clone image configurable (#755) Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- cmd/vela-server/main.go | 24 ++++++----- cmd/vela-server/validate.go | 4 ++ compiler/native/clone.go | 6 +-- compiler/native/clone_test.go | 8 +++- compiler/native/compile_test.go | 45 ++++++++++++--------- compiler/native/native.go | 5 +++ router/middleware/pipeline/pipeline_test.go | 5 ++- 7 files changed, 61 insertions(+), 36 deletions(-) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 0dbe038fa..24192ac79 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -75,6 +75,12 @@ func main() { Name: "vela-secret", Usage: "secret used for server <-> agent communication", }, + &cli.StringFlag{ + EnvVars: []string{"VELA_CLONE_IMAGE"}, + Name: "clone-image", + Usage: "the clone image to use for the injected clone step", + Value: "target/vela-git:v0.7.0@sha256:c2e8794556d6debceeaa2c82ff3cc9e8e6ed045b723419e3ff050409f25cc258", + }, &cli.StringSliceFlag{ EnvVars: []string{"VELA_REPO_ALLOWLIST"}, Name: "vela-repo-allowlist", @@ -84,9 +90,8 @@ func main() { &cli.BoolFlag{ EnvVars: []string{"VELA_DISABLE_WEBHOOK_VALIDATION"}, Name: "vela-disable-webhook-validation", - - Usage: "determines whether or not webhook validation is disabled. useful for local development.", - Value: false, + Usage: "determines whether or not webhook validation is disabled. useful for local development.", + Value: false, }, &cli.BoolFlag{ EnvVars: []string{"VELA_ENABLE_SECURE_COOKIE"}, @@ -155,22 +160,19 @@ func main() { &cli.StringFlag{ EnvVars: []string{"VELA_MODIFICATION_SECRET", "MODIFICATION_SECRET"}, Name: "modification-secret", - - Usage: "modification secret, used by compiler, secret to allow connectivity between compiler and modification endpoint", + Usage: "modification secret, used by compiler, secret to allow connectivity between compiler and modification endpoint", }, &cli.DurationFlag{ EnvVars: []string{"VELA_MODIFICATION_TIMEOUT", "MODIFICATION_TIMEOUT"}, Name: "modification-timeout", - - Usage: "modification timeout, used by compiler, duration that the modification http request will timeout after", - Value: 8 * time.Second, + Usage: "modification timeout, used by compiler, duration that the modification http request will timeout after", + Value: 8 * time.Second, }, &cli.IntFlag{ EnvVars: []string{"VELA_MODIFICATION_RETRIES", "MODIFICATION_RETRIES"}, Name: "modification-retries", - - Usage: "modification retries, used by compiler, number of http requires that the modification http request will fail after", - Value: 5, + Usage: "modification retries, used by compiler, number of http requires that the modification http request will fail after", + Value: 5, }, &cli.DurationFlag{ EnvVars: []string{"VELA_WORKER_ACTIVE_INTERVAL", "WORKER_ACTIVE_INTERVAL"}, diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index a29b4dcf1..1de402e2a 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -47,6 +47,10 @@ func validateCore(c *cli.Context) error { return fmt.Errorf("server-addr (VELA_ADDR or VELA_HOST) flag must not have trailing slash") } + if len(c.String("clone-image")) == 0 { + return fmt.Errorf("clone-image (VELA_CLONE_IMAGE) flag is not properly configured") + } + if len(c.String("vela-secret")) == 0 { return fmt.Errorf("vela-secret (VELA_SECRET) flag is not properly configured") } diff --git a/compiler/native/clone.go b/compiler/native/clone.go index 08cfb3193..ffc14393a 100644 --- a/compiler/native/clone.go +++ b/compiler/native/clone.go @@ -10,8 +10,6 @@ import ( ) const ( - // default image for clone process. - cloneImage = "target/vela-git:v0.5.1" // default name for clone stage. cloneStageName = "clone" // default name for clone step. @@ -34,7 +32,7 @@ func (c *client) CloneStage(p *yaml.Build) (*yaml.Build, error) { Steps: yaml.StepSlice{ &yaml.Step{ Detach: false, - Image: cloneImage, + Image: c.CloneImage, Name: cloneStepName, Privileged: false, Pull: constants.PullNotPresent, @@ -67,7 +65,7 @@ func (c *client) CloneStep(p *yaml.Build) (*yaml.Build, error) { // create new clone step clone := &yaml.Step{ Detach: false, - Image: cloneImage, + Image: c.CloneImage, Name: cloneStepName, Privileged: false, Pull: constants.PullNotPresent, diff --git a/compiler/native/clone_test.go b/compiler/native/clone_test.go index 890efc267..f481ee4c3 100644 --- a/compiler/native/clone_test.go +++ b/compiler/native/clone_test.go @@ -13,9 +13,12 @@ import ( "github.com/urfave/cli/v2" ) +const defaultCloneImage = "target/vela-git:latest" + func TestNative_CloneStage(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) str := "foo" @@ -53,7 +56,7 @@ func TestNative_CloneStage(t *testing.T) { Name: "clone", Steps: yaml.StepSlice{ &yaml.Step{ - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Pull: "not_present", }, @@ -113,6 +116,7 @@ func TestNative_CloneStage(t *testing.T) { func TestNative_CloneStep(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) str := "foo" @@ -142,7 +146,7 @@ func TestNative_CloneStep(t *testing.T) { Version: "v1", Steps: yaml.StepSlice{ &yaml.Step{ - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Pull: "not_present", }, diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index d2d7df7ec..e6f93f6d6 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -37,6 +37,7 @@ import ( func TestNative_Compile_StagesPipeline(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -135,7 +136,7 @@ func TestNative_Compile_StagesPipeline(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: cloneEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -415,6 +416,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { func TestNative_Compile_StepsPipeline(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -495,7 +497,7 @@ func TestNative_Compile_StepsPipeline(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: cloneEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -616,6 +618,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -712,7 +715,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -879,6 +882,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -965,7 +969,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1107,6 +1111,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName(t *testi set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1158,7 +1163,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName(t *testi ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1225,6 +1230,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName_Inline(t set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1276,7 +1282,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName_Inline(t ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: setupEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1395,6 +1401,7 @@ func TestNative_Compile_Clone(t *testing.T) { set := flag.NewFlagSet("test", 0) set.Bool("github-driver", true, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1475,7 +1482,7 @@ func TestNative_Compile_Clone(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1584,6 +1591,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { set := flag.NewFlagSet("test", 0) set.Bool("github-driver", true, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1632,7 +1640,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1677,7 +1685,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultGoEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1722,7 +1730,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { ID: "step___0_clone", Directory: "/vela/src/foo//", Environment: defaultStarlarkEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -1910,7 +1918,7 @@ func Test_client_modifyConfig(t *testing.T) { }, &yaml.Step{ Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Pull: "not_present", }, @@ -1943,7 +1951,7 @@ func Test_client_modifyConfig(t *testing.T) { }, &yaml.Step{ Environment: environment(nil, m, nil, nil), - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Pull: "not_present", }, @@ -2152,6 +2160,7 @@ func Test_Compile_Inline(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.String("clone-image", defaultCloneImage, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -2232,7 +2241,7 @@ func Test_Compile_Inline(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: initEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", @@ -2378,7 +2387,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Environment: initEnv, Name: "clone", - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Number: 2, Pull: "not_present", }, @@ -2486,7 +2495,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Environment: initEnv, Name: "clone", - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Number: 2, Pull: "not_present", }, @@ -2583,7 +2592,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Environment: initEnv, Name: "clone", - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Number: 2, Pull: "not_present", }, @@ -2658,7 +2667,7 @@ func Test_Compile_Inline(t *testing.T) { Directory: "/vela/src/foo//", Environment: testEnv, Name: "clone", - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Number: 2, Pull: "not_present", }, @@ -2711,7 +2720,7 @@ func Test_Compile_Inline(t *testing.T) { ID: "__0_clone_clone", Directory: "/vela/src/foo//", Environment: golangEnv, - Image: "target/vela-git:v0.5.1", + Image: defaultCloneImage, Name: "clone", Number: 2, Pull: "not_present", diff --git a/compiler/native/native.go b/compiler/native/native.go index 2e9d90357..e7e549b58 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -31,6 +31,7 @@ type client struct { PrivateGithub registry.Service UsePrivateGithub bool ModificationService ModificationConfig + CloneImage string build *library.Build comment string @@ -66,6 +67,9 @@ func New(ctx *cli.Context) (*client, error) { c.Github = github + // set the clone image to use for the injected clone step + c.CloneImage = ctx.String("clone-image") + if ctx.Bool("github-driver") { logrus.Tracef("setting up Private GitHub Client for %s", ctx.String("github-url")) // setup private github service @@ -104,6 +108,7 @@ func (c *client) Duplicate() compiler.Engine { cc.PrivateGithub = c.PrivateGithub cc.UsePrivateGithub = c.UsePrivateGithub cc.ModificationService = c.ModificationService + cc.CloneImage = c.CloneImage return cc } diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index e8fff08ff..573d2ae0a 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -251,7 +251,10 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { t.Errorf("unable to create access token: %v", err) } - comp, err := native.New(cli.NewContext(nil, flag.NewFlagSet("test", 0), nil)) + set := flag.NewFlagSet("test", 0) + set.String("clone-image", "target/vela-git:latest", "doc") + + comp, err := native.New(cli.NewContext(nil, set, nil)) if err != nil { t.Errorf("unable to create compiler: %v", err) } From bff8352d3020d3c4ab255222a636eb88286a5c3a Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:44:38 -0700 Subject: [PATCH 156/298] feat(auth): build token implementation (#765) * feat(build_tokens): server changes for build token implementation * go mod fixes and re-add publish workflow * edit publish workflow * yaml tabs * update doc.go * new types + linter * api spec updates to use token type * Update internal/token/compose.go Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> * gofmt --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/authenticate.go | 47 +- api/build.go | 96 +- api/secret.go | 4 +- api/token.go | 13 +- api/user.go | 36 +- cmd/vela-server/main.go | 27 +- cmd/vela-server/server.go | 3 +- cmd/vela-server/token.go | 30 + cmd/vela-server/validate.go | 17 +- database/user/table.go | 4 +- docker-compose.yml | 1 + go.mod | 4 +- go.sum | 8 +- internal/token/compose.go | 75 ++ internal/token/compose_test.go | 80 ++ internal/token/manager.go | 28 + internal/token/mint.go | 89 ++ internal/token/parse.go | 62 ++ internal/token/parse_test.go | 299 +++++ internal/token/refresh.go | 43 + internal/token/refresh_test.go | 127 +++ mock/server/authentication.go | 6 +- mock/server/build.go | 32 + mock/server/server.go | 1 + router/build.go | 5 +- router/log.go | 6 +- router/middleware/auth/auth.go | 31 + router/middleware/auth/auth_test.go | 85 ++ router/middleware/{token => auth}/doc.go | 4 +- router/middleware/claims/claims.go | 58 + router/middleware/claims/claims_test.go | 279 +++++ router/middleware/claims/context.go | 39 + router/middleware/claims/context_test.go | 110 ++ router/middleware/claims/doc.go | 12 + router/middleware/perm/perm.go | 173 ++- router/middleware/perm/perm_test.go | 1093 ++++++++++++++++--- router/middleware/pipeline/pipeline_test.go | 28 +- router/middleware/token/token.go | 215 ---- router/middleware/token/token_test.go | 541 --------- router/middleware/token_manager.go | 20 + router/middleware/token_manager_test.go | 53 + router/middleware/user/user.go | 24 +- router/middleware/user/user_test.go | 104 +- router/router.go | 3 +- router/service.go | 4 +- router/step.go | 4 +- router/worker.go | 4 +- 47 files changed, 2978 insertions(+), 1049 deletions(-) create mode 100644 cmd/vela-server/token.go create mode 100644 internal/token/compose.go create mode 100644 internal/token/compose_test.go create mode 100644 internal/token/manager.go create mode 100644 internal/token/mint.go create mode 100644 internal/token/parse.go create mode 100644 internal/token/parse_test.go create mode 100644 internal/token/refresh.go create mode 100644 internal/token/refresh_test.go create mode 100644 router/middleware/auth/auth.go create mode 100644 router/middleware/auth/auth_test.go rename router/middleware/{token => auth}/doc.go (80%) create mode 100644 router/middleware/claims/claims.go create mode 100644 router/middleware/claims/claims_test.go create mode 100644 router/middleware/claims/context.go create mode 100644 router/middleware/claims/context_test.go create mode 100644 router/middleware/claims/doc.go delete mode 100644 router/middleware/token/token.go delete mode 100644 router/middleware/token/token_test.go create mode 100644 router/middleware/token_manager.go create mode 100644 router/middleware/token_manager_test.go diff --git a/api/authenticate.go b/api/authenticate.go index 0a518b697..6d89d7611 100644 --- a/api/authenticate.go +++ b/api/authenticate.go @@ -5,18 +5,17 @@ package api import ( - "encoding/base64" "fmt" "net/http" "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/internal/token" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" "github.com/go-vela/types" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -47,7 +46,7 @@ import ( // Set-Cookie: // type: string // schema: -// "$ref": "#/definitions/Login" +// "$ref": "#/definitions/Token" // '307': // description: Redirected for authentication // '401': @@ -65,6 +64,8 @@ import ( func Authenticate(c *gin.Context) { var err error + tm := c.MustGet("token-manager").(*token.Manager) + // capture the OAuth state if present oAuthState := c.Request.FormValue("state") @@ -102,30 +103,15 @@ func Authenticate(c *gin.Context) { u, err := database.FromContext(c).GetUserForName(newUser.GetName()) // create a new user account if len(u.GetName()) == 0 || err != nil { - // create unique id for the user - uid, err := uuid.NewRandom() - if err != nil { - retErr := fmt.Errorf("unable to create UID for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - // create the user account u := new(library.User) u.SetName(newUser.GetName()) u.SetToken(newUser.GetToken()) - u.SetHash( - base64.StdEncoding.EncodeToString( - []byte(uid.String()), - ), - ) u.SetActive(true) u.SetAdmin(false) // compose jwt tokens for user - rt, at, err := token.Compose(c, u) + rt, at, err := tm.Compose(c, u) if err != nil { retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) @@ -148,7 +134,7 @@ func Authenticate(c *gin.Context) { } // return the jwt access token - c.JSON(http.StatusOK, library.Login{Token: &at}) + c.JSON(http.StatusOK, library.Token{Token: &at}) return } @@ -158,7 +144,7 @@ func Authenticate(c *gin.Context) { u.SetActive(true) // compose jwt tokens for user - rt, at, err := token.Compose(c, u) + rt, at, err := tm.Compose(c, u) if err != nil { retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) @@ -181,7 +167,7 @@ func Authenticate(c *gin.Context) { } // return the user with their jwt access token - c.JSON(http.StatusOK, library.Login{Token: &at}) + c.JSON(http.StatusOK, library.Token{Token: &at}) } // swagger:operation GET /authenticate/web authenticate GetAuthenticateTypeWeb @@ -289,7 +275,7 @@ func AuthenticateType(c *gin.Context) { // '200': // description: Successfully authenticated // schema: -// "$ref": "#/definitions/Login" +// "$ref": "#/definitions/Token" // '401': // description: Unable to authenticate // schema: @@ -325,8 +311,15 @@ func AuthenticateToken(c *gin.Context) { // We don't need refresh token for this scenario // We only need access token and are configured based on the config defined - m := c.MustGet("metadata").(*types.Metadata) - at, err := token.CreateAccessToken(u, m.Vela.AccessTokenDuration) + tm := c.MustGet("token-manager").(*token.Manager) + + // mint token options for access token + amto := &token.MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: tm.UserAccessTokenDuration, + } + at, err := tm.MintToken(amto) if err != nil { retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) @@ -335,5 +328,5 @@ func AuthenticateToken(c *gin.Context) { } // return the user with their jwt access token - c.JSON(http.StatusOK, library.Login{Token: &at}) + c.JSON(http.StatusOK, library.Token{Token: &at}) } diff --git a/api/build.go b/api/build.go index c31c5d5c2..5be0c08d6 100644 --- a/api/build.go +++ b/api/build.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. @@ -14,6 +14,8 @@ import ( "strings" "time" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/compiler" @@ -1899,3 +1901,95 @@ func CancelBuild(c *gin.Context) { c.JSON(http.StatusOK, b) } + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/token builds GetBuildToken +// +// Get a build token +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved build token +// schema: +// "$ref": "#/definitions/Token" +// '400': +// description: Bad request +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to generate build token +// schema: +// "$ref": "#/definitions/Error" + +// GetBuildToken represents the API handler to generate a build token. +func GetBuildToken(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + cl := claims.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": cl.Subject, + }).Infof("generating build token for build %s/%d", r.GetFullName(), b.GetNumber()) + + // if build is not in a pending state, then a build token should not be needed - bad request + if !strings.EqualFold(b.GetStatus(), constants.StatusPending) { + retErr := fmt.Errorf("unable to mint build token: build is not in pending state") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // retrieve token manager from context + tm := c.MustGet("token-manager").(*token.Manager) + + // set expiration to repo timeout plus configurable buffer + exp := (time.Duration(r.GetTimeout()) * time.Minute) + tm.BuildTokenBufferDuration + + // set mint token options + bmto := &token.MintTokenOpts{ + Hostname: cl.Subject, + BuildID: b.GetID(), + Repo: r.GetFullName(), + TokenType: constants.WorkerBuildTokenType, + TokenDuration: exp, + } + + // mint token + bt, err := tm.MintToken(bmto) + if err != nil { + retErr := fmt.Errorf("unable to generate build token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, library.Token{Token: &bt}) +} diff --git a/api/secret.go b/api/secret.go index c23bd7010..6e1534d01 100644 --- a/api/secret.go +++ b/api/secret.go @@ -12,6 +12,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/secret" @@ -485,6 +486,7 @@ func GetSecrets(c *gin.Context) { // GetSecret gets a secret from the provided secrets service. func GetSecret(c *gin.Context) { // capture middleware values + cl := claims.Retrieve(c) u := user.Retrieve(c) e := util.PathParameter(c, "engine") t := util.PathParameter(c, "type") @@ -533,7 +535,7 @@ func GetSecret(c *gin.Context) { } // only allow workers to access the full secret with the value - if u.GetAdmin() && u.GetName() == "vela-worker" { + if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { c.JSON(http.StatusOK, secret) return diff --git a/api/token.go b/api/token.go index 1225f149f..87a49288a 100644 --- a/api/token.go +++ b/api/token.go @@ -8,7 +8,8 @@ import ( "fmt" "net/http" - "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/auth" "github.com/go-vela/server/util" "github.com/go-vela/types/library" @@ -29,7 +30,7 @@ import ( // '200': // description: Successfully refreshed a token // schema: -// "$ref": "#/definitions/Login" +// "$ref": "#/definitions/Token" // '401': // description: Unauthorized // schema: @@ -41,7 +42,7 @@ func RefreshAccessToken(c *gin.Context) { // capture the refresh token // TODO: move this into token package and do it internally // since we are already passsing context - rt, err := token.RetrieveRefreshToken(c.Request) + rt, err := auth.RetrieveRefreshToken(c.Request) if err != nil { retErr := fmt.Errorf("refresh token error: %w", err) @@ -50,8 +51,10 @@ func RefreshAccessToken(c *gin.Context) { return } + tm := c.MustGet("token-manager").(*token.Manager) + // validate the refresh token and return a new access token - newAccessToken, err := token.Refresh(c, rt) + newAccessToken, err := tm.Refresh(c, rt) if err != nil { retErr := fmt.Errorf("unable to refresh token: %w", err) @@ -60,5 +63,5 @@ func RefreshAccessToken(c *gin.Context) { return } - c.JSON(http.StatusOK, library.Login{Token: &newAccessToken}) + c.JSON(http.StatusOK, library.Token{Token: &newAccessToken}) } diff --git a/api/user.go b/api/user.go index 37c66d82d..c73fe17e4 100644 --- a/api/user.go +++ b/api/user.go @@ -5,19 +5,17 @@ package api import ( - "encoding/base64" "fmt" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/internal/token" "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" - "github.com/google/uuid" "github.com/sirupsen/logrus" ) @@ -658,7 +656,7 @@ func DeleteUser(c *gin.Context) { // '200': // description: Successfully created a token for the current user // schema: -// "$ref": "#/definitions/Login" +// "$ref": "#/definitions/Token" // '503': // description: Unable to create a token for the current user // schema: @@ -666,6 +664,8 @@ func DeleteUser(c *gin.Context) { // CreateToken represents the API handler to create // a user token in the configured backend. +// +//nolint:dupl // ignore duplicate flag with delete token func CreateToken(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -677,8 +677,10 @@ func CreateToken(c *gin.Context) { "user": u.GetName(), }).Infof("composing token for user %s", u.GetName()) + tm := c.MustGet("token-manager").(*token.Manager) + // compose JWT token for user - rt, at, err := token.Compose(c, u) + rt, at, err := tm.Compose(c, u) if err != nil { retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) @@ -699,7 +701,7 @@ func CreateToken(c *gin.Context) { return } - c.JSON(http.StatusOK, library.Login{Token: &at}) + c.JSON(http.StatusOK, library.Token{Token: &at}) } // swagger:operation DELETE /api/v1/user/token users DeleteToken @@ -723,6 +725,8 @@ func CreateToken(c *gin.Context) { // DeleteToken represents the API handler to revoke // and recreate a user token in the configured backend. +// +//nolint:dupl // ignore duplicate flag with create token func DeleteToken(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -734,24 +738,10 @@ func DeleteToken(c *gin.Context) { "user": u.GetName(), }).Infof("revoking token for user %s", u.GetName()) - // create unique id for the user - uid, err := uuid.NewRandom() - if err != nil { - retErr := fmt.Errorf("unable to create UID for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - u.SetHash( - base64.StdEncoding.EncodeToString( - []byte(uid.String()), - ), - ) + tm := c.MustGet("token-manager").(*token.Manager) // compose JWT token for user - rt, at, err := token.Compose(c, u) + rt, at, err := tm.Compose(c, u) if err != nil { retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) @@ -772,5 +762,5 @@ func DeleteToken(c *gin.Context) { return } - c.JSON(http.StatusOK, library.Login{Token: &at}) + c.JSON(http.StatusOK, library.Token{Token: &at}) } diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 24192ac79..fd1ebfedf 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.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. @@ -75,6 +75,11 @@ func main() { Name: "vela-secret", Usage: "secret used for server <-> agent communication", }, + &cli.StringFlag{ + EnvVars: []string{"VELA_SERVER_PRIVATE_KEY"}, + Name: "vela-server-private-key", + Usage: "private key used for signing tokens", + }, &cli.StringFlag{ EnvVars: []string{"VELA_CLONE_IMAGE"}, Name: "clone-image", @@ -123,19 +128,25 @@ func main() { Usage: "override default events for newly activated repositories", Value: cli.NewStringSlice(constants.EventPush), }, - // Security Flags + // Token Manager Flags &cli.DurationFlag{ - EnvVars: []string{"VELA_ACCESS_TOKEN_DURATION", "ACCESS_TOKEN_DURATION"}, - Name: "access-token-duration", - Usage: "sets the duration of the access token", + EnvVars: []string{"VELA_USER_ACCESS_TOKEN_DURATION", "USER_ACCESS_TOKEN_DURATION"}, + Name: "user-access-token-duration", + Usage: "sets the duration of the user access token", Value: 15 * time.Minute, }, &cli.DurationFlag{ - EnvVars: []string{"VELA_REFRESH_TOKEN_DURATION", "REFRESH_TOKEN_DURATION"}, - Name: "refresh-token-duration", - Usage: "sets the duration of the refresh token", + EnvVars: []string{"VELA_USER_REFRESH_TOKEN_DURATION", "USER_REFRESH_TOKEN_DURATION"}, + Name: "user-refresh-token-duration", + Usage: "sets the duration of the user refresh token", Value: 8 * time.Hour, }, + &cli.DurationFlag{ + EnvVars: []string{"VELA_BUILD_TOKEN_BUFFER_DURATION", "BUILD_TOKEN_BUFFER_DURATION"}, + Name: "build-token-buffer-duration", + Usage: "sets the duration of the buffer for build token expiration based on repo build timeout", + Value: 5 * time.Minute, + }, // Compiler Flags &cli.BoolFlag{ EnvVars: []string{"VELA_COMPILER_GITHUB", "COMPILER_GITHUB"}, diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index d12338b2a..8ecb006e4 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.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. @@ -88,6 +88,7 @@ func server(c *cli.Context) error { middleware.Database(database), middleware.Logger(logrus.StandardLogger(), time.RFC3339), middleware.Metadata(metadata), + middleware.TokenManager(setupTokenManager(c)), middleware.Queue(queue), middleware.RequestVersion, middleware.Secret(c.String("vela-secret")), diff --git a/cmd/vela-server/token.go b/cmd/vela-server/token.go new file mode 100644 index 000000000..eae471373 --- /dev/null +++ b/cmd/vela-server/token.go @@ -0,0 +1,30 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "github.com/golang-jwt/jwt/v4" + + "github.com/sirupsen/logrus" + + "github.com/urfave/cli/v2" + + "github.com/go-vela/server/internal/token" +) + +// helper function to setup the tokenmanager from the CLI arguments. +func setupTokenManager(c *cli.Context) *token.Manager { + logrus.Debug("Creating token manager from CLI configuration") + + tm := &token.Manager{ + PrivateKey: c.String("vela-server-private-key"), + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: c.Duration("user-access-token-duration"), + UserRefreshTokenDuration: c.Duration("user-refresh-token-duration"), + BuildTokenBufferDuration: c.Duration("build-token-buffer-duration"), + } + + return tm +} diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index 1de402e2a..f79512e9e 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.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,9 +6,10 @@ package main import ( "fmt" - "github.com/go-vela/types/constants" "strings" + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) @@ -55,6 +56,10 @@ func validateCore(c *cli.Context) error { return fmt.Errorf("vela-secret (VELA_SECRET) flag is not properly configured") } + if len(c.String("vela-server-private-key")) == 0 { + return fmt.Errorf("vela-server-private-key (VELA_SERVER_PRIVATE_KEY) flag is not properly configured") + } + if len(c.String("webui-addr")) == 0 { logrus.Warn("optional flag webui-addr (VELA_WEBUI_ADDR or VELA_WEBUI_HOST) not set") } else { @@ -71,8 +76,12 @@ func validateCore(c *cli.Context) error { } } - if c.Duration("refresh-token-duration").Seconds() <= c.Duration("access-token-duration").Seconds() { - return fmt.Errorf("refresh-token-duration (VELA_REFRESH_TOKEN_DURATION) must be larger than the access-token-duration (VELA_ACCESS_TOKEN_DURATION)") + if c.Duration("token-manager-user-refresh-token-duration").Seconds() <= c.Duration("token-manager-user-access-token-duration").Seconds() { + return fmt.Errorf("token-manager-user-refresh-token-duration (VELA_TOKEN_MANAGER_USER_REFRESH_TOKEN_DURATION) must be larger than the token-manager-user-access-token-duration (VELA_TOKEN_MANAGER_USER_ACCESS_TOKEN_DURATION)") + } + + if c.Duration("token-manager-build-token-buffer-duration").Seconds() < 0 { + return fmt.Errorf("token-manager-build-token-buffer-duration (VELA_TOKEN_MANAGER_BUILD_TOKEN_BUFFER_DURATION) must not be a negative time value") } if c.Int64("default-build-limit") == 0 { diff --git a/database/user/table.go b/database/user/table.go index 456853770..20a450b84 100644 --- a/database/user/table.go +++ b/database/user/table.go @@ -16,8 +16,8 @@ IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(250), - refresh_token VARCHAR(500), - token VARCHAR(500), + refresh_token VARCHAR(1000), + token VARCHAR(1000), hash VARCHAR(500), favorites VARCHAR(5000), active BOOLEAN, diff --git a/docker-compose.yml b/docker-compose.yml index c3b9501c7..b0d7c5f72 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,6 +37,7 @@ services: VELA_WEBUI_ADDR: 'http://localhost:8888' VELA_LOG_LEVEL: trace VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' + VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' VELA_REFRESH_TOKEN_DURATION: 90m VELA_ACCESS_TOKEN_DURATION: 60m VELA_DISABLE_WEBHOOK_VALIDATION: 'true' diff --git a/go.mod b/go.mod index 86e17605d..240012799 100644 --- a/go.mod +++ b/go.mod @@ -9,12 +9,12 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.23.1 github.com/aws/aws-sdk-go v1.44.161 - github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 + github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/go-vela/types v0.17.0 + github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v44 v44.1.0 diff --git a/go.sum b/go.sum index ab2291f6f..f35038998 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= -github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= +github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 h1:qLN32md48xyTEqw6XEZMyNMre7njm0XXvDrea6NVwOM= +github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396/go.mod h1:AV5wtJnn1/CRaRGlJ8xspkMWfKXV0/pkJVgGleTIrfk= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -161,8 +161,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.17.0 h1:nvKBbNO8BSiLtYPMScT0XWosGqEWX85UKSkkclb2DVA= -github.com/go-vela/types v0.17.0/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 h1:tdjas7NJLWlU2vmETaU36wjbd+zvWPLtznE4uwtnFlw= +github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= diff --git a/internal/token/compose.go b/internal/token/compose.go new file mode 100644 index 000000000..61bea7a32 --- /dev/null +++ b/internal/token/compose.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "net/http" + "net/url" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" +) + +// Compose generates a refresh and access token pair unique +// to the provided user and sets a secure cookie. +// It uses the user's hash to sign the token. to +// guarantee the signature is unique per token. The refresh +// token is returned to store with the user +// in the database. +func (tm *Manager) Compose(c *gin.Context, u *library.User) (string, string, error) { + // grab the metadata from the context to pull in provided + // cookie duration information + m := c.MustGet("metadata").(*types.Metadata) + + // mint token options for refresh token + rmto := MintTokenOpts{ + User: u, + TokenType: constants.UserRefreshTokenType, + TokenDuration: tm.UserRefreshTokenDuration, + } + + // create a refresh token with the provided options + refreshToken, err := tm.MintToken(&rmto) + if err != nil { + return "", "", err + } + + // mint token options for access token + amto := MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: tm.UserAccessTokenDuration, + } + + // create an access token with the provided options + accessToken, err := tm.MintToken(&amto) + if err != nil { + return "", "", err + } + + // parse the address for the backend server + // so we can set it for the cookie domain + addr, err := url.Parse(m.Vela.Address) + if err != nil { + return "", "", err + } + + refreshExpiry := int(tm.UserRefreshTokenDuration.Seconds()) + + // set the SameSite value for the cookie + // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#samesite-attribute + // We set to Lax because we will have links from source provider web UI. + // Setting this to Strict would force a login when navigating via source provider web UI links. + c.SetSameSite(http.SameSiteLaxMode) + // set the cookie with the refresh token as a HttpOnly, Secure cookie + // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#httponly-attribute + // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#secure-attribute + c.SetCookie(constants.RefreshTokenName, refreshToken, refreshExpiry, "/", addr.Hostname(), c.Value("securecookie").(bool), true) + + // return the refresh and access tokens + return refreshToken, accessToken, nil +} diff --git a/internal/token/compose_test.go b/internal/token/compose_test.go new file mode 100644 index 000000000..75f113e77 --- /dev/null +++ b/internal/token/compose_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + + jwt "github.com/golang-jwt/jwt/v4" +) + +func TestToken_Compose(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + d := time.Minute * 5 + now := time.Now() + exp := now.Add(d) + + claims := &Claims{ + IsActive: u.GetActive(), + IsAdmin: u.GetAdmin(), + TokenType: constants.UserAccessTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: u.GetName(), + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(exp), + }, + } + + tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + want, err := tkn.SignedString([]byte(tm.PrivateKey)) + if err != nil { + t.Errorf("Unable to create test token: %v", err) + } + + m := &types.Metadata{ + Vela: &types.Vela{ + AccessTokenDuration: d, + }, + } + + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, _ := gin.CreateTestContext(resp) + context.Set("metadata", m) + context.Set("securecookie", false) + + // run test + _, got, err := tm.Compose(context, u) + if err != nil { + t.Errorf("Compose returned err: %v", err) + } + + if !strings.EqualFold(got, want) { + t.Errorf("Compose is %v, want %v", got, want) + } +} diff --git a/internal/token/manager.go b/internal/token/manager.go new file mode 100644 index 000000000..121e4fa0f --- /dev/null +++ b/internal/token/manager.go @@ -0,0 +1,28 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "time" + + "github.com/golang-jwt/jwt/v4" +) + +type Manager struct { + // PrivateKey key used to sign tokens + PrivateKey string + + // SignMethod method to sign tokens + SignMethod jwt.SigningMethod + + // UserAccessTokenDuration specifies the token duration to use for users + UserAccessTokenDuration time.Duration + + // UserRefreshTokenDuration specifies the token duration for user refresh + UserRefreshTokenDuration time.Duration + + // BuildTokenBufferDuration specifies the additional token duration of build tokens beyond repo timeout + BuildTokenBufferDuration time.Duration +} diff --git a/internal/token/mint.go b/internal/token/mint.go new file mode 100644 index 000000000..e90c0c34f --- /dev/null +++ b/internal/token/mint.go @@ -0,0 +1,89 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "errors" + "fmt" + "time" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/golang-jwt/jwt/v4" +) + +// Claims struct is an extension of the JWT standard claims. It +// includes information about the user. +type Claims struct { + BuildID int64 `json:"build_id"` + IsActive bool `json:"is_active"` + IsAdmin bool `json:"is_admin"` + Repo string `json:"repo"` + TokenType string `json:"token_type"` + jwt.RegisteredClaims +} + +// MintTokenOpts is a type to inform the token minter how to construct +// the token. +type MintTokenOpts struct { + BuildID int64 + Hostname string + Repo string + TokenDuration time.Duration + TokenType string + User *library.User +} + +// MintToken mints a Vela JWT Token given a set of options. +func (tm *Manager) MintToken(mto *MintTokenOpts) (string, error) { + // initialize claims struct + var claims = new(Claims) + + // apply claims based on token type + switch mto.TokenType { + case constants.UserAccessTokenType, constants.UserRefreshTokenType: + if mto.User == nil { + return "", fmt.Errorf("no user provided for user access token") + } + + claims.IsActive = mto.User.GetActive() + claims.IsAdmin = mto.User.GetAdmin() + claims.Subject = mto.User.GetName() + + case constants.WorkerBuildTokenType: + if mto.BuildID == 0 { + return "", errors.New("missing build id for build token") + } + + if len(mto.Repo) == 0 { + return "", errors.New("missing repo for build token") + } + + if len(mto.Hostname) == 0 { + return "", errors.New("missing host name for build token") + } + + claims.BuildID = mto.BuildID + claims.Repo = mto.Repo + claims.Subject = mto.Hostname + + default: + return "", errors.New("invalid token type") + } + + claims.IssuedAt = jwt.NewNumericDate(time.Now()) + claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(mto.TokenDuration)) + claims.TokenType = mto.TokenType + + tk := jwt.NewWithClaims(tm.SignMethod, claims) + + //sign token with configured private signing key + token, err := tk.SignedString([]byte(tm.PrivateKey)) + if err != nil { + return "", fmt.Errorf("unable to sign token: %w", err) + } + + return token, nil +} diff --git a/internal/token/parse.go b/internal/token/parse.go new file mode 100644 index 000000000..dc9b002d3 --- /dev/null +++ b/internal/token/parse.go @@ -0,0 +1,62 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "errors" + + "github.com/golang-jwt/jwt/v4" +) + +// ParseToken scans the signed JWT token as a string and extracts +// the user login from the claims to be looked up in the database. +// This function will return an error for a few different reasons: +// +// * the token signature doesn't match what is expected +// * the token signing method doesn't match what is expected +// * the token is invalid (potentially expired or improper). +func (tm *Manager) ParseToken(token string) (*Claims, error) { + var claims = new(Claims) + + // create a new JWT parser + p := &jwt.Parser{ + // explicitly only allow these signing methods + ValidMethods: []string{jwt.SigningMethodHS256.Name}, + } + + // parse and validate given token + tkn, err := p.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { + var err error + + // extract the claims from the token + claims = t.Claims.(*Claims) + name := claims.Subject + + // check if subject has a value in claims; + // we can save a db lookup attempt + if len(name) == 0 { + return nil, errors.New("no subject defined") + } + + // ParseWithClaims will skip expiration check + // if expiration has default value; + // forcing a check and exiting if not set + if claims.ExpiresAt == nil { + return nil, errors.New("token has no expiration") + } + + return []byte(tm.PrivateKey), err + }) + + if err != nil { + return nil, errors.New("failed parsing: " + err.Error()) + } + + if !tkn.Valid { + return nil, errors.New("invalid token") + } + + return claims, nil +} diff --git a/internal/token/parse_test.go b/internal/token/parse_test.go new file mode 100644 index 000000000..9ee9ce453 --- /dev/null +++ b/internal/token/parse_test.go @@ -0,0 +1,299 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "reflect" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + + jwt "github.com/golang-jwt/jwt/v4" +) + +func TestTokenManager_ParseToken(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + now := time.Now() + + tests := []struct { + TokenType string + Mto *MintTokenOpts + Want *Claims + }{ + { + TokenType: constants.UserAccessTokenType, + Mto: &MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: tm.UserAccessTokenDuration, + }, + Want: &Claims{ + IsActive: u.GetActive(), + IsAdmin: u.GetAdmin(), + TokenType: constants.UserAccessTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: u.GetName(), + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), + }, + }, + }, + { + TokenType: constants.UserRefreshTokenType, + Mto: &MintTokenOpts{ + User: u, + TokenType: constants.UserRefreshTokenType, + TokenDuration: tm.UserRefreshTokenDuration, + }, + Want: &Claims{ + IsActive: u.GetActive(), + IsAdmin: u.GetAdmin(), + TokenType: constants.UserRefreshTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: u.GetName(), + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 30)), + }, + }, + }, + { + TokenType: constants.WorkerBuildTokenType, + Mto: &MintTokenOpts{ + BuildID: 1, + Repo: "foo/bar", + Hostname: "worker", + TokenType: constants.WorkerBuildTokenType, + TokenDuration: time.Minute * 90, + }, + Want: &Claims{ + BuildID: 1, + Repo: "foo/bar", + TokenType: constants.WorkerBuildTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "worker", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 90)), + }, + }, + }, + } + + gin.SetMode(gin.TestMode) + + for _, tt := range tests { + t.Run(tt.TokenType, func(t *testing.T) { + tkn, err := tm.MintToken(tt.Mto) + if err != nil { + t.Errorf("Unable to create token: %v", err) + } + // run test + got, err := tm.ParseToken(tkn) + if err != nil { + t.Errorf("Parse returned err: %v", err) + } + + if !reflect.DeepEqual(got, tt.Want) { + t.Errorf("Parse is %v, want %v", got, tt.Want) + } + }) + } +} + +func TestTokenManager_ParseToken_Error_NoParse(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + // run test + got, err := tm.ParseToken("!@#$%^&*()") + if err == nil { + t.Errorf("Parse should have returned err") + } + + if got != nil { + t.Errorf("Parse is %v, want nil", got) + } +} + +func TestTokenManager_ParseToken_Expired(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: time.Minute * -1, + } + + tkn, err := tm.MintToken(mto) + if err != nil { + t.Errorf("Unable to create token: %v", err) + } + + // run test + _, err = tm.ParseToken(tkn) + if err == nil { + t.Errorf("Parse should return error due to expiration") + } +} + +func TestTokenManager_ParseToken_NoSubject(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + claims := &Claims{ + IsActive: u.GetActive(), + IsAdmin: u.GetAdmin(), + TokenType: constants.UserRefreshTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now()), + }, + } + tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + token, err := tkn.SignedString([]byte(tm.PrivateKey)) + if err != nil { + t.Errorf("Unable to create test token: %v", err) + } + + // run test + got, err := tm.ParseToken(token) + if err == nil { + t.Errorf("Parse should have returned err") + } + + if got != nil { + t.Errorf("Parse is %v, want nil", got) + } +} + +func TestTokenManager_ParseToken_Error_InvalidSignature(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + claims := &Claims{ + IsActive: u.GetActive(), + IsAdmin: u.GetAdmin(), + TokenType: constants.UserAccessTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: u.GetName(), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 1)), + }, + } + tkn := jwt.NewWithClaims(jwt.SigningMethodHS512, claims) + + token, err := tkn.SignedString([]byte(tm.PrivateKey)) + if err != nil { + t.Errorf("Unable to create test token: %v", err) + } + + // run test + got, err := tm.ParseToken(token) + if err == nil { + t.Errorf("Parse should have returned err") + } + + if got != nil { + t.Errorf("Parse is %v, want nil", got) + } +} + +func TestToken_Parse_AccessToken_NoExpiration(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + claims := &Claims{ + TokenType: constants.UserAccessTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "user", + }, + } + tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + token, err := tkn.SignedString([]byte(u.GetHash())) + if err != nil { + t.Errorf("Unable to create test token: %v", err) + } + + // run test + got, err := tm.ParseToken(token) + if err == nil { + t.Errorf("Parse should have returned err") + } + + if got != nil { + t.Errorf("Parse is %v, want nil", got) + } +} diff --git a/internal/token/refresh.go b/internal/token/refresh.go new file mode 100644 index 000000000..8cb69f374 --- /dev/null +++ b/internal/token/refresh.go @@ -0,0 +1,43 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/types/constants" +) + +// Refresh returns a new access token, if the provided refreshToken is valid. +func (tm *Manager) Refresh(c *gin.Context, refreshToken string) (string, error) { + // retrieve claims from token + claims, err := tm.ParseToken(refreshToken) + if err != nil { + return "", err + } + + // look up user in database given claims subject + u, err := database.FromContext(c).GetUserForName(claims.Subject) + if err != nil { + return "", fmt.Errorf("unable to retrieve user %s from database from claims subject: %w", claims.Subject, err) + } + + // options for user access token minting + amto := &MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: tm.UserAccessTokenDuration, + } + + // create a new access token + at, err := tm.MintToken(amto) + if err != nil { + return "", err + } + + return at, nil +} diff --git a/internal/token/refresh_test.go b/internal/token/refresh_test.go new file mode 100644 index 000000000..dda71cb4a --- /dev/null +++ b/internal/token/refresh_test.go @@ -0,0 +1,127 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package token + +import ( + "net/http/httptest" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + jwt "github.com/golang-jwt/jwt/v4" +) + +func TestTokenManager_Refresh(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &MintTokenOpts{ + User: u, + TokenType: constants.UserRefreshTokenType, + TokenDuration: tm.UserRefreshTokenDuration, + } + + rt, err := tm.MintToken(mto) + if err != nil { + t.Errorf("unable to create refresh token") + } + + u.SetRefreshToken(rt) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + // set up context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, _ := gin.CreateTestContext(resp) + context.Set("database", db) + + // run tests + got, err := tm.Refresh(context, rt) + if err != nil { + t.Error("Refresh should not error") + } + + if len(got) == 0 { + t.Errorf("Refresh should have returned an access token") + } +} + +func TestTokenManager_Refresh_Expired(t *testing.T) { + // setup types + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + + tm := &Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &MintTokenOpts{ + User: u, + TokenType: constants.UserRefreshTokenType, + TokenDuration: time.Minute * -1, + } + + rt, err := tm.MintToken(mto) + if err != nil { + t.Errorf("unable to create refresh token") + } + + u.SetRefreshToken(rt) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + // set up context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, _ := gin.CreateTestContext(resp) + context.Set("database", db) + + // run tests + _, err = tm.Refresh(context, rt) + if err == nil { + t.Error("Refresh with expired token should error") + } +} diff --git a/mock/server/authentication.go b/mock/server/authentication.go index 4f9e5055e..e75217565 100644 --- a/mock/server/authentication.go +++ b/mock/server/authentication.go @@ -26,7 +26,7 @@ const ( func getTokenRefresh(c *gin.Context) { data := []byte(TokenRefreshResp) - var body library.Login + var body library.Token _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) @@ -48,7 +48,7 @@ func getAuthenticate(c *gin.Context) { return } - var body library.Login + var body library.Token _ = json.Unmarshal(data, &body) c.SetCookie(constants.RefreshTokenName, "refresh", 2, "/", "", true, true) @@ -68,7 +68,7 @@ func getAuthenticateFromToken(c *gin.Context) { c.AbortWithStatusJSON(http.StatusUnauthorized, types.Error{Message: &err}) } - var body library.Login + var body library.Token _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) diff --git a/mock/server/build.go b/mock/server/build.go index 19f12a950..37809bae4 100644 --- a/mock/server/build.go +++ b/mock/server/build.go @@ -142,6 +142,13 @@ const ( "full_name": "github/octocat" } ]` + + // BuildTokenResp represents a JSON return for requesting a build token + // + //nolint:gosec // not actual credentials + BuildTokenResp = `{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJidWlsZF9pZCI6MSwicmVwbyI6ImZvby9iYXIiLCJzdWIiOiJPY3RvY2F0IiwiaWF0IjoxNTE2MjM5MDIyfQ.hD7gXpaf9acnLBdOBa4GOEa5KZxdzd0ZvK6fGwaN4bc" + }` ) // getBuilds returns mock JSON for a http GET. @@ -305,3 +312,28 @@ func buildQueue(c *gin.Context) { c.JSON(http.StatusOK, body) } + +// buildToken has a param :build returns mock JSON for a http GET. +// +// Pass "0" to :build to test receiving a http 404 response. Pass "2" +// to :build to test receiving a http 400 response. +func buildToken(c *gin.Context) { + b := c.Param("build") + + if strings.EqualFold(b, "0") { + c.AbortWithStatusJSON(http.StatusNotFound, "") + + return + } + + if strings.EqualFold(b, "2") { + c.AbortWithStatusJSON(http.StatusBadRequest, "") + } + + data := []byte(BuildTokenResp) + + var body library.Token + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} diff --git a/mock/server/server.go b/mock/server/server.go index 843a2f591..1b1ebd7c7 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -47,6 +47,7 @@ func FakeHandler() http.Handler { e.POST("/api/v1/repos/:org/:repo/builds", addBuild) e.PUT("/api/v1/repos/:org/:repo/builds/:build", updateBuild) e.DELETE("/api/v1/repos/:org/:repo/builds/:build", removeBuild) + e.GET("/api/v1/repos/:org/:repo/builds/:build/token", buildToken) // mock endpoints for deployment calls e.GET("/api/v1/deployments/:org/:repo", getDeployments) diff --git a/router/build.go b/router/build.go index 153f61ad5..3abf130d9 100644 --- a/router/build.go +++ b/router/build.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. @@ -54,10 +54,11 @@ func BuildHandlers(base *gin.RouterGroup) { { build.POST("", perm.MustWrite(), api.RestartBuild) build.GET("", perm.MustRead(), api.GetBuild) - build.PUT("", perm.MustWrite(), middleware.Payload(), api.UpdateBuild) + build.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateBuild) build.DELETE("", perm.MustPlatformAdmin(), api.DeleteBuild) build.DELETE("/cancel", executors.Establish(), perm.MustWrite(), api.CancelBuild) build.GET("/logs", perm.MustRead(), api.GetBuildLogs) + build.GET("/token", perm.MustWorker(), api.GetBuildToken) // Service endpoints // * Log endpoints diff --git a/router/log.go b/router/log.go index d7e8dc8db..fc7498b48 100644 --- a/router/log.go +++ b/router/log.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. @@ -23,7 +23,7 @@ func LogServiceHandlers(base *gin.RouterGroup) { { logs.POST("", perm.MustAdmin(), api.CreateServiceLog) logs.GET("", perm.MustRead(), api.GetServiceLog) - logs.PUT("", perm.MustWrite(), api.UpdateServiceLog) + logs.PUT("", perm.MustBuildAccess(), api.UpdateServiceLog) logs.DELETE("", perm.MustPlatformAdmin(), api.DeleteServiceLog) } // end of logs endpoints } @@ -41,7 +41,7 @@ func LogStepHandlers(base *gin.RouterGroup) { { logs.POST("", perm.MustAdmin(), api.CreateStepLog) logs.GET("", perm.MustRead(), api.GetStepLog) - logs.PUT("", perm.MustWrite(), api.UpdateStepLog) + logs.PUT("", perm.MustBuildAccess(), api.UpdateStepLog) logs.DELETE("", perm.MustPlatformAdmin(), api.DeleteStepLog) } // end of logs endpoints } diff --git a/router/middleware/auth/auth.go b/router/middleware/auth/auth.go new file mode 100644 index 000000000..76291a3cb --- /dev/null +++ b/router/middleware/auth/auth.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "fmt" + "net/http" + + "github.com/go-vela/types/constants" + + "github.com/golang-jwt/jwt/v4/request" +) + +// RetrieveAccessToken gets the passed in access token from the header in the request. +func RetrieveAccessToken(r *http.Request) (accessToken string, err error) { + return request.AuthorizationHeaderExtractor.ExtractToken(r) +} + +// RetrieveRefreshToken gets the refresh token sent along with the request as a cookie. +func RetrieveRefreshToken(r *http.Request) (string, error) { + refreshToken, err := r.Cookie(constants.RefreshTokenName) + + if refreshToken == nil || len(refreshToken.Value) == 0 { + // cookie will not be sent if it has expired + return "", fmt.Errorf("refresh token expired or not provided") + } + + return refreshToken.Value, err +} diff --git a/router/middleware/auth/auth_test.go b/router/middleware/auth/auth_test.go new file mode 100644 index 000000000..850309c04 --- /dev/null +++ b/router/middleware/auth/auth_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "context" + "fmt" + "net/http" + "strings" + "testing" + + "github.com/go-vela/types/constants" +) + +func TestToken_Retrieve_Refresh(t *testing.T) { + // setup types + want := "fresh" + + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) + request.AddCookie(&http.Cookie{ + Name: constants.RefreshTokenName, + Value: want, + }) + + // run test + got, err := RetrieveRefreshToken(request) + if err != nil { + t.Errorf("Retrieve returned err: %v", err) + } + + if !strings.EqualFold(got, want) { + t.Errorf("Retrieve is %v, want %v", got, want) + } +} + +func TestToken_Retrieve_Access(t *testing.T) { + // setup types + want := "foobar" + + header := fmt.Sprintf("Bearer %s", want) + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) + request.Header.Set("Authorization", header) + + // run test + got, err := RetrieveAccessToken(request) + if err != nil { + t.Errorf("Retrieve returned err: %v", err) + } + + if !strings.EqualFold(got, want) { + t.Errorf("Retrieve is %v, want %v", got, want) + } +} + +func TestToken_Retrieve_Access_Error(t *testing.T) { + // setup types + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) + + // run test + got, err := RetrieveAccessToken(request) + if err == nil { + t.Errorf("Retrieve should have returned err") + } + + if len(got) > 0 { + t.Errorf("Retrieve is %v, want \"\"", got) + } +} + +func TestToken_Retrieve_Refresh_Error(t *testing.T) { + // setup types + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) + + // run test + got, err := RetrieveRefreshToken(request) + if err == nil { + t.Errorf("Retrieve should have returned err") + } + + if len(got) > 0 { + t.Errorf("Retrieve is %v, want \"\"", got) + } +} diff --git a/router/middleware/token/doc.go b/router/middleware/auth/doc.go similarity index 80% rename from router/middleware/token/doc.go rename to router/middleware/auth/doc.go index b4c5a498d..e50ae3a1a 100644 --- a/router/middleware/token/doc.go +++ b/router/middleware/auth/doc.go @@ -8,5 +8,5 @@ // // Usage: // -// import "github.com/go-vela/server/router/middleware/token" -package token +// import "github.com/go-vela/server/router/middleware/auth" +package auth diff --git a/router/middleware/claims/claims.go b/router/middleware/claims/claims.go new file mode 100644 index 000000000..bc0726c7a --- /dev/null +++ b/router/middleware/claims/claims.go @@ -0,0 +1,58 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package claims + +import ( + "net/http" + "strings" + + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/auth" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + + "github.com/gin-gonic/gin" +) + +// Retrieve gets the claims in the given context. +func Retrieve(c *gin.Context) *token.Claims { + return FromContext(c) +} + +// Establish sets the claims in the given context. +func Establish() gin.HandlerFunc { + return func(c *gin.Context) { + claims := new(token.Claims) + + tm := c.MustGet("token-manager").(*token.Manager) + // get the access token from the request + at, err := auth.RetrieveAccessToken(c.Request) + if err != nil { + util.HandleError(c, http.StatusUnauthorized, err) + return + } + + // special handling for workers + secret := c.MustGet("secret").(string) + if strings.EqualFold(at, secret) { + claims.Subject = "vela-worker" + claims.TokenType = constants.ServerWorkerTokenType + ToContext(c, claims) + c.Next() + + return + } + + // parse and validate the token and return the associated the user + claims, err = tm.ParseToken(at) + if err != nil { + util.HandleError(c, http.StatusUnauthorized, err) + return + } + + ToContext(c, claims) + c.Next() + } +} diff --git a/router/middleware/claims/claims_test.go b/router/middleware/claims/claims_test.go new file mode 100644 index 000000000..239c97296 --- /dev/null +++ b/router/middleware/claims/claims_test.go @@ -0,0 +1,279 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package claims + +import ( + "fmt" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" + "time" + + "github.com/go-vela/server/database" + "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/internal/token" + "github.com/golang-jwt/jwt/v4" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + + "github.com/gin-gonic/gin" +) + +func TestClaims_Retrieve(t *testing.T) { + // setup types + now := time.Now() + want := &token.Claims{ + TokenType: constants.UserAccessTokenType, + IsAdmin: false, + IsActive: true, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "octocat", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 1)), + }, + } + + // setup context + gin.SetMode(gin.TestMode) + + context, _ := gin.CreateTestContext(nil) + ToContext(context, want) + + // run test + got := Retrieve(context) + + if got != want { + t.Errorf("Retrieve is %v, want %v", got, want) + } +} + +func TestClaims_Establish(t *testing.T) { + // setup types + user := new(library.User) + user.SetID(1) + user.SetName("foo") + user.SetRefreshToken("fresh") + user.SetToken("bar") + user.SetHash("baz") + user.SetActive(true) + user.SetAdmin(false) + user.SetFavorites([]string{}) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + now := time.Now() + + tests := []struct { + TokenType string + WantClaims *token.Claims + Mto *token.MintTokenOpts + CtxRequest string + Endpoint string + }{ + { + TokenType: constants.UserAccessTokenType, + WantClaims: &token.Claims{ + TokenType: constants.UserAccessTokenType, + IsAdmin: false, + IsActive: true, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "foo", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), + }, + }, + Mto: &token.MintTokenOpts{ + User: user, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + }, + CtxRequest: "/repos/foo/bar/builds/1", + Endpoint: "repos/:org/:repo/builds/:build", + }, + { + TokenType: constants.WorkerBuildTokenType, + WantClaims: &token.Claims{ + TokenType: constants.WorkerBuildTokenType, + BuildID: 1, + Repo: "foo/bar", + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "host", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 35)), + }, + }, + Mto: &token.MintTokenOpts{ + Hostname: "host", + BuildID: 1, + Repo: "foo/bar", + TokenDuration: time.Minute * 35, + TokenType: constants.WorkerBuildTokenType, + }, + CtxRequest: "/repos/foo/bar/builds/1", + Endpoint: "repos/:org/:repo/builds/:build", + }, + { + TokenType: constants.ServerWorkerTokenType, + WantClaims: &token.Claims{ + TokenType: constants.ServerWorkerTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "vela-worker", + }, + }, + CtxRequest: "/repos/foo/bar/builds/1", + Endpoint: "repos/:org/:repo/builds/:build", + }, + } + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(user) + + got := new(token.Claims) + + gin.SetMode(gin.TestMode) + + for _, tt := range tests { + t.Run(tt.TokenType, func(t *testing.T) { + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodPut, tt.CtxRequest, nil) + + var tkn string + + if strings.EqualFold(tt.TokenType, constants.ServerWorkerTokenType) { + tkn = "very-secret" + } else { + tkn, _ = tm.MintToken(tt.Mto) + } + + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // setup context + gin.SetMode(gin.TestMode) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { c.Set("secret", "very-secret") }) + engine.Use(Establish()) + engine.PUT(tt.Endpoint, func(c *gin.Context) { + got = Retrieve(c) + + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusOK) + } + + if !reflect.DeepEqual(got, tt.WantClaims) { + t.Errorf("Establish is %v, want %v", got, tt.WantClaims) + } + + s1.Close() + }) + } +} + +func TestClaims_Establish_NoToken(t *testing.T) { + // setup types + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/workers/host", nil) + + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(Establish()) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusUnauthorized { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusUnauthorized) + } +} + +func TestClaims_Establish_BadToken(t *testing.T) { + // setup types + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/workers/host", nil) + + u := new(library.User) + u.SetID(1) + u.SetName("octocat") + u.SetHash("abc") + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: time.Minute * -1, + TokenType: constants.UserRefreshTokenType, + } + + tkn, _ := tm.MintToken(mto) + + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { c.Set("secret", "very-secret") }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(Establish()) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusUnauthorized { + t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusUnauthorized) + } +} diff --git a/router/middleware/claims/context.go b/router/middleware/claims/context.go new file mode 100644 index 000000000..5e51b2b4f --- /dev/null +++ b/router/middleware/claims/context.go @@ -0,0 +1,39 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package claims + +import ( + "context" + + "github.com/go-vela/server/internal/token" +) + +const key = "claims" + +// Setter defines a context that enables setting values. +type Setter interface { + Set(string, interface{}) +} + +// FromContext returns the Claims associated with this context. +func FromContext(c context.Context) *token.Claims { + value := c.Value(key) + if value == nil { + return nil + } + + cl, ok := value.(*token.Claims) + if !ok { + return nil + } + + return cl +} + +// ToContext adds the Claims to this context if it supports +// the Setter interface. +func ToContext(c Setter, cl *token.Claims) { + c.Set(key, cl) +} diff --git a/router/middleware/claims/context_test.go b/router/middleware/claims/context_test.go new file mode 100644 index 000000000..54713010c --- /dev/null +++ b/router/middleware/claims/context_test.go @@ -0,0 +1,110 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package claims + +import ( + "testing" + "time" + + "github.com/go-vela/server/internal/token" + "github.com/go-vela/types/constants" + "github.com/golang-jwt/jwt/v4" + + "github.com/gin-gonic/gin" +) + +func TestClaims_FromContext(t *testing.T) { + now := time.Now() + want := &token.Claims{ + TokenType: constants.UserAccessTokenType, + IsAdmin: false, + IsActive: true, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "octocat", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 1)), + }, + } + + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, want) + + // run test + got := FromContext(context) + + if got != want { + t.Errorf("FromContext is %v, want %v", got, want) + } +} + +func TestClaims_FromContext_Bad(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, nil) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestClaims_FromContext_WrongType(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, 1) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestClaims_FromContext_Empty(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestClaims_ToContext(t *testing.T) { + // setup types + now := time.Now() + want := &token.Claims{ + TokenType: constants.UserAccessTokenType, + IsAdmin: false, + IsActive: true, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "octocat", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 1)), + }, + } + + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + ToContext(context, want) + + // run test + got := context.Value(key) + + if got != want { + t.Errorf("ToContext is %v, want %v", got, want) + } +} diff --git a/router/middleware/claims/doc.go b/router/middleware/claims/doc.go new file mode 100644 index 000000000..f91ec309c --- /dev/null +++ b/router/middleware/claims/doc.go @@ -0,0 +1,12 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package claims provides the ability for inserting +// token claims resources into or extracting token claims +// resources from the middleware chain for the API. +// +// Usage: +// +// import "github.com/go-vela/server/router/middleware/claims" +package claims diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 0c4c20243..560753ad8 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.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. @@ -11,34 +11,123 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" "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/scm" "github.com/go-vela/server/util" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // MustPlatformAdmin ensures the user has admin access to the platform. func MustPlatformAdmin() gin.HandlerFunc { return func(c *gin.Context) { - u := user.Retrieve(c) + cl := claims.Retrieve(c) // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Debugf("verifying user %s is a platform admin", u.GetName()) + "user": cl.Subject, + }).Debugf("verifying user %s is a platform admin", cl.Subject) + + switch { + case cl.IsAdmin: + return + + default: + if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + "repo": cl.Repo, + "build": cl.BuildID, + }).Warnf("attempted access of admin endpoint with build token from %s", cl.Subject) + } + + retErr := fmt.Errorf("user %s is not a platform admin", cl.Subject) + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + } +} + +// MustWorker ensures the request is coming from an agent. +func MustWorker() gin.HandlerFunc { + return func(c *gin.Context) { + cl := claims.Retrieve(c) + + // global permissions bypass + if cl.IsAdmin { + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + }).Debugf("user %s has platform admin permissions", cl.Subject) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "subject": cl.Subject, + }).Debugf("verifying user %s is a worker", cl.Subject) + // validate claims as worker switch { - case globalPerms(u): + case (strings.EqualFold(cl.Subject, "vela-worker") && strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType)): return default: - retErr := fmt.Errorf("user %s is not a platform admin", u.GetName()) + retErr := fmt.Errorf("user %s is not a worker", cl.Subject) + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + } +} + +// MustBuildAccess ensures the token is a build token for the appropriate build. +func MustBuildAccess() gin.HandlerFunc { + return func(c *gin.Context) { + cl := claims.Retrieve(c) + b := build.Retrieve(c) + + // global permissions bypass + if cl.IsAdmin { + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + }).Debugf("user %s has platform admin permissions", cl.Subject) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "worker": cl.Subject, + }).Debugf("verifying worker %s has a valid build token", cl.Subject) + + // validate token type and match build id in request with build id in token claims + switch cl.TokenType { + case constants.WorkerBuildTokenType: + if b.GetID() == cl.BuildID { + return + } + + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + "repo": cl.Repo, + "build": cl.BuildID, + }).Warnf("build token for build %d attempted to be used for build %d by %s", cl.BuildID, b.GetID(), cl.Subject) + + fallthrough + default: + retErr := fmt.Errorf("invalid token: must provide matching worker build token") util.HandleError(c, http.StatusUnauthorized, retErr) return @@ -49,11 +138,13 @@ func MustPlatformAdmin() gin.HandlerFunc { // MustSecretAdmin ensures the user has admin access to the org, repo or team. func MustSecretAdmin() gin.HandlerFunc { return func(c *gin.Context) { + cl := claims.Retrieve(c) u := user.Retrieve(c) e := util.PathParameter(c, "engine") t := util.PathParameter(c, "type") o := util.PathParameter(c, "org") n := util.PathParameter(c, "name") + s := util.PathParameter(c, "secret") m := c.Request.Method // create log fields from API metadata @@ -82,10 +173,56 @@ func MustSecretAdmin() gin.HandlerFunc { // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields logger := logrus.WithFields(fields) - if globalPerms(u) { + if u.GetAdmin() { return } + // if caller is worker with build token, verify it has access to requested secret + if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { + // split repo full name into org and repo + repoSlice := strings.Split(cl.Repo, "/") + if len(repoSlice) != 2 { + logger.Errorf("unable to parse repo claim in build token") + } + + org := repoSlice[0] + repo := repoSlice[1] + + switch t { + case constants.SecretShared: + return + case constants.SecretOrg: + logger.Debugf("verifying subject %s has token permissions for org %s", cl.Subject, o) + + if strings.EqualFold(org, o) { + return + } + + logger.Warnf("build token for build %s/%d attempted to be used for secret %s/%s by %s", cl.Repo, cl.BuildID, o, s, cl.Subject) + + retErr := fmt.Errorf("subject %s does not have token permissions for the org %s", cl.Subject, o) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + + case constants.SecretRepo: + logger.Debugf("verifying subject %s has token permissions for repo %s/%s", cl.Subject, o, n) + + if strings.EqualFold(org, o) && strings.EqualFold(repo, n) { + return + } + + logger.Warnf("build token for build %s/%d attempted to be used for secret %s/%s/%s by %s", cl.Repo, cl.BuildID, o, n, s, cl.Subject) + + retErr := fmt.Errorf("subject %s does not have token permissions for the repo %s/%s", cl.Subject, o, n) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + } + switch t { case constants.SecretOrg: logger.Debugf("verifying user %s has 'admin' permissions for org %s", u.GetName(), o) @@ -178,7 +315,7 @@ func MustAdmin() gin.HandlerFunc { logger.Debugf("verifying user %s has 'admin' permissions for repo %s", u.GetName(), r.GetFullName()) - if globalPerms(u) { + if u.GetAdmin() { return } @@ -236,7 +373,7 @@ func MustWrite() gin.HandlerFunc { logger.Debugf("verifying user %s has 'write' permissions for repo %s", u.GetName(), r.GetFullName()) - if globalPerms(u) { + if u.GetAdmin() { return } @@ -302,7 +439,7 @@ func MustRead() gin.HandlerFunc { logger.Debugf("verifying user %s has 'read' permissions for repo %s", u.GetName(), r.GetFullName()) - if globalPerms(u) { + if u.GetAdmin() { return } @@ -344,17 +481,3 @@ func MustRead() gin.HandlerFunc { } } } - -// helper function to check if the user is a platform admin. -func globalPerms(user *library.User) bool { - switch { - // Agents have full access to endpoints - case user.GetName() == "vela-worker": - return true - // platform admins have full access to endpoints - case user.GetAdmin(): - return true - } - - return false -} diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 1b560a63a..a47dcef40 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_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. @@ -11,44 +11,726 @@ import ( "testing" "time" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/golang-jwt/jwt/v4" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/router/middleware/user" + "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) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(true) + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + context.Request, _ = http.NewRequest(http.MethodGet, "/admin/users", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup github mock server + engine.GET("/api/v3/user", func(c *gin.Context) { + c.String(http.StatusOK, userPayload) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup client + client, _ := github.NewTest(s.URL) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustPlatformAdmin()) + engine.GET("/admin/users", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustPlatAdmin returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + u := new(library.User) + u.SetID(1) + u.SetName("foo") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(false) + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + context.Request, _ = http.NewRequest(http.MethodGet, "/admin/users", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup github mock server + engine.GET("/api/v3/user", func(c *gin.Context) { + c.String(http.StatusOK, userPayload) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup client + client, _ := github.NewTest(s.URL) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustPlatformAdmin()) + engine.GET("/admin/users", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusUnauthorized { + t.Errorf("MustPlatAdmin returned %v, want %v", resp.Code, http.StatusUnauthorized) + } +} + +func TestPerm_MustWorker(t *testing.T) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) + context.Request.Header.Add("Authorization", fmt.Sprint(secret)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustWorker()) + engine.GET("/test/:org/:repo", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustWorker_PlatAdmin(t *testing.T) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + u := new(library.User) + u.SetID(1) + u.SetName("vela-worker") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(true) + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustWorker()) + engine.GET("/test/:org/:repo", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustWorker_UserNamedVelaWorker(t *testing.T) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + u := new(library.User) + u.SetID(1) + u.SetName("vela-worker") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(false) + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateUser(u) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustWorker()) + engine.GET("/test/:org/:repo", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusUnauthorized { + t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusUnauthorized) + } +} + +func TestPerm_MustBuildAccess(t *testing.T) { + // setup types + secret := "superSecret" + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + BuildID: 1, + Repo: "foo/bar", + TokenDuration: time.Minute * 30, + TokenType: constants.WorkerBuildTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(build.Establish()) + engine.Use(MustBuildAccess()) + engine.GET("/test/:org/:repo/builds/:build", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustBuildAccess returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { + // setup types + secret := "superSecret" + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + u := new(library.User) + u.SetID(1) + u.SetName("admin") + u.SetToken("bar") + u.SetHash("baz") + u.SetAdmin(true) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from users;") + db.Sqlite.Exec("delete from builds;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) + _ = db.CreateUser(u) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(build.Establish()) + engine.Use(MustBuildAccess()) + engine.GET("/test/:org/:repo/builds/:build", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustBuildAccess returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { + // setup types + secret := "superSecret" + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + BuildID: 2, + Repo: "foo/bar", + TokenDuration: time.Minute * 30, + TokenType: constants.WorkerBuildTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/token" - "github.com/go-vela/server/router/middleware/user" - "github.com/go-vela/server/scm" - "github.com/go-vela/server/scm/github" - "github.com/go-vela/types/library" -) + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) -const accessTokenDuration = time.Minute * 15 + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) -func TestPerm_MustPlatformAdmin(t *testing.T) { + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(build.Establish()) + engine.Use(MustBuildAccess()) + engine.GET("/test/:org/:repo/builds/:build", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusUnauthorized { + t.Errorf("MustBuildAccess returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { // setup types secret := "superSecret" - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(true) + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + BuildID: 1, + Repo: "foo/bar", + TokenDuration: time.Minute * 30, + TokenType: constants.WorkerBuildTokenType, + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) // setup database db, _ := sqlite.NewTest() defer func() { + db.Sqlite.Exec("delete from repos;") db.Sqlite.Exec("delete from users;") _sql, _ := db.Sqlite.DB() _sql.Close() }() - _ = db.CreateUser(u) + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/repo/foo/bar/baz", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustSecretAdmin()) + engine.GET("/test/:engine/:type/:org/:name/:secret", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustBuildAccess returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { + // setup types + secret := "superSecret" + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + BuildID: 1, + Repo: "foo/bar", + TokenDuration: time.Minute * 30, + TokenType: constants.WorkerBuildTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -56,27 +738,30 @@ func TestPerm_MustPlatformAdmin(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) - context.Request, _ = http.NewRequest(http.MethodGet, "/admin/users", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + // setup database + db, _ := sqlite.NewTest() - // setup github mock server - engine.GET("/api/v3/user", func(c *gin.Context) { - c.String(http.StatusOK, userPayload) - }) + defer func() { + db.Sqlite.Exec("delete from repos;") + db.Sqlite.Exec("delete from users;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() - s := httptest.NewServer(engine) - defer s.Close() + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) - // setup client - client, _ := github.NewTest(s.URL) + context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/org/foo/*/baz", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) - engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) - engine.Use(MustPlatformAdmin()) - engine.GET("/admin/users", func(c *gin.Context) { + engine.Use(MustSecretAdmin()) + engine.GET("/test/:engine/:type/:org/:name/:secret", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -87,22 +772,44 @@ func TestPerm_MustPlatformAdmin(t *testing.T) { engine.ServeHTTP(context.Writer, context.Request) if resp.Code != http.StatusOK { - t.Errorf("MustPlatAdmin returned %v, want %v", resp.Code, http.StatusOK) + t.Errorf("MustSecretAdmin returned %v, want %v", resp.Code, http.StatusOK) } } -func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { +func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { // setup types secret := "superSecret" - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(false) + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("public") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + BuildID: 1, + Repo: "foo/bar", + TokenDuration: time.Minute * 30, + TokenType: constants.WorkerBuildTokenType, + } - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -114,34 +821,26 @@ func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { db, _ := sqlite.NewTest() defer func() { + db.Sqlite.Exec("delete from repos;") db.Sqlite.Exec("delete from users;") _sql, _ := db.Sqlite.DB() _sql.Close() }() - _ = db.CreateUser(u) + _ = db.CreateRepo(r) + _ = db.CreateBuild(b) - context.Request, _ = http.NewRequest(http.MethodGet, "/admin/users", nil) + context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/shared/foo/*/*", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) - // setup github mock server - engine.GET("/api/v3/user", func(c *gin.Context) { - c.String(http.StatusOK, userPayload) - }) - - s := httptest.NewServer(engine) - defer s.Close() - - // setup client - client, _ := github.NewTest(s.URL) - // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) - engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) - engine.Use(MustPlatformAdmin()) - engine.GET("/admin/users", func(c *gin.Context) { + engine.Use(MustSecretAdmin()) + engine.GET("/test/:engine/:type/:org/:name/:secret", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -151,8 +850,8 @@ func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { // run test engine.ServeHTTP(context.Writer, context.Request) - if resp.Code != http.StatusUnauthorized { - t.Errorf("MustPlatAdmin returned %v, want %v", resp.Code, http.StatusUnauthorized) + if resp.Code != http.StatusOK { + t.Errorf("MustSecretAdmin returned %v, want %v", resp.Code, http.StatusOK) } } @@ -160,6 +859,13 @@ func TestPerm_MustAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -176,7 +882,13 @@ func TestPerm_MustAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -216,8 +928,10 @@ func TestPerm_MustAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -241,6 +955,13 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -257,7 +978,13 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(true) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -297,8 +1024,10 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -322,6 +1051,13 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -338,7 +1074,13 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -378,8 +1120,10 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -403,6 +1147,13 @@ func TestPerm_MustWrite(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -419,7 +1170,13 @@ func TestPerm_MustWrite(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -459,8 +1216,10 @@ func TestPerm_MustWrite(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -484,6 +1243,13 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -500,7 +1266,13 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(true) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -540,8 +1312,10 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -565,6 +1339,13 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -581,7 +1362,13 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -621,8 +1408,10 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -646,6 +1435,13 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -662,7 +1458,13 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -702,8 +1504,10 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -727,6 +1531,13 @@ func TestPerm_MustRead(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -743,7 +1554,13 @@ func TestPerm_MustRead(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -783,8 +1600,10 @@ func TestPerm_MustRead(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -808,6 +1627,13 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -824,7 +1650,13 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(true) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -864,8 +1696,10 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -889,6 +1723,13 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -905,7 +1746,13 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -945,8 +1792,10 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -970,6 +1819,13 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -986,7 +1842,13 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -1026,8 +1888,10 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -1051,6 +1915,13 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -1067,7 +1938,13 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -1107,8 +1984,10 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -1132,6 +2011,13 @@ func TestPerm_MustRead_NotRead(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -1148,7 +2034,13 @@ func TestPerm_MustRead_NotRead(t *testing.T) { u.SetHash("baz") u.SetAdmin(false) - tok, _ := token.CreateAccessToken(u, accessTokenDuration) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + tok, _ := tm.MintToken(mto) // setup context gin.SetMode(gin.TestMode) @@ -1188,8 +2080,10 @@ func TestPerm_MustRead_NotRead(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(user.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) @@ -1209,57 +2103,6 @@ func TestPerm_MustRead_NotRead(t *testing.T) { } } -func TestPerm_globalPerms(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(false) - - // run test - got := globalPerms(u) - - if got { - t.Errorf("globalPerms returned %v, want false", got) - } -} - -func TestPerm_globalPerms_Agent(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("vela-worker") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(false) - - // run test - got := globalPerms(u) - - if !got { - t.Errorf("globalPerms returned %v, want true", got) - } -} - -func TestPerm_globalPerms_Admin(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(true) - - // run test - got := globalPerms(u) - - if !got { - t.Errorf("globalPerms returned %v, want true", got) - } -} - const permAdminPayload = ` { "permission": "admin", diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index 573d2ae0a..090a3b3f5 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_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. @@ -18,14 +18,17 @@ import ( "github.com/go-vela/server/compiler/native" "github.com/go-vela/server/database" "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/token" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/scm/github" "github.com/go-vela/types" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" + "github.com/golang-jwt/jwt/v4" "github.com/urfave/cli/v2" ) @@ -210,6 +213,13 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + r := new(library.Repo) r.SetID(1) r.SetUserID(1) @@ -246,9 +256,15 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { }, } - tok, err := token.CreateAccessToken(u, time.Minute*15) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + at, err := tm.MintToken(mto) if err != nil { - t.Errorf("unable to create access token: %v", err) + t.Errorf("unable to mint user access token: %v", err) } set := flag.NewFlagSet("test", 0) @@ -278,7 +294,7 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/pipelines/foo/bar/148afb5bdc41ad69bf22588491333f7cf71135163", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", at)) // setup github mock server engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { @@ -295,10 +311,12 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("metadata", m) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { compiler.WithGinContext(c, comp) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(org.Establish()) engine.Use(repo.Establish()) engine.Use(user.Establish()) diff --git a/router/middleware/token/token.go b/router/middleware/token/token.go deleted file mode 100644 index 7bd9ae257..000000000 --- a/router/middleware/token/token.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package token - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/types" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - - "github.com/golang-jwt/jwt/v4" - "github.com/golang-jwt/jwt/v4/request" - "github.com/sirupsen/logrus" -) - -//lint:ignore SA1019 ignore deprecated -type Claims struct { - IsAdmin bool `json:"is_admin"` - IsActive bool `json:"is_active"` - jwt.StandardClaims -} - -// Compose generates an refresh and access token pair unique -// to the provided user and sets a secure cookie. -// It uses a secret hash, which is unique for every user. -// The hash signs the token to guarantee the signature is unique -// per token. The refresh token is returned to store with the user -// in the database. -func Compose(c *gin.Context, u *library.User) (string, string, error) { - // grab the metadata from the context to pull in provided - // cookie duration information - m := c.MustGet("metadata").(*types.Metadata) - - // create a refresh with the provided duration - refreshToken, refreshExpiry, err := CreateRefreshToken(u, m.Vela.RefreshTokenDuration) - if err != nil { - return "", "", err - } - - // create an access token with the provided duration - accessToken, err := CreateAccessToken(u, m.Vela.AccessTokenDuration) - if err != nil { - return "", "", err - } - - // parse the address for the backend server - // so we can set it for the cookie domain - addr, err := url.Parse(m.Vela.Address) - if err != nil { - return "", "", err - } - - // set the SameSite value for the cookie - // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#samesite-attribute - // We set to Lax because we will have links from source provider web UI. - // Setting this to Strict would force a login when navigating via source provider web UI links. - c.SetSameSite(http.SameSiteLaxMode) - // set the cookie with the refresh token as a HttpOnly, Secure cookie - // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#httponly-attribute - // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#secure-attribute - c.SetCookie(constants.RefreshTokenName, refreshToken, refreshExpiry, "/", addr.Hostname(), c.Value("securecookie").(bool), true) - - // return the refresh and access tokens - return refreshToken, accessToken, nil -} - -// Parse scans the signed JWT token as a string and extracts -// the user login from the claims to be looked up in the database. -// This function will return an error for a few different reasons: -// -// * the token signature doesn't match what is expected -// * the token signing method doesn't match what is expected -// * the token is invalid (potentially expired or improper). -func Parse(t string, db database.Service) (*library.User, error) { - u := new(library.User) - - // create a new JWT parser - p := &jwt.Parser{ - // explicitly only allow these signing methods - ValidMethods: []string{jwt.SigningMethodHS256.Name}, - } - - // parse the signed JWT token string - // parse also validates the claims and token by default. - _, err := p.ParseWithClaims(t, &Claims{}, func(token *jwt.Token) (interface{}, error) { - var err error - - // extract the claims from the token - claims := token.Claims.(*Claims) - name := claims.Subject - - // check if subject has a value in claims; - // we can save a db lookup attempt - if len(name) == 0 { - return nil, errors.New("no subject defined") - } - - // ParseWithClaims will skip expiration check - // if expiration has default value; - // forcing a check and exiting if not set - if claims.ExpiresAt == 0 { - return nil, errors.New("token has no expiration") - } - - // lookup the user in the database - logrus.WithField("user", name).Debugf("reading user %s", name) - u, err = db.GetUserForName(name) - return []byte(u.GetHash()), err - }) - - // there will be an error if we're not able to parse - // the token, eg. due to expiration, invalid signature, etc - if err != nil { - return nil, fmt.Errorf("invalid token provided for %s: %w", u.GetName(), err) - } - - return u, nil -} - -// RetrieveAccessToken gets the passed in access token from the header in the request. -func RetrieveAccessToken(r *http.Request) (accessToken string, err error) { - accessToken, err = request.AuthorizationHeaderExtractor.ExtractToken(r) - - return -} - -// RetrieveRefreshToken gets the refresh token sent along with the request as a cookie. -func RetrieveRefreshToken(r *http.Request) (string, error) { - refreshToken, err := r.Cookie(constants.RefreshTokenName) - - if refreshToken == nil || len(refreshToken.Value) == 0 { - // cookie will not be sent if it has expired - return "", fmt.Errorf("refresh token expired or not provided") - } - - return refreshToken.Value, err -} - -// CreateAccessToken creates a new access token for the given user and duration. -// -//nolint:staticcheck // ignore deprecated -func CreateAccessToken(u *library.User, d time.Duration) (string, error) { - now := time.Now() - exp := now.Add(d) - - claims := &Claims{ - IsActive: u.GetActive(), - IsAdmin: u.GetAdmin(), - StandardClaims: jwt.StandardClaims{ - Subject: u.GetName(), - IssuedAt: now.Unix(), - ExpiresAt: exp.Unix(), - }, - } - - t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - token, err := t.SignedString([]byte(u.GetHash())) - if err != nil { - return "", err - } - - return token, nil -} - -// CreateCreateRefreshToken creates a new refresh token for the given user and duration. -// -//nolint:staticcheck // ignore deprecated -func CreateRefreshToken(u *library.User, d time.Duration) (string, int, error) { - exp := time.Now().Add(d) - - claims := jwt.StandardClaims{} - claims.Subject = u.GetName() - claims.ExpiresAt = exp.Unix() - - t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - refreshToken, err := t.SignedString([]byte(u.GetHash())) - if err != nil { - return "", 0, err - } - - return refreshToken, int(d.Seconds()), nil -} - -// Refresh returns a new access token, if the provided refreshToken is valid. -func Refresh(c *gin.Context, refreshToken string) (string, error) { - // get the metadata - m := c.MustGet("metadata").(*types.Metadata) - // get a reference to the database - db := database.FromContext(c) - - // parse (which also validates) the token - u, err := Parse(refreshToken, db) - if err != nil { - return "", err - } - - // create a new access token - at, err := CreateAccessToken(u, m.Vela.AccessTokenDuration) - if err != nil { - return "", err - } - - return at, nil -} diff --git a/router/middleware/token/token_test.go b/router/middleware/token/token_test.go deleted file mode 100644 index 6add3ed56..000000000 --- a/router/middleware/token/token_test.go +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -//nolint:staticcheck // ignore deprecated -package token - -import ( - "context" - "fmt" - "net/http" - "net/http/httptest" - "reflect" - "strings" - "testing" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/types" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - - jwt "github.com/golang-jwt/jwt/v4" -) - -func TestToken_Compose(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - d := time.Minute * 5 - now := time.Now() - exp := now.Add(d) - - claims := &Claims{ - IsActive: u.GetActive(), - IsAdmin: u.GetAdmin(), - StandardClaims: jwt.StandardClaims{ - Subject: u.GetName(), - IssuedAt: now.Unix(), - ExpiresAt: exp.Unix(), - }, - } - - tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - want, err := tkn.SignedString([]byte(u.GetHash())) - if err != nil { - t.Errorf("Unable to create test token: %v", err) - } - - m := &types.Metadata{ - Vela: &types.Vela{ - AccessTokenDuration: d, - }, - } - - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, _ := gin.CreateTestContext(resp) - context.Set("metadata", m) - context.Set("securecookie", false) - - // run test - _, got, err := Compose(context, u) - if err != nil { - t.Errorf("Compose returned err: %v", err) - } - - if !strings.EqualFold(got, want) { - t.Errorf("Compose is %v, want %v", got, want) - } -} - -func TestToken_Parse(t *testing.T) { - // setup types - want := new(library.User) - want.SetID(1) - want.SetName("foo") - want.SetRefreshToken("fresh") - want.SetToken("bar") - want.SetHash("baz") - want.SetActive(false) - want.SetAdmin(false) - want.SetFavorites([]string{}) - - m := &types.Metadata{ - Vela: &types.Vela{ - AccessTokenDuration: time.Minute * 5, - }, - } - - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, _ := gin.CreateTestContext(resp) - context.Set("metadata", m) - - tkn, err := CreateAccessToken(want, time.Minute*5) - if err != nil { - t.Errorf("Unable to create token: %v", err) - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(want) - - // run test - got, err := Parse(tkn, db) - if err != nil { - t.Errorf("Parse returned err: %v", err) - } - - if !reflect.DeepEqual(got, want) { - t.Errorf("Parse is %v, want %v", got, want) - } -} - -func TestToken_Parse_Error_NoParse(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // run test - got, err := Parse("!@#$%^&*()", db) - if err == nil { - t.Errorf("Parse should have returned err") - } - - if got != nil { - t.Errorf("Parse is %v, want nil", got) - } -} - -func TestToken_Parse_Error_InvalidSignature(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - claims := &Claims{ - IsActive: u.GetActive(), - IsAdmin: u.GetAdmin(), - StandardClaims: jwt.StandardClaims{ - Subject: u.GetName(), - }, - } - tkn := jwt.NewWithClaims(jwt.SigningMethodHS512, claims) - - token, err := tkn.SignedString([]byte(u.GetHash())) - if err != nil { - t.Errorf("Unable to create test token: %v", err) - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // run test - got, err := Parse(token, db) - if err == nil { - t.Errorf("Parse should have returned err") - } - - if got != nil { - t.Errorf("Parse is %v, want nil", got) - } -} - -func TestToken_Parse_AccessToken_Expired(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - tkn, err := CreateAccessToken(u, time.Minute*-1) - if err != nil { - t.Errorf("Unable to create token: %v", err) - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // run test - _, err = Parse(tkn, db) - if err == nil { - t.Errorf("Parse should return error due to expiration") - } -} - -func TestToken_Parse_AccessToken_NoSubject(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - claims := &Claims{ - IsActive: u.GetActive(), - IsAdmin: u.GetAdmin(), - StandardClaims: jwt.StandardClaims{ - ExpiresAt: 42, - }, - } - tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - token, err := tkn.SignedString([]byte(u.GetHash())) - if err != nil { - t.Errorf("Unable to create test token: %v", err) - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // run test - got, err := Parse(token, db) - if err == nil { - t.Errorf("Parse should have returned err") - } - - if got != nil { - t.Errorf("Parse is %v, want nil", got) - } -} - -func TestToken_Parse_AccessToken_NoExpiration(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - claims := &Claims{ - IsActive: u.GetActive(), - IsAdmin: u.GetAdmin(), - StandardClaims: jwt.StandardClaims{ - Subject: u.GetName(), - }, - } - tkn := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - token, err := tkn.SignedString([]byte(u.GetHash())) - if err != nil { - t.Errorf("Unable to create test token: %v", err) - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // run test - got, err := Parse(token, db) - if err == nil { - t.Errorf("Parse should have returned err") - } - - if got != nil { - t.Errorf("Parse is %v, want nil", got) - } -} - -func TestToken_Refresh(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - d := time.Minute * 5 - - m := &types.Metadata{ - Vela: &types.Vela{ - AccessTokenDuration: d, - }, - } - - rt, _, err := CreateRefreshToken(u, d) - if err != nil { - t.Errorf("unable to create refresh token") - } - - u.SetRefreshToken(rt) - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // set up context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, _ := gin.CreateTestContext(resp) - context.Set("metadata", m) - context.Set("database", db) - - // run tests - got, err := Refresh(context, rt) - if err != nil { - t.Error("Refresh should not error") - } - - if len(got) == 0 { - t.Errorf("Refresh should have returned an access token") - } -} - -func TestToken_Refresh_Expired(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - d := time.Minute * -1 - - m := &types.Metadata{ - Vela: &types.Vela{ - AccessTokenDuration: d, - }, - } - - rt, _, err := CreateRefreshToken(u, d) - if err != nil { - t.Errorf("unable to create refresh token") - } - - u.SetRefreshToken(rt) - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // set up context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, _ := gin.CreateTestContext(resp) - context.Set("metadata", m) - context.Set("database", db) - - // run tests - _, err = Refresh(context, rt) - if err == nil { - t.Error("Refresh with expired token should error") - } -} - -func TestToken_Refresh_TokenMissing(t *testing.T) { - // setup types - u := new(library.User) - u.SetID(1) - u.SetName("foo") - u.SetToken("bar") - u.SetHash("baz") - - d := time.Minute * -1 - - m := &types.Metadata{ - Vela: &types.Vela{ - AccessTokenDuration: d, - }, - } - - rt, _, err := CreateRefreshToken(u, d) - if err != nil { - t.Errorf("unable to create refresh token") - } - - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(u) - - // set up context - gin.SetMode(gin.TestMode) - - resp := httptest.NewRecorder() - context, _ := gin.CreateTestContext(resp) - context.Set("metadata", m) - context.Set("database", db) - - // run tests - _, err = Refresh(context, rt) - if err == nil { - t.Error("Refresh with token that doesn't exist in database should error") - } -} - -func TestToken_Retrieve_Refresh(t *testing.T) { - // setup types - want := "fresh" - - request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) - request.AddCookie(&http.Cookie{ - Name: constants.RefreshTokenName, - Value: want, - }) - - // run test - got, err := RetrieveRefreshToken(request) - if err != nil { - t.Errorf("Retrieve returned err: %v", err) - } - - if !strings.EqualFold(got, want) { - t.Errorf("Retrieve is %v, want %v", got, want) - } -} - -func TestToken_Retrieve_Access(t *testing.T) { - // setup types - want := "foobar" - - header := fmt.Sprintf("Bearer %s", want) - request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) - request.Header.Set("Authorization", header) - - // run test - got, err := RetrieveAccessToken(request) - if err != nil { - t.Errorf("Retrieve returned err: %v", err) - } - - if !strings.EqualFold(got, want) { - t.Errorf("Retrieve is %v, want %v", got, want) - } -} - -func TestToken_Retrieve_Access_Error(t *testing.T) { - // setup types - request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) - - // run test - got, err := RetrieveAccessToken(request) - if err == nil { - t.Errorf("Retrieve should have returned err") - } - - if len(got) > 0 { - t.Errorf("Retrieve is %v, want \"\"", got) - } -} - -func TestToken_Retrieve_Refresh_Error(t *testing.T) { - // setup types - request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", nil) - - // run test - got, err := RetrieveRefreshToken(request) - if err == nil { - t.Errorf("Retrieve should have returned err") - } - - if len(got) > 0 { - t.Errorf("Retrieve is %v, want \"\"", got) - } -} diff --git a/router/middleware/token_manager.go b/router/middleware/token_manager.go new file mode 100644 index 000000000..0d8d78108 --- /dev/null +++ b/router/middleware/token_manager.go @@ -0,0 +1,20 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "github.com/gin-gonic/gin" + + "github.com/go-vela/server/internal/token" +) + +// TokenManager is a middleware function that attaches the token manager +// to the context of every http.Request. +func TokenManager(m *token.Manager) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("token-manager", m) + c.Next() + } +} diff --git a/router/middleware/token_manager_test.go b/router/middleware/token_manager_test.go new file mode 100644 index 000000000..2ba6e23f2 --- /dev/null +++ b/router/middleware/token_manager_test.go @@ -0,0 +1,53 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/go-vela/server/internal/token" + + "github.com/gin-gonic/gin" +) + +func TestMiddleware_TokenManager(t *testing.T) { + // setup types + s := httptest.NewServer(http.NotFoundHandler()) + defer s.Close() + + var got *token.Manager + + want := new(token.Manager) + want.PrivateKey = "123abc" + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil) + + // setup mock server + engine.Use(TokenManager(want)) + engine.GET("/health", func(c *gin.Context) { + got = c.MustGet("token-manager").(*token.Manager) + + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("TokenManager returned %v, want %v", resp.Code, http.StatusOK) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("TokenManager is %v, want %v", got, want) + } +} diff --git a/router/middleware/user/user.go b/router/middleware/user/user.go index 58d2cab87..1dd894a10 100644 --- a/router/middleware/user/user.go +++ b/router/middleware/user/user.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. @@ -9,9 +9,10 @@ import ( "strings" "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/gin-gonic/gin" @@ -26,20 +27,11 @@ func Retrieve(c *gin.Context) *library.User { // Establish sets the user in the given context. func Establish() gin.HandlerFunc { return func(c *gin.Context) { - // get the access token from the request - at, err := token.RetrieveAccessToken(c.Request) - if err != nil { - util.HandleError(c, http.StatusUnauthorized, err) - return - } + cl := claims.Retrieve(c) - // special handling for workers - secret := c.MustGet("secret").(string) - if strings.EqualFold(at, secret) { + // if token is not a user token, establish empty user to better handle nil checks + if !strings.EqualFold(cl.TokenType, constants.UserAccessTokenType) { u := new(library.User) - u.SetName("vela-worker") - u.SetActive(true) - u.SetAdmin(true) ToContext(c, u) c.Next() @@ -49,8 +41,8 @@ func Establish() gin.HandlerFunc { logrus.Debugf("parsing user access token") - // parse and validate the token and return the associated the user - u, err := token.Parse(at, database.FromContext(c)) + // lookup user in claims subject in the database + u, err := database.FromContext(c).GetUserForName(cl.Subject) if err != nil { util.HandleError(c, http.StatusUnauthorized, err) return diff --git a/router/middleware/user/user_test.go b/router/middleware/user/user_test.go index 724ac1cdb..46034914b 100644 --- a/router/middleware/user/user_test.go +++ b/router/middleware/user/user_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. @@ -14,9 +14,11 @@ import ( "github.com/go-vela/server/database" "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/server/router/middleware/token" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/scm" "github.com/go-vela/server/scm/github" + "github.com/golang-jwt/jwt/v4" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -47,6 +49,13 @@ func TestUser_Establish(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + want := new(library.User) want.SetID(1) want.SetName("foo") @@ -65,7 +74,13 @@ func TestUser_Establish(t *testing.T) { context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/users/foo", nil) - at, _ := token.CreateAccessToken(want, time.Minute*5) + mto := &token.MintTokenOpts{ + User: want, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } + + at, _ := tm.MintToken(mto) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", at)) context.Request.AddCookie(&http.Cookie{ @@ -100,8 +115,10 @@ func TestUser_Establish(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(claims.Establish()) engine.Use(Establish()) engine.GET("/users/:user", func(c *gin.Context) { got = Retrieve(c) @@ -125,6 +142,14 @@ func TestUser_Establish(t *testing.T) { } func TestUser_Establish_NoToken(t *testing.T) { + // setup types + secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } // setup database db, _ := sqlite.NewTest() @@ -138,7 +163,10 @@ func TestUser_Establish_NoToken(t *testing.T) { context.Request, _ = http.NewRequest(http.MethodGet, "/users/foo", nil) // setup mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) engine.Use(Establish()) // run test @@ -149,14 +177,18 @@ func TestUser_Establish_NoToken(t *testing.T) { } } -func TestUser_Establish_SecretValid(t *testing.T) { +func TestUser_Establish_DiffTokenType(t *testing.T) { // setup types secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + want := new(library.User) - want.SetName("vela-worker") - want.SetActive(true) - want.SetAdmin(true) got := new(library.User) @@ -170,6 +202,8 @@ func TestUser_Establish_SecretValid(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) engine.Use(Establish()) engine.GET("/users/:user", func(c *gin.Context) { got = Retrieve(c) @@ -196,6 +230,13 @@ func TestUser_Establish_NoAuthorizeUser(t *testing.T) { // setup database secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + // setup database db, _ := sqlite.NewTest() @@ -215,6 +256,8 @@ func TestUser_Establish_NoAuthorizeUser(t *testing.T) { engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) engine.Use(Establish()) // run test @@ -227,8 +270,19 @@ func TestUser_Establish_NoAuthorizeUser(t *testing.T) { func TestUser_Establish_NoUser(t *testing.T) { // setup types + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + u := new(library.User) + u.SetID(1) + u.SetName("foo") + + // setup database secret := "superSecret" - got := new(library.User) // setup database db, _ := sqlite.NewTest() @@ -242,30 +296,30 @@ func TestUser_Establish_NoUser(t *testing.T) { context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/users/foo?access_token=bar", nil) - // setup github mock server - engine.GET("/api/v3/user", func(c *gin.Context) { - c.String(http.StatusOK, userPayload) - }) + mto := &token.MintTokenOpts{ + User: u, + TokenDuration: tm.UserAccessTokenDuration, + TokenType: constants.UserAccessTokenType, + } - s := httptest.NewServer(engine) - defer s.Close() + at, _ := tm.MintToken(mto) + + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", at)) + context.Request.AddCookie(&http.Cookie{ + Name: constants.RefreshTokenName, + Value: "fresh", + }) // setup client - client, _ := github.NewTest(s.URL) + client, _ := github.NewTest("") // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { scm.ToContext(c, client) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) engine.Use(Establish()) - engine.GET("/users/:user", func(c *gin.Context) { - got = Retrieve(c) - - c.Status(http.StatusOK) - }) - - s1 := httptest.NewServer(engine) - defer s1.Close() // run test engine.ServeHTTP(context.Writer, context.Request) @@ -273,10 +327,6 @@ func TestUser_Establish_NoUser(t *testing.T) { if resp.Code != http.StatusUnauthorized { t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusUnauthorized) } - - if got.GetID() != 0 { - t.Errorf("Establish is %v, want 0", got) - } } const userPayload = ` diff --git a/router/router.go b/router/router.go index 9b33c700f..3327e4a7b 100644 --- a/router/router.go +++ b/router/router.go @@ -34,6 +34,7 @@ package router import ( "github.com/go-vela/server/api" "github.com/go-vela/server/router/middleware" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/user" @@ -92,7 +93,7 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { } // API endpoints - baseAPI := r.Group(base, user.Establish()) + baseAPI := r.Group(base, claims.Establish(), user.Establish()) { // Admin endpoints AdminHandlers(baseAPI) diff --git a/router/service.go b/router/service.go index 400feb4b5..7fe39d0e9 100644 --- a/router/service.go +++ b/router/service.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. @@ -37,7 +37,7 @@ func ServiceHandlers(base *gin.RouterGroup) { service := services.Group("/:service", service.Establish()) { service.GET("", perm.MustRead(), api.GetService) - service.PUT("", perm.MustPlatformAdmin(), middleware.Payload(), api.UpdateService) + service.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateService) service.DELETE("", perm.MustPlatformAdmin(), api.DeleteService) service.POST("/stream", perm.MustPlatformAdmin(), api.PostServiceStream) diff --git a/router/step.go b/router/step.go index 5ac9b05de..80aad489a 100644 --- a/router/step.go +++ b/router/step.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. @@ -37,7 +37,7 @@ func StepHandlers(base *gin.RouterGroup) { step := steps.Group("/:step", step.Establish()) { step.GET("", perm.MustRead(), api.GetStep) - step.PUT("", perm.MustPlatformAdmin(), middleware.Payload(), api.UpdateStep) + step.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateStep) step.DELETE("", perm.MustPlatformAdmin(), api.DeleteStep) step.POST("/stream", perm.MustPlatformAdmin(), api.PostStepStream) diff --git a/router/worker.go b/router/worker.go index 7f7df3a3b..7853c2a82 100644 --- a/router/worker.go +++ b/router/worker.go @@ -24,14 +24,14 @@ func WorkerHandlers(base *gin.RouterGroup) { // Workers endpoints workers := base.Group("/workers") { - workers.POST("", perm.MustPlatformAdmin(), middleware.Payload(), api.CreateWorker) + workers.POST("", perm.MustWorker(), middleware.Payload(), api.CreateWorker) workers.GET("", api.GetWorkers) // Worker endpoints w := workers.Group("/:worker") { w.GET("", worker.Establish(), api.GetWorker) - w.PUT("", perm.MustPlatformAdmin(), worker.Establish(), api.UpdateWorker) + w.PUT("", perm.MustWorker(), worker.Establish(), api.UpdateWorker) w.DELETE("", perm.MustPlatformAdmin(), worker.Establish(), api.DeleteWorker) } // end of worker endpoints } // end of workers endpoints From c4283eb079e8fad30b666cb07f4211a1438af696 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 24 Feb 2023 10:31:14 -0600 Subject: [PATCH 157/298] fix: revert buildkite yaml upgrade from #765 (#767) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 240012799..027e10ab7 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.23.1 github.com/aws/aws-sdk-go v1.44.161 - github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 + github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.2.0 diff --git a/go.sum b/go.sum index f35038998..dfd246366 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396 h1:qLN32md48xyTEqw6XEZMyNMre7njm0XXvDrea6NVwOM= -github.com/buildkite/yaml v0.0.0-20210326113714-4a3f40911396/go.mod h1:AV5wtJnn1/CRaRGlJ8xspkMWfKXV0/pkJVgGleTIrfk= +github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= +github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= From 9e83ba0f0f8bd5892abf121e06a5902b562d2c4d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 24 Feb 2023 13:32:43 -0700 Subject: [PATCH 158/298] fix(validate): update validation to use new, shorter name for token durations (#768) --- cmd/vela-server/validate.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index f79512e9e..6b82e6b4e 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -76,12 +76,12 @@ func validateCore(c *cli.Context) error { } } - if c.Duration("token-manager-user-refresh-token-duration").Seconds() <= c.Duration("token-manager-user-access-token-duration").Seconds() { - return fmt.Errorf("token-manager-user-refresh-token-duration (VELA_TOKEN_MANAGER_USER_REFRESH_TOKEN_DURATION) must be larger than the token-manager-user-access-token-duration (VELA_TOKEN_MANAGER_USER_ACCESS_TOKEN_DURATION)") + if c.Duration("user-refresh-token-duration").Seconds() <= c.Duration("user-access-token-duration").Seconds() { + return fmt.Errorf("user-refresh-token-duration (VELA_USER_REFRESH_TOKEN_DURATION) must be larger than the user-access-token-duration (VELA_USER_ACCESS_TOKEN_DURATION)") } - if c.Duration("token-manager-build-token-buffer-duration").Seconds() < 0 { - return fmt.Errorf("token-manager-build-token-buffer-duration (VELA_TOKEN_MANAGER_BUILD_TOKEN_BUFFER_DURATION) must not be a negative time value") + if c.Duration("build-token-buffer-duration").Seconds() < 0 { + return fmt.Errorf("build-token-buffer-duration (VELA_BUILD_TOKEN_BUFFER_DURATION) must not be a negative time value") } if c.Int64("default-build-limit") == 0 { From 4ba273567239df4d41dc2d49b634b3af84cdc5f3 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 24 Feb 2023 16:07:33 -0600 Subject: [PATCH 159/298] refactor(database): move log logic into separate package (#722) --- api/log.go | 57 +++-- api/stream.go | 4 +- database/log/count.go | 25 ++ database/log/count_build.go | 27 ++ database/log/count_build_test.go | 99 ++++++++ database/log/count_test.go | 93 +++++++ database/log/create.go | 57 +++++ database/log/create_test.go | 92 +++++++ database/log/delete.go | 33 +++ database/log/delete_test.go | 73 ++++++ database/log/get.go | 48 ++++ database/log/get_service.go | 49 ++++ database/log/get_service_test.go | 93 +++++++ database/log/get_step.go | 49 ++++ database/log/get_step_test.go | 93 +++++++ database/log/get_test.go | 86 +++++++ database/log/index.go | 24 ++ database/log/index_test.go | 59 +++++ database/log/list.go | 65 +++++ database/log/list_build.go | 72 ++++++ database/log/list_build_test.go | 110 ++++++++ database/log/list_test.go | 104 ++++++++ database/log/log.go | 82 ++++++ database/log/log_test.go | 276 ++++++++++++++++++++ database/log/opts.go | 54 ++++ database/log/opts_test.go | 216 ++++++++++++++++ database/log/service.go | 49 ++++ database/log/table.go | 60 +++++ database/log/table_test.go | 59 +++++ database/log/update.go | 57 +++++ database/log/update_test.go | 101 ++++++++ database/postgres/ddl/log.go | 33 --- database/postgres/dml/log.go | 49 ---- database/postgres/log.go | 212 ---------------- database/postgres/log_test.go | 388 ----------------------------- database/postgres/postgres.go | 36 ++- database/postgres/postgres_test.go | 11 +- database/service.go | 26 +- database/sqlite/ddl/log.go | 33 --- database/sqlite/dml/log.go | 49 ---- database/sqlite/log.go | 212 ---------------- database/sqlite/log_test.go | 380 ---------------------------- database/sqlite/sqlite.go | 28 ++- 43 files changed, 2401 insertions(+), 1422 deletions(-) create mode 100644 database/log/count.go create mode 100644 database/log/count_build.go create mode 100644 database/log/count_build_test.go create mode 100644 database/log/count_test.go create mode 100644 database/log/create.go create mode 100644 database/log/create_test.go create mode 100644 database/log/delete.go create mode 100644 database/log/delete_test.go create mode 100644 database/log/get.go create mode 100644 database/log/get_service.go create mode 100644 database/log/get_service_test.go create mode 100644 database/log/get_step.go create mode 100644 database/log/get_step_test.go create mode 100644 database/log/get_test.go create mode 100644 database/log/index.go create mode 100644 database/log/index_test.go create mode 100644 database/log/list.go create mode 100644 database/log/list_build.go create mode 100644 database/log/list_build_test.go create mode 100644 database/log/list_test.go create mode 100644 database/log/log.go create mode 100644 database/log/log_test.go create mode 100644 database/log/opts.go create mode 100644 database/log/opts_test.go create mode 100644 database/log/service.go create mode 100644 database/log/table.go create mode 100644 database/log/table_test.go create mode 100644 database/log/update.go create mode 100644 database/log/update_test.go delete mode 100644 database/postgres/ddl/log.go delete mode 100644 database/postgres/dml/log.go delete mode 100644 database/postgres/log.go delete mode 100644 database/postgres/log_test.go delete mode 100644 database/sqlite/ddl/log.go delete mode 100644 database/sqlite/dml/log.go delete mode 100644 database/sqlite/log.go delete mode 100644 database/sqlite/log_test.go diff --git a/api/log.go b/api/log.go index 105ae1337..fe593c40d 100644 --- a/api/log.go +++ b/api/log.go @@ -83,7 +83,9 @@ func GetBuildLogs(c *gin.Context) { }).Infof("reading logs for build %s", entry) // send API call to capture the list of logs for the build - l, err := database.FromContext(c).GetBuildLogs(b.GetID()) + // + // TODO: add page and per_page query parameters + l, t, err := database.FromContext(c).ListLogsForBuild(b, 1, 100) if err != nil { retErr := fmt.Errorf("unable to get logs for build %s: %w", entry, err) @@ -92,6 +94,15 @@ func GetBuildLogs(c *gin.Context) { return } + // create pagination object + pagination := Pagination{ + Page: 1, + PerPage: 100, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + c.JSON(http.StatusOK, l) } @@ -200,7 +211,7 @@ func CreateServiceLog(c *gin.Context) { } // send API call to capture the created log - l, _ := database.FromContext(c).GetServiceLog(s.GetID()) + l, _ := database.FromContext(c).GetLogForService(s) c.JSON(http.StatusCreated, l) } @@ -270,7 +281,7 @@ func GetServiceLog(c *gin.Context) { }).Infof("reading logs for service %s", entry) // send API call to capture the service logs - l, err := database.FromContext(c).GetServiceLog(s.GetID()) + l, err := database.FromContext(c).GetLogForService(s) if err != nil { retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) @@ -358,7 +369,7 @@ func UpdateServiceLog(c *gin.Context) { }).Infof("updating logs for service %s", entry) // send API call to capture the service logs - l, err := database.FromContext(c).GetServiceLog(s.GetID()) + l, err := database.FromContext(c).GetLogForService(s) if err != nil { retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) @@ -396,7 +407,7 @@ func UpdateServiceLog(c *gin.Context) { } // send API call to capture the updated log - l, _ = database.FromContext(c).GetServiceLog(s.GetID()) + l, _ = database.FromContext(c).GetLogForService(s) c.JSON(http.StatusOK, l) } @@ -444,8 +455,6 @@ func UpdateServiceLog(c *gin.Context) { // DeleteServiceLog represents the API handler to remove // the logs for a service from the configured backend. -// -//nolint:dupl // ignore similar code with step func DeleteServiceLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -467,8 +476,18 @@ func DeleteServiceLog(c *gin.Context) { "user": u.GetName(), }).Infof("deleting logs for service %s", entry) + // send API call to capture the service logs + l, err := database.FromContext(c).GetLogForService(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // send API call to remove the log - err := database.FromContext(c).DeleteLog(s.GetID()) + err = database.FromContext(c).DeleteLog(l) if err != nil { retErr := fmt.Errorf("unable to delete logs for service %s: %w", entry, err) @@ -585,7 +604,7 @@ func CreateStepLog(c *gin.Context) { } // send API call to capture the created log - l, _ := database.FromContext(c).GetStepLog(s.GetID()) + l, _ := database.FromContext(c).GetLogForStep(s) c.JSON(http.StatusCreated, l) } @@ -656,7 +675,7 @@ func GetStepLog(c *gin.Context) { }).Infof("reading logs for step %s", entry) // send API call to capture the step logs - l, err := database.FromContext(c).GetStepLog(s.GetID()) + l, err := database.FromContext(c).GetLogForStep(s) if err != nil { retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) @@ -744,7 +763,7 @@ func UpdateStepLog(c *gin.Context) { }).Infof("updating logs for step %s", entry) // send API call to capture the step logs - l, err := database.FromContext(c).GetStepLog(s.GetID()) + l, err := database.FromContext(c).GetLogForStep(s) if err != nil { retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) @@ -782,7 +801,7 @@ func UpdateStepLog(c *gin.Context) { } // send API call to capture the updated log - l, _ = database.FromContext(c).GetStepLog(s.GetID()) + l, _ = database.FromContext(c).GetLogForStep(s) c.JSON(http.StatusOK, l) } @@ -830,8 +849,6 @@ func UpdateStepLog(c *gin.Context) { // DeleteStepLog represents the API handler to remove // the logs for a step from the configured backend. -// -//nolint:dupl // ignore similar code with service func DeleteStepLog(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -853,8 +870,18 @@ func DeleteStepLog(c *gin.Context) { "user": u.GetName(), }).Infof("deleting logs for step %s", entry) + // send API call to capture the step logs + l, err := database.FromContext(c).GetLogForStep(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // send API call to remove the log - err := database.FromContext(c).DeleteLog(s.GetID()) + err = database.FromContext(c).DeleteLog(l) if err != nil { retErr := fmt.Errorf("unable to delete logs for step %s: %w", entry, err) diff --git a/api/stream.go b/api/stream.go index c3425d517..701758f14 100644 --- a/api/stream.go +++ b/api/stream.go @@ -114,7 +114,7 @@ func PostServiceStream(c *gin.Context) { defer close(done) // send API call to capture the service logs - _log, err := database.FromContext(c).GetServiceLog(s.GetID()) + _log, err := database.FromContext(c).GetLogForService(s) if err != nil { retErr := fmt.Errorf("unable to get logs for service %s/%d: %w", entry, s.GetNumber(), err) @@ -269,7 +269,7 @@ func PostStepStream(c *gin.Context) { defer close(done) // send API call to capture the step logs - _log, err := database.FromContext(c).GetStepLog(s.GetID()) + _log, err := database.FromContext(c).GetLogForStep(s) if err != nil { retErr := fmt.Errorf("unable to get logs for step %s/%d: %w", entry, s.GetNumber(), err) diff --git a/database/log/count.go b/database/log/count.go new file mode 100644 index 000000000..e4ec570fe --- /dev/null +++ b/database/log/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/constants" +) + +// CountLogs gets the count of all logs from the database. +func (e *engine) CountLogs() (int64, error) { + e.logger.Tracef("getting count of all logs from the database") + + // variable to store query results + var l int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableLog). + Count(&l). + Error + + return l, err +} diff --git a/database/log/count_build.go b/database/log/count_build.go new file mode 100644 index 000000000..6a7fb74fb --- /dev/null +++ b/database/log/count_build.go @@ -0,0 +1,27 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "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(b *library.Build) (int64, error) { + e.logger.Tracef("getting count of logs for build %d from the database", b.GetID()) + + // variable to store query results + var l int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableLog). + Where("build_id = ?", b.GetID()). + Count(&l). + Error + + return l, err +} diff --git a/database/log/count_build_test.go b/database/log/count_build_test.go new file mode 100644 index 000000000..d462eedf0 --- /dev/null +++ b/database/log/count_build_test.go @@ -0,0 +1,99 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestLog_Engine_CountLogsForBuild(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + + _build := testBuild() + _build.SetID(1) + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "logs" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_service) + if err != nil { + t.Errorf("unable to create test service log for sqlite: %v", err) + } + + err = _sqlite.CreateLog(_step) + if err != nil { + t.Errorf("unable to create test step log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountLogsForBuild(_build) + + if test.failure { + if err == nil { + t.Errorf("CountLogsForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountLogsForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountLogsForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/count_test.go b/database/log/count_test.go new file mode 100644 index 000000000..99e75a767 --- /dev/null +++ b/database/log/count_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestLog_Engine_CountLogs(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "logs"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_service) + if err != nil { + t.Errorf("unable to create test service log for sqlite: %v", err) + } + + err = _sqlite.CreateLog(_step) + if err != nil { + t.Errorf("unable to create test step log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountLogs() + + if test.failure { + if err == nil { + t.Errorf("CountLogs for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountLogs for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountLogs for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/create.go b/database/log/create.go new file mode 100644 index 000000000..978da9a1f --- /dev/null +++ b/database/log/create.go @@ -0,0 +1,57 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create.go +package log + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// CreateLog creates a new log in the database. +func (e *engine) CreateLog(l *library.Log) error { + // check what the log entry is for + switch { + case l.GetServiceID() > 0: + e.logger.Tracef("creating log for service %d for build %d in the database", l.GetServiceID(), l.GetBuildID()) + case l.GetStepID() > 0: + e.logger.Tracef("creating log for step %d for build %d in the database", l.GetStepID(), l.GetBuildID()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#LogFromLibrary + log := database.LogFromLibrary(l) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate + err := log.Validate() + if err != nil { + return err + } + + // compress log data for the resource + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress + err = log.Compress(e.config.CompressionLevel) + if err != nil { + switch { + case l.GetServiceID() > 0: + return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + case l.GetStepID() > 0: + return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + } + } + + // send query to the database + return e.client. + Table(constants.TableLog). + Create(log). + Error +} diff --git a/database/log/create_test.go b/database/log/create_test.go new file mode 100644 index 000000000..1574e88a8 --- /dev/null +++ b/database/log/create_test.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_CreateLog(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the service query + _mock.ExpectQuery(`INSERT INTO "logs" +("build_id","repo_id","service_id","step_id","data","id") +VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`). + WithArgs(1, 1, 1, nil, AnyArgument{}, 1). + WillReturnRows(_rows) + + // ensure the mock expects the step query + _mock.ExpectQuery(`INSERT INTO "logs" +("build_id","repo_id","service_id","step_id","data","id") +VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`). + WithArgs(1, 1, nil, 1, AnyArgument{}, 2). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + logs []*library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + logs: []*library.Log{_service, _step}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + logs: []*library.Log{_service, _step}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + for _, log := range test.logs { + err := test.database.CreateLog(log) + + if test.failure { + if err == nil { + t.Errorf("CreateLog for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateLog for %s returned err: %v", test.name, err) + } + } + }) + } +} diff --git a/database/log/delete.go b/database/log/delete.go new file mode 100644 index 000000000..255e6213b --- /dev/null +++ b/database/log/delete.go @@ -0,0 +1,33 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// DeleteLog deletes an existing log from the database. +func (e *engine) DeleteLog(l *library.Log) error { + // check what the log entry is for + switch { + case l.GetServiceID() > 0: + e.logger.Tracef("deleting log for service %d for build %d in the database", l.GetServiceID(), l.GetBuildID()) + case l.GetStepID() > 0: + e.logger.Tracef("deleting log for step %d for build %d in the database", l.GetStepID(), l.GetBuildID()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#LogFromLibrary + log := database.LogFromLibrary(l) + + // send query to the database + return e.client. + Table(constants.TableLog). + Delete(log). + Error +} diff --git a/database/log/delete_test.go b/database/log/delete_test.go new file mode 100644 index 000000000..15329a0af --- /dev/null +++ b/database/log/delete_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestLog_Engine_DeleteLog(t *testing.T) { + // setup types + _log := testLog() + _log.SetID(1) + _log.SetRepoID(1) + _log.SetBuildID(1) + _log.SetStepID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "logs" WHERE "logs"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_log) + if err != nil { + t.Errorf("unable to create test log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteLog(_log) + + if test.failure { + if err == nil { + t.Errorf("DeleteLog for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteLog for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/log/get.go b/database/log/get.go new file mode 100644 index 000000000..d91a6687d --- /dev/null +++ b/database/log/get.go @@ -0,0 +1,48 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetLog gets a log by ID from the database. +func (e *engine) GetLog(id int64) (*library.Log, error) { + e.logger.Tracef("getting log %d from the database", id) + + // variable to store query results + l := new(database.Log) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableLog). + Where("id = ?", id). + Take(l). + Error + if err != nil { + return nil, err + } + + // decompress log data + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress + err = l.Decompress() + if err != nil { + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allowing us to fetch uncompressed logs + e.logger.Errorf("unable to decompress log %d: %v", id, err) + + // return the uncompressed log + return l.ToLibrary(), nil + } + + // return the log + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.ToLibrary + return l.ToLibrary(), nil +} diff --git a/database/log/get_service.go b/database/log/get_service.go new file mode 100644 index 000000000..2d03bf127 --- /dev/null +++ b/database/log/get_service.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with get_step.go +package log + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetLogForService gets a log by service ID from the database. +func (e *engine) GetLogForService(s *library.Service) (*library.Log, error) { + e.logger.Tracef("getting log for service %d for build %d from the database", s.GetID(), s.GetBuildID()) + + // variable to store query results + l := new(database.Log) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableLog). + Where("service_id = ?", s.GetID()). + Take(l). + Error + if err != nil { + return nil, err + } + + // decompress log data for the service + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress + err = l.Decompress() + if err != nil { + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allowing us to fetch uncompressed logs + e.logger.Errorf("unable to decompress log for service %d for build %d: %v", s.GetID(), s.GetBuildID(), err) + + // return the uncompressed log + return l.ToLibrary(), nil + } + + // return the log + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.ToLibrary + return l.ToLibrary(), nil +} diff --git a/database/log/get_service_test.go b/database/log/get_service_test.go new file mode 100644 index 000000000..26f42813c --- /dev/null +++ b/database/log/get_service_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_GetLogForService(t *testing.T) { + // setup types + _log := testLog() + _log.SetID(1) + _log.SetRepoID(1) + _log.SetBuildID(1) + _log.SetServiceID(1) + _log.SetData([]byte{}) + + _service := testService() + _service.SetID(1) + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}). + AddRow(1, 1, 1, 1, 0, []byte{}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "logs" WHERE service_id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_log) + if err != nil { + t.Errorf("unable to create test log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _log, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _log, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetLogForService(_service) + + if test.failure { + if err == nil { + t.Errorf("GetLogForService for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetLogForService for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetLogForService for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/get_step.go b/database/log/get_step.go new file mode 100644 index 000000000..eb1b95c7f --- /dev/null +++ b/database/log/get_step.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with get_service.go +package log + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetLogForStep gets a log by step ID from the database. +func (e *engine) GetLogForStep(s *library.Step) (*library.Log, error) { + e.logger.Tracef("getting log for step %d for build %d from the database", s.GetID(), s.GetBuildID()) + + // variable to store query results + l := new(database.Log) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableLog). + Where("step_id = ?", s.GetID()). + Take(l). + Error + if err != nil { + return nil, err + } + + // decompress log data for the step + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress + err = l.Decompress() + if err != nil { + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allowing us to fetch uncompressed logs + e.logger.Errorf("unable to decompress log for step %d for build %d: %v", s.GetID(), s.GetBuildID(), err) + + // return the uncompressed log + return l.ToLibrary(), nil + } + + // return the log + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.ToLibrary + return l.ToLibrary(), nil +} diff --git a/database/log/get_step_test.go b/database/log/get_step_test.go new file mode 100644 index 000000000..39f019039 --- /dev/null +++ b/database/log/get_step_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_GetLogForStep(t *testing.T) { + // setup types + _log := testLog() + _log.SetID(1) + _log.SetRepoID(1) + _log.SetBuildID(1) + _log.SetStepID(1) + _log.SetData([]byte{}) + + _step := testStep() + _step.SetID(1) + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "build_id", "repo_id", "step_id", "step_id", "data"}). + AddRow(1, 1, 1, 0, 1, []byte{}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "logs" WHERE step_id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_log) + if err != nil { + t.Errorf("unable to create test log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _log, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _log, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetLogForStep(_step) + + if test.failure { + if err == nil { + t.Errorf("GetLogForStep for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetLogForStep for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetLogForStep for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/get_test.go b/database/log/get_test.go new file mode 100644 index 000000000..31325e3ac --- /dev/null +++ b/database/log/get_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_GetLog(t *testing.T) { + // setup types + _log := testLog() + _log.SetID(1) + _log.SetRepoID(1) + _log.SetBuildID(1) + _log.SetStepID(1) + _log.SetData([]byte{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}). + AddRow(1, 1, 1, 0, 1, []byte{}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "logs" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_log) + if err != nil { + t.Errorf("unable to create test log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _log, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _log, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetLog(1) + + if test.failure { + if err == nil { + t.Errorf("GetLog for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetLog for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetLog for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/index.go b/database/log/index.go new file mode 100644 index 000000000..3ff3cdbc5 --- /dev/null +++ b/database/log/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +const ( + // CreateBuildIDIndex represents a query to create an + // index on the logs table for the build_id column. + CreateBuildIDIndex = ` +CREATE INDEX +IF NOT EXISTS +logs_build_id +ON logs (build_id); +` +) + +// CreateLogIndexes creates the indexes for the logs table in the database. +func (e *engine) CreateLogIndexes() error { + e.logger.Tracef("creating indexes for logs table in the database") + + // create the hostname and address columns index for the logs table + return e.client.Exec(CreateBuildIDIndex).Error +} diff --git a/database/log/index_test.go b/database/log/index_test.go new file mode 100644 index 000000000..26c0045db --- /dev/null +++ b/database/log/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestLog_Engine_CreateLogIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateLogIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateLogIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateLogIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/log/list.go b/database/log/list.go new file mode 100644 index 000000000..703155a37 --- /dev/null +++ b/database/log/list.go @@ -0,0 +1,65 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListLogs gets a list of all logs from the database. +func (e *engine) ListLogs() ([]*library.Log, error) { + e.logger.Trace("listing all logs from the database") + + // variables to store query results and return value + count := int64(0) + h := new([]database.Log) + logs := []*library.Log{} + + // count the results + count, err := e.CountLogs() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return logs, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableLog). + Find(&h). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, log := range *h { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := log + + // decompress log data + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress + err = tmp.Decompress() + if err != nil { + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch uncompressed logs + e.logger.Errorf("unable to decompress logs: %v", err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.ToLibrary + logs = append(logs, tmp.ToLibrary()) + } + + return logs, nil +} diff --git a/database/log/list_build.go b/database/log/list_build.go new file mode 100644 index 000000000..58ca12111 --- /dev/null +++ b/database/log/list_build.go @@ -0,0 +1,72 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "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(b *library.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 + count := int64(0) + l := new([]database.Log) + logs := []*library.Log{} + + // count the results + count, err := e.CountLogsForBuild(b) + if err != nil { + return nil, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return logs, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableLog). + Where("build_id = ?", b.GetID()). + Order("step_id ASC"). + Limit(perPage). + Offset(offset). + Find(&l). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, log := range *l { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := log + + // decompress log data for the build + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress + err = tmp.Decompress() + if err != nil { + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch uncompressed logs + e.logger.Errorf("unable to decompress logs for build %d: %v", b.GetID(), err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.ToLibrary + logs = append(logs, tmp.ToLibrary()) + } + + return logs, count, nil +} diff --git a/database/log/list_build_test.go b/database/log/list_build_test.go new file mode 100644 index 000000000..fb08236e9 --- /dev/null +++ b/database/log/list_build_test.go @@ -0,0 +1,110 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_ListLogsForBuild(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + _service.SetData([]byte{}) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + _step.SetData([]byte{}) + + _build := testBuild() + _build.SetID(1) + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "logs" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}). + AddRow(1, 1, 1, 1, 0, []byte{}).AddRow(2, 1, 1, 0, 1, []byte{}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "logs" WHERE build_id = $1 ORDER BY step_id ASC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_service) + if err != nil { + t.Errorf("unable to create test service log for sqlite: %v", err) + } + + err = _sqlite.CreateLog(_step) + if err != nil { + t.Errorf("unable to create test step log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Log{_service, _step}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Log{_service, _step}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListLogsForBuild(_build, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListLogsForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListLogsForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListLogsForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/list_test.go b/database/log/list_test.go new file mode 100644 index 000000000..0cf420255 --- /dev/null +++ b/database/log/list_test.go @@ -0,0 +1,104 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_ListLogs(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + _service.SetData([]byte{}) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + _step.SetData([]byte{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "logs"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}). + AddRow(1, 1, 1, 1, 0, []byte{}).AddRow(2, 1, 1, 0, 1, []byte{}) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "logs"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_service) + if err != nil { + t.Errorf("unable to create test service log for sqlite: %v", err) + } + + err = _sqlite.CreateLog(_step) + if err != nil { + t.Errorf("unable to create test step log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Log{_service, _step}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Log{_service, _step}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListLogs() + + if test.failure { + if err == nil { + t.Errorf("ListLogs for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListLogs for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListLogs for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/log/log.go b/database/log/log.go new file mode 100644 index 000000000..22604e411 --- /dev/null +++ b/database/log/log.go @@ -0,0 +1,82 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the LogService interface. + config struct { + // specifies the level of compression to use for the Log engine + CompressionLevel int + // specifies to skip creating tables and indexes for the Log engine + SkipCreation bool + } + + // engine represents the log functionality that implements the LogService interface. + engine struct { + // engine configuration settings used in log functions + config *config + + // gorm.io/gorm database client used in log functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in log functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with logs in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Log engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating log database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of logs table and indexes in the database") + + return e, nil + } + + // create the logs table + err := e.CreateLogTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) + } + + // create the indexes for the logs table + err = e.CreateLogIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableLog, err) + } + + return e, nil +} diff --git a/database/log/log_test.go b/database/log/log_test.go new file mode 100644 index 000000000..69e3835d5 --- /dev/null +++ b/database/log/log_test.go @@ -0,0 +1,276 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestLog_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres log engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite log engine: %v", err) + } + + return _engine +} + +// 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(v 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/opts.go b/database/log/opts.go new file mode 100644 index 000000000..ea1897ba9 --- /dev/null +++ b/database/log/opts.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Logs. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Logs. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the log engine + e.client = client + + return nil + } +} + +// WithCompressionLevel sets the compression level in the database engine for Logs. +func WithCompressionLevel(level int) EngineOpt { + return func(e *engine) error { + // set the compression level in the log engine + e.config.CompressionLevel = level + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Logs. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the log engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Logs. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the log engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/log/opts_test.go b/database/log/opts_test.go new file mode 100644 index 000000000..c35dbaa48 --- /dev/null +++ b/database/log/opts_test.go @@ -0,0 +1,216 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestLog_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestLog_EngineOpt_WithCompressionLevel(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + level int + want int + }{ + { + failure: false, + name: "compression level set to -1", + level: -1, + want: -1, + }, + { + failure: false, + name: "compression level set to 0", + level: 0, + want: 0, + }, + { + failure: false, + name: "compression level set to 1", + level: 1, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithCompressionLevel(test.level)(e) + + if test.failure { + if err == nil { + t.Errorf("WithCompressionLevel for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithCompressionLevel returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.CompressionLevel, test.want) { + t.Errorf("WithCompressionLevel is %v, want %v", e.config.CompressionLevel, test.want) + } + }) + } +} + +func TestLog_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestLog_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/log/service.go b/database/log/service.go new file mode 100644 index 000000000..00e686ee9 --- /dev/null +++ b/database/log/service.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/library" +) + +// LogService represents the Vela interface for log +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type LogService interface { + // Log Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateLogIndexes defines a function that creates the indexes for the logs table. + CreateLogIndexes() error + // CreateLogTable defines a function that creates the logs table. + CreateLogTable(string) error + + // Log Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountLogs defines a function that gets the count of all logs. + CountLogs() (int64, error) + // CountLogsForBuild defines a function that gets the count of logs by build ID. + CountLogsForBuild(*library.Build) (int64, error) + // CreateLog defines a function that creates a new log. + CreateLog(*library.Log) error + // DeleteLog defines a function that deletes an existing log. + DeleteLog(*library.Log) error + // GetLog defines a function that gets a log by ID. + GetLog(int64) (*library.Log, error) + // GetLogForService defines a function that gets a log by service ID. + GetLogForService(*library.Service) (*library.Log, error) + // GetLogForStep defines a function that gets a log by step ID. + GetLogForStep(*library.Step) (*library.Log, error) + // ListLogs defines a function that gets a list of all logs. + ListLogs() ([]*library.Log, error) + // ListLogsForBuild defines a function that gets a list of logs by build ID. + ListLogsForBuild(*library.Build, int, int) ([]*library.Log, int64, error) + // UpdateLog defines a function that updates an existing log. + UpdateLog(*library.Log) error +} diff --git a/database/log/table.go b/database/log/table.go new file mode 100644 index 000000000..2d5e5e0c5 --- /dev/null +++ b/database/log/table.go @@ -0,0 +1,60 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres logs table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +logs ( + id SERIAL PRIMARY KEY, + build_id INTEGER, + repo_id INTEGER, + service_id INTEGER, + step_id INTEGER, + data BYTEA, + UNIQUE(step_id), + UNIQUE(service_id) +); +` + + // CreateSqliteTable represents a query to create the Sqlite logs table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + build_id INTEGER, + repo_id INTEGER, + service_id INTEGER, + step_id INTEGER, + data BLOB, + UNIQUE(step_id), + UNIQUE(service_id) +); +` +) + +// CreateLogTable creates the logs table in the database. +func (e *engine) CreateLogTable(driver string) error { + e.logger.Tracef("creating logs table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the logs table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the logs table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/log/table_test.go b/database/log/table_test.go new file mode 100644 index 000000000..066d9f38a --- /dev/null +++ b/database/log/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestLog_Engine_CreateLogTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateLogTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateLogTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateLogTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/log/update.go b/database/log/update.go new file mode 100644 index 000000000..fb7165004 --- /dev/null +++ b/database/log/update.go @@ -0,0 +1,57 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with update.go +package log + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// UpdateLog updates an existing log in the database. +func (e *engine) UpdateLog(l *library.Log) error { + // check what the log entry is for + switch { + case l.GetServiceID() > 0: + e.logger.Tracef("updating log for service %d for build %d in the database", l.GetServiceID(), l.GetBuildID()) + case l.GetStepID() > 0: + e.logger.Tracef("updating log for step %d for build %d in the database", l.GetStepID(), l.GetBuildID()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#LogFromLibrary + log := database.LogFromLibrary(l) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate + err := log.Validate() + if err != nil { + return err + } + + // compress log data for the resource + // + // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress + err = log.Compress(e.config.CompressionLevel) + if err != nil { + switch { + case l.GetServiceID() > 0: + return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + case l.GetStepID() > 0: + return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + } + } + + // send query to the database + return e.client. + Table(constants.TableLog). + Save(log). + Error +} diff --git a/database/log/update_test.go b/database/log/update_test.go new file mode 100644 index 000000000..0b4e8e127 --- /dev/null +++ b/database/log/update_test.go @@ -0,0 +1,101 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestLog_Engine_UpdateLog(t *testing.T) { + // setup types + _service := testLog() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetServiceID(1) + _service.SetData([]byte{}) + + _step := testLog() + _step.SetID(2) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetStepID(1) + _step.SetData([]byte{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the service query + _mock.ExpectExec(`UPDATE "logs" +SET "build_id"=$1,"repo_id"=$2,"service_id"=$3,"step_id"=$4,"data"=$5 +WHERE "id" = $6`). + WithArgs(1, 1, 1, nil, AnyArgument{}, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the step query + _mock.ExpectExec(`UPDATE "logs" +SET "build_id"=$1,"repo_id"=$2,"service_id"=$3,"step_id"=$4,"data"=$5 +WHERE "id" = $6`). + WithArgs(1, 1, nil, 1, AnyArgument{}, 2). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateLog(_service) + if err != nil { + t.Errorf("unable to create test service log for sqlite: %v", err) + } + + err = _sqlite.CreateLog(_step) + if err != nil { + t.Errorf("unable to create test step log for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + logs []*library.Log + }{ + { + failure: false, + name: "postgres", + database: _postgres, + logs: []*library.Log{_service, _step}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + logs: []*library.Log{_service, _step}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + for _, log := range test.logs { + err = test.database.UpdateLog(log) + + if test.failure { + if err == nil { + t.Errorf("UpdateLog for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateLog for %s returned err: %v", test.name, err) + } + } + }) + } +} diff --git a/database/postgres/ddl/log.go b/database/postgres/ddl/log.go deleted file mode 100644 index f9c9d7bd9..000000000 --- a/database/postgres/ddl/log.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateLogTable represents a query to - // create the logs table for Vela. - CreateLogTable = ` -CREATE TABLE -IF NOT EXISTS -logs ( - id SERIAL PRIMARY KEY, - build_id INTEGER, - repo_id INTEGER, - service_id INTEGER, - step_id INTEGER, - data BYTEA, - UNIQUE(step_id), - UNIQUE(service_id) -); -` - - // CreateLogBuildIDIndex represents a query to create an - // index on the logs table for the build_id column. - CreateLogBuildIDIndex = ` -CREATE INDEX -IF NOT EXISTS -logs_build_id -ON logs (build_id); -` -) diff --git a/database/postgres/dml/log.go b/database/postgres/dml/log.go deleted file mode 100644 index e3e904cc4..000000000 --- a/database/postgres/dml/log.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListLogs represents a query to - // list all logs in the database. - ListLogs = ` -SELECT * -FROM logs; -` - - // ListBuildLogs represents a query to list - // all logs for a build_id in the database. - ListBuildLogs = ` -SELECT * -FROM logs -WHERE build_id = ? -ORDER BY step_id ASC; -` - - // SelectStepLog represents a query to select - // a log for a step_id in the database. - SelectStepLog = ` -SELECT * -FROM logs -WHERE step_id = ? -LIMIT 1; -` - - // SelectServiceLog represents a query to select - // a log for a service_id in the database. - SelectServiceLog = ` -SELECT * -FROM logs -WHERE service_id = ? -LIMIT 1; -` - - // DeleteLog represents a query to - // remove a log from the database. - DeleteLog = ` -DELETE -FROM logs -WHERE id = ?; -` -) diff --git a/database/postgres/log.go b/database/postgres/log.go deleted file mode 100644 index fe23549eb..000000000 --- a/database/postgres/log.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - "fmt" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetBuildLogs gets a collection of logs for a build by unique ID from the database. -func (c *client) GetBuildLogs(id int64) ([]*library.Log, error) { - c.Logger.Tracef("listing logs for build %d from the database", id) - - // variable to store query results - l := new([]database.Log) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableLog). - Raw(dml.ListBuildLogs, id). - Scan(l).Error - if err != nil { - return nil, err - } - - // variable we want to return - logs := []*library.Log{} - // iterate through all query results - for _, log := range *l { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := log - - // decompress log data for the step - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err = tmp.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for build %d: %v", id, err) - } - - // convert query result to library type - logs = append(logs, tmp.ToLibrary()) - } - - return logs, nil -} - -// GetStepLog gets a log by unique ID from the database. -// -//nolint:dupl // ignore similar code with service -func (c *client) GetStepLog(id int64) (*library.Log, error) { - c.Logger.Tracef("getting log for step %d from the database", id) - - // variable to store query results - l := new(database.Log) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableLog). - Raw(dml.SelectStepLog, id). - Scan(l) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decompress log data for the step - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err := l.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for step %d: %v", id, err) - - // return the uncompressed log - return l.ToLibrary(), result.Error - } - - // return the decompressed log - return l.ToLibrary(), result.Error -} - -// GetServiceLog gets a log by unique ID from the database. -// -//nolint:dupl // ignore similar code with step -func (c *client) GetServiceLog(id int64) (*library.Log, error) { - c.Logger.Tracef("getting log for service %d from the database", id) - - // variable to store query results - l := new(database.Log) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableLog). - Raw(dml.SelectServiceLog, id). - Scan(l) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decompress log data for the service - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err := l.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allowing us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for service %d: %v", id, err) - - // return the uncompressed log - return l.ToLibrary(), result.Error - } - - // return the decompressed log - return l.ToLibrary(), result.Error -} - -// CreateLog creates a new log in the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) CreateLog(l *library.Log) error { - // check if the log entry is for a step - if l.GetStepID() > 0 { - c.Logger.Tracef("creating log for step %d in the database", l.GetStepID()) - } else { - c.Logger.Tracef("creating log for service %d in the database", l.GetServiceID()) - } - - // cast to database type - log := database.LogFromLibrary(l) - - // validate the necessary fields are populated - err := log.Validate() - if err != nil { - return err - } - - // compress log data for the resource - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress - err = log.Compress(c.config.CompressionLevel) - if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableLog). - Create(log).Error -} - -// UpdateLog updates a log in the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) UpdateLog(l *library.Log) error { - // check if the log entry is for a step - if l.GetStepID() > 0 { - c.Logger.Tracef("updating log for step %d in the database", l.GetStepID()) - } else { - c.Logger.Tracef("updating log for service %d in the database", l.GetServiceID()) - } - - // cast to database type - log := database.LogFromLibrary(l) - - // validate the necessary fields are populated - err := log.Validate() - if err != nil { - return err - } - - // compress log data for the resource - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress - err = log.Compress(c.config.CompressionLevel) - if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableLog). - Save(log).Error -} - -// DeleteLog deletes a log by unique ID from the database. -func (c *client) DeleteLog(id int64) error { - c.Logger.Tracef("deleting log %d from the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableLog). - Exec(dml.DeleteLog, id).Error -} diff --git a/database/postgres/log_test.go b/database/postgres/log_test.go deleted file mode 100644 index 7173cecbf..000000000 --- a/database/postgres/log_test.go +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuildLogs(t *testing.T) { - // setup types - _logOne := testLog() - _logOne.SetID(1) - _logOne.SetStepID(1) - _logOne.SetBuildID(1) - _logOne.SetRepoID(1) - _logOne.SetData([]byte{}) - - _logTwo := testLog() - _logTwo.SetID(2) - _logTwo.SetServiceID(1) - _logTwo.SetBuildID(1) - _logTwo.SetRepoID(1) - _logTwo.SetData([]byte{}) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListBuildLogs, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}, - ).AddRow(1, 1, 1, 0, 1, []byte{}).AddRow(2, 1, 1, 1, 0, []byte{}) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Log - }{ - { - failure: false, - want: []*library.Log{_logOne, _logTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildLogs(1) - - if test.failure { - if err == nil { - t.Errorf("GetBuildLogs should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildLogs returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildLogs is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetStepLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectStepLog, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}, - ).AddRow(1, 1, 1, 0, 1, []byte{}) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Log - }{ - { - failure: false, - want: _log, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepLog(1) - - if test.failure { - if err == nil { - t.Errorf("GetStepLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepLog returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepLog is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetServiceLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetServiceID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectServiceLog, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "build_id", "repo_id", "service_id", "step_id", "data"}, - ).AddRow(1, 1, 1, 1, 0, []byte{}) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Log - }{ - { - failure: false, - want: _log, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceLog(1) - - if test.failure { - if err == nil { - t.Errorf("GetServiceLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceLog returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceLog is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "logs" ("build_id","repo_id","service_id","step_id","data","id") VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`). - WithArgs(1, 1, nil, 1, AnyArgument{}, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateLog(_log) - - if test.failure { - if err == nil { - t.Errorf("CreateLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateLog returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "logs" SET "build_id"=$1,"repo_id"=$2,"service_id"=$3,"step_id"=$4,"data"=$5 WHERE "id" = $6`). - WithArgs(1, 1, nil, 1, AnyArgument{}, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateLog(_log) - - if test.failure { - if err == nil { - t.Errorf("UpdateLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateLog returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteLog(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteLog, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteLog(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteLog returned err: %v", err) - } - } -} - -// testLog is a test helper function to create a -// library Log type with all fields set to their -// zero values. -func testLog() *library.Log { - i64 := int64(0) - b := []byte{} - - return &library.Log{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - ServiceID: &i64, - StepID: &i64, - Data: &b, - } -} diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index a4793ca56..a4199f316 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -10,6 +10,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" @@ -48,6 +49,8 @@ type ( Logger *logrus.Entry // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService hook.HookService + // https://pkg.go.dev/github.com/go-vela/server/database/log#LogService + log.LogService // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService @@ -152,14 +155,22 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { return nil, nil, err } + // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the log queries + _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the worker queries _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -248,12 +259,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the logs table - err = c.Postgres.Exec(ddl.CreateLogTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) - } - // create the secrets table err = c.Postgres.Exec(ddl.CreateSecretTable).Error if err != nil { @@ -304,12 +309,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the logs_build_id index for the logs table - err = c.Postgres.Exec(ddl.CreateLogBuildIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) - } - // create the secrets_type_org_repo index for the secrets table err = c.Postgres.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { @@ -347,6 +346,19 @@ func createServices(c *client) error { return err } + // create the database agnostic log service + // + // https://pkg.go.dev/github.com/go-vela/server/database/log#New + c.LogService, err = log.New( + log.WithClient(c.Postgres), + log.WithCompressionLevel(c.config.CompressionLevel), + log.WithLogger(c.Logger), + log.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic pipeline service // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index d00c540f3..97bb1c46c 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -11,6 +11,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" @@ -79,7 +80,6 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -89,7 +89,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -97,6 +96,9 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the log queries + _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -170,7 +172,6 @@ func TestPostgres_createTables(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateLogTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -216,7 +217,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateLogBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -260,6 +260,9 @@ func TestPostgres_createServices(t *testing.T) { // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the log queries + _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the pipeline queries _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/service.go b/database/service.go index 01ab1cf58..33517b484 100644 --- a/database/service.go +++ b/database/service.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,6 +6,7 @@ package database import ( "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/user" @@ -77,26 +78,9 @@ type Service interface { // related to hooks stored in the database. hook.HookService - // Log Database Interface Functions - - // GetStepLog defines a function that - // gets a step log by unique ID. - GetStepLog(int64) (*library.Log, error) - // GetServiceLog defines a function that - // gets a service log by unique ID. - GetServiceLog(int64) (*library.Log, error) - // GetBuildLogs defines a function that - // gets a list of logs by build ID. - GetBuildLogs(int64) ([]*library.Log, error) - // CreateLog defines a function that - // creates a new log. - CreateLog(*library.Log) error - // UpdateLog defines a function that - // updates a log. - UpdateLog(*library.Log) error - // DeleteLog defines a function that - // deletes a log by unique ID. - DeleteLog(int64) error + // LogService provides the interface for functionality + // related to logs stored in the database. + log.LogService // PipelineService provides the interface for functionality // related to pipelines stored in the database. diff --git a/database/sqlite/ddl/log.go b/database/sqlite/ddl/log.go deleted file mode 100644 index 225155bfb..000000000 --- a/database/sqlite/ddl/log.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateLogTable represents a query to - // create the logs table for Vela. - CreateLogTable = ` -CREATE TABLE -IF NOT EXISTS -logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - build_id INTEGER, - repo_id INTEGER, - service_id INTEGER, - step_id INTEGER, - data BLOB, - UNIQUE(step_id), - UNIQUE(service_id) -); -` - - // CreateLogBuildIDIndex represents a query to create an - // index on the logs table for the build_id column. - CreateLogBuildIDIndex = ` -CREATE INDEX -IF NOT EXISTS -logs_build_id -ON logs (build_id); -` -) diff --git a/database/sqlite/dml/log.go b/database/sqlite/dml/log.go deleted file mode 100644 index e3e904cc4..000000000 --- a/database/sqlite/dml/log.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListLogs represents a query to - // list all logs in the database. - ListLogs = ` -SELECT * -FROM logs; -` - - // ListBuildLogs represents a query to list - // all logs for a build_id in the database. - ListBuildLogs = ` -SELECT * -FROM logs -WHERE build_id = ? -ORDER BY step_id ASC; -` - - // SelectStepLog represents a query to select - // a log for a step_id in the database. - SelectStepLog = ` -SELECT * -FROM logs -WHERE step_id = ? -LIMIT 1; -` - - // SelectServiceLog represents a query to select - // a log for a service_id in the database. - SelectServiceLog = ` -SELECT * -FROM logs -WHERE service_id = ? -LIMIT 1; -` - - // DeleteLog represents a query to - // remove a log from the database. - DeleteLog = ` -DELETE -FROM logs -WHERE id = ?; -` -) diff --git a/database/sqlite/log.go b/database/sqlite/log.go deleted file mode 100644 index 037bdcc08..000000000 --- a/database/sqlite/log.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - "fmt" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetBuildLogs gets a collection of logs for a build by unique ID from the database. -func (c *client) GetBuildLogs(id int64) ([]*library.Log, error) { - c.Logger.Tracef("listing logs for build %d from the database", id) - - // variable to store query results - l := new([]database.Log) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableLog). - Raw(dml.ListBuildLogs, id). - Scan(l).Error - if err != nil { - return nil, err - } - - // variable we want to return - logs := []*library.Log{} - // iterate through all query results - for _, log := range *l { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := log - - // decompress log data for the step - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err = tmp.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for build %d: %v", id, err) - } - - // convert query result to library type - logs = append(logs, tmp.ToLibrary()) - } - - return logs, nil -} - -// GetStepLog gets a log by unique ID from the database. -// -//nolint:dupl // ignore similar code with service -func (c *client) GetStepLog(id int64) (*library.Log, error) { - c.Logger.Tracef("getting log for step %d from the database", id) - - // variable to store query results - l := new(database.Log) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableLog). - Raw(dml.SelectStepLog, id). - Scan(l) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decompress log data for the step - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err := l.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for step %d: %v", id, err) - - // return the uncompressed log - return l.ToLibrary(), result.Error - } - - // return the decompressed log - return l.ToLibrary(), result.Error -} - -// GetServiceLog gets a log by unique ID from the database. -// -//nolint:dupl // ignore similar code with step -func (c *client) GetServiceLog(id int64) (*library.Log, error) { - c.Logger.Tracef("getting log for service %d from the database", id) - - // variable to store query results - l := new(database.Log) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableLog). - Raw(dml.SelectServiceLog, id). - Scan(l) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - // decompress log data for the service - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Decompress - err := l.Decompress() - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allowing us to fetch uncompressed logs - c.Logger.Errorf("unable to decompress logs for service %d: %v", id, err) - - // return the uncompressed log - return l.ToLibrary(), result.Error - } - - // return the decompressed log - return l.ToLibrary(), result.Error -} - -// CreateLog creates a new log in the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) CreateLog(l *library.Log) error { - // check if the log entry is for a step - if l.GetStepID() > 0 { - c.Logger.Tracef("creating log for step %d in the database", l.GetStepID()) - } else { - c.Logger.Tracef("creating log for service %d in the database", l.GetServiceID()) - } - - // cast to database type - log := database.LogFromLibrary(l) - - // validate the necessary fields are populated - err := log.Validate() - if err != nil { - return err - } - - // compress log data for the resource - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress - err = log.Compress(c.config.CompressionLevel) - if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableLog). - Create(log).Error -} - -// UpdateLog updates a log in the database. -// -//nolint:dupl // ignore false positive of duplicate code -func (c *client) UpdateLog(l *library.Log) error { - // check if the log entry is for a step - if l.GetStepID() > 0 { - c.Logger.Tracef("updating log for step %d in the database", l.GetStepID()) - } else { - c.Logger.Tracef("updating log for service %d in the database", l.GetServiceID()) - } - - // cast to database type - log := database.LogFromLibrary(l) - - // validate the necessary fields are populated - err := log.Validate() - if err != nil { - return err - } - - // compress log data for the resource - // - // https://pkg.go.dev/github.com/go-vela/types/database#Log.Compress - err = log.Compress(c.config.CompressionLevel) - if err != nil { - return fmt.Errorf("unable to compress logs for step %d: %w", l.GetStepID(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableLog). - Save(log).Error -} - -// DeleteLog deletes a log by unique ID from the database. -func (c *client) DeleteLog(id int64) error { - c.Logger.Tracef("deleting log %d from the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableLog). - Exec(dml.DeleteLog, id).Error -} diff --git a/database/sqlite/log_test.go b/database/sqlite/log_test.go deleted file mode 100644 index a1a52a502..000000000 --- a/database/sqlite/log_test.go +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetBuildLogs(t *testing.T) { - // setup types - _logOne := testLog() - _logOne.SetID(1) - _logOne.SetStepID(1) - _logOne.SetBuildID(1) - _logOne.SetRepoID(1) - _logOne.SetData([]byte{}) - - _logTwo := testLog() - _logTwo.SetID(2) - _logTwo.SetServiceID(1) - _logTwo.SetBuildID(1) - _logTwo.SetRepoID(1) - _logTwo.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Log - }{ - { - failure: false, - want: []*library.Log{_logTwo, _logOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the logs table - defer _database.Sqlite.Exec("delete from logs;") - - for _, log := range test.want { - // create the log in the database - err := _database.CreateLog(log) - if err != nil { - t.Errorf("unable to create test log: %v", err) - } - } - - got, err := _database.GetBuildLogs(1) - - if test.failure { - if err == nil { - t.Errorf("GetBuildLogs should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildLogs returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildLogs is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetStepLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Log - }{ - { - failure: false, - want: _log, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the log in the database - err := _database.CreateLog(test.want) - if err != nil { - t.Errorf("unable to create test log: %v", err) - } - } - - got, err := _database.GetStepLog(1) - - // cleanup the logs table - _ = _database.Sqlite.Exec("DELETE FROM logs;") - - if test.failure { - if err == nil { - t.Errorf("GetStepLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepLog returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepLog is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetServiceLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetServiceID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Log - }{ - { - failure: false, - want: _log, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the log in the database - err := _database.CreateLog(test.want) - if err != nil { - t.Errorf("unable to create test log: %v", err) - } - } - - got, err := _database.GetServiceLog(1) - - // cleanup the logs table - _ = _database.Sqlite.Exec("DELETE FROM logs;") - - if test.failure { - if err == nil { - t.Errorf("GetServiceLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceLog returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceLog is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the logs table - defer _database.Sqlite.Exec("delete from logs;") - - err := _database.CreateLog(_log) - - if test.failure { - if err == nil { - t.Errorf("CreateLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateLog returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the logs table - defer _database.Sqlite.Exec("delete from logs;") - - // create the log in the database - err := _database.CreateLog(_log) - if err != nil { - t.Errorf("unable to create test log: %v", err) - } - - err = _database.UpdateLog(_log) - - if test.failure { - if err == nil { - t.Errorf("UpdateLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateLog returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteLog(t *testing.T) { - // setup types - _log := testLog() - _log.SetID(1) - _log.SetStepID(1) - _log.SetBuildID(1) - _log.SetRepoID(1) - _log.SetData([]byte{}) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the logs table - defer _database.Sqlite.Exec("delete from logs;") - - // create the log in the database - err := _database.CreateLog(_log) - if err != nil { - t.Errorf("unable to create test log: %v", err) - } - - err = _database.DeleteLog(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteLog should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteLog returned err: %v", err) - } - } -} - -// testLog is a test helper function to create a -// library Log type with all fields set to their -// zero values. -func testLog() *library.Log { - i64 := int64(0) - b := []byte{} - - return &library.Log{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - ServiceID: &i64, - StepID: &i64, - Data: &b, - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index d89a0ee2f..5018e8548 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -9,6 +9,7 @@ import ( "time" "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/sqlite/ddl" @@ -47,6 +48,8 @@ type ( Logger *logrus.Entry // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService hook.HookService + // https://pkg.go.dev/github.com/go-vela/server/database/log#LogService + log.LogService // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService @@ -236,12 +239,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the logs table - err = c.Sqlite.Exec(ddl.CreateLogTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableLog, err) - } - // create the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTable).Error if err != nil { @@ -292,12 +289,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the logs_build_id index for the logs table - err = c.Sqlite.Exec(ddl.CreateLogBuildIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create logs_build_id index for the %s table: %w", constants.TableLog, err) - } - // create the secrets_type_org_repo index for the secrets table err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgRepo).Error if err != nil { @@ -335,6 +326,19 @@ func createServices(c *client) error { return err } + // create the database agnostic log service + // + // https://pkg.go.dev/github.com/go-vela/server/database/log#New + c.LogService, err = log.New( + log.WithClient(c.Sqlite), + log.WithCompressionLevel(c.config.CompressionLevel), + log.WithLogger(c.Logger), + log.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic pipeline service // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New From a8149f4e5ec9195eb372ac8eca8752811d0c2b88 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:16:27 -0600 Subject: [PATCH 160/298] fix(deps): update deps (patch) (#750) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 31 +++++------ go.sum | 158 ++++++++++++--------------------------------------------- 2 files changed, 46 insertions(+), 143 deletions(-) diff --git a/go.mod b/go.mod index 027e10ab7..54dcb3127 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.23.1 - github.com/aws/aws-sdk-go v1.44.161 + github.com/aws/aws-sdk-go v1.44.209 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.8.1 @@ -22,22 +22,22 @@ require ( github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-retryablehttp v0.7.1 + github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/vault/api v1.8.2 github.com/joho/godotenv v1.4.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 - github.com/spf13/afero v1.9.3 + github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.23.7 go.starlark.net v0.0.0-20221205180719-3fd0dac74452 golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.4.5 - gorm.io/driver/sqlite v1.4.3 - gorm.io/gorm v1.24.2 - k8s.io/apimachinery v0.26.0 + gorm.io/driver/postgres v1.4.8 + gorm.io/driver/sqlite v1.4.4 + gorm.io/gorm v1.24.5 + k8s.io/apimachinery v0.26.1 ) require ( @@ -85,14 +85,9 @@ require ( github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/pgx/v4 v4.17.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -125,10 +120,10 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/crypto v0.3.0 // indirect - golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.6.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect diff --git a/go.sum b/go.sum index dfd246366..3046d4374 100644 --- a/go.sum +++ b/go.sum @@ -47,7 +47,6 @@ github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYI github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= @@ -73,8 +72,8 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.161 h1:uZdZJ30mlbaU2wsrd/wzibrX01cbgKE2t486TtRjeHs= -github.com/aws/aws-sdk-go v1.44.161/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.209 h1:wZuiaA4eaqYZmoZXqGgNHqVD7y7kUGFvACDGBgowTps= +github.com/aws/aws-sdk-go v1.44.209/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -100,13 +99,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -165,8 +159,6 @@ github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 h1:tdjas7NJLWlU2v github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -256,7 +248,6 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -271,8 +262,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= +github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= @@ -307,53 +298,13 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= +github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= @@ -380,7 +331,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -389,29 +339,20 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -501,33 +442,27 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs= +github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -535,8 +470,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= @@ -554,7 +490,6 @@ github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBU github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -564,36 +499,21 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20221205180719-3fd0dac74452 h1:JZtNuL6LPB+scU5yaQ6hqRlJFRiddZm2FwRt2AQqtHA= go.starlark.net v0.0.0-20221205180719-3fd0dac74452/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -642,7 +562,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -663,14 +582,13 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -695,6 +613,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -703,7 +622,6 @@ golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -711,10 +629,8 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -755,14 +671,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -772,8 +688,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -786,18 +702,14 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -805,7 +717,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -834,8 +745,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -946,7 +855,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -965,14 +873,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= -gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= -gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= -gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/postgres v1.4.8 h1:NDWizaclb7Q2aupT0jkwK8jx1HVCNzt+PQ8v/VnxviA= +gorm.io/driver/postgres v1.4.8/go.mod h1:O9MruWGNLUBUWVYfWuBClpf3HeGjOoybY0SNmCs3wsw= +gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= +gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0= gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE= +gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -980,8 +888,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg= -k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= +k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 4146511fc6ef2ad879a05a6a89b909cddffed61d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:28:54 -0600 Subject: [PATCH 161/298] fix(deps): update go.starlark.net digest to c52844e (#751) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 54dcb3127..7fef3ad08 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.23.7 - go.starlark.net v0.0.0-20221205180719-3fd0dac74452 + go.starlark.net v0.0.0-20230224151120-c52844e64a10 golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 3046d4374..9532e20eb 100644 --- a/go.sum +++ b/go.sum @@ -497,8 +497,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20221205180719-3fd0dac74452 h1:JZtNuL6LPB+scU5yaQ6hqRlJFRiddZm2FwRt2AQqtHA= -go.starlark.net v0.0.0-20221205180719-3fd0dac74452/go.mod h1:kIVgS18CjmEC3PqMd5kaJSGEifyV/CeB9x506ZJ1Vbk= +go.starlark.net v0.0.0-20230224151120-c52844e64a10 h1:lVljOiU1EFbXp5KnE9TBYNoV4zHQxkr4g9QbR9U6e04= +go.starlark.net v0.0.0-20230224151120-c52844e64a10/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From 82f6c6b3731ce9c5042f9b314e0e088854944fad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:35:32 -0600 Subject: [PATCH 162/298] fix(deps): update module github.com/alicebob/miniredis/v2 to v2.30.0 (#753) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7fef3ad08..93f332b59 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/alicebob/miniredis/v2 v2.23.1 + github.com/alicebob/miniredis/v2 v2.30.0 github.com/aws/aws-sdk-go v1.44.209 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 diff --git a/go.sum b/go.sum index 9532e20eb..b025a0055 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.23.1 h1:jR6wZggBxwWygeXcdNyguCOCIjPsZyNUNlAkTx2fu0U= -github.com/alicebob/miniredis/v2 v2.23.1/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= +github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= +github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= From 4cb4faec432487779baa7a8d18bbac89fcf1a845 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:46:16 -0600 Subject: [PATCH 163/298] fix(deps): update module github.com/google/go-github/v44 to v50 (#756) --- compiler/native/compile_test.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/github_test.go | 2 +- compiler/registry/github/template.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- scm/github/access.go | 2 +- scm/github/authentication.go | 2 +- scm/github/changeset.go | 2 +- scm/github/deployment.go | 2 +- scm/github/github.go | 2 +- scm/github/github_test.go | 2 +- scm/github/repo.go | 2 +- scm/github/webhook.go | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index e6f93f6d6..0dcb8e1e3 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/raw" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" "testing" "time" diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index ab7f13d45..f6d062898 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -9,7 +9,7 @@ import ( "net/url" "strings" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index 760ce9018..a3225c357 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index ea6b94a32..d867ec929 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // Template captures the templated pipeline configuration from the GitHub repo. diff --git a/go.mod b/go.mod index 93f332b59..4fd757986 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/google/go-cmp v0.5.9 - github.com/google/go-github/v44 v44.1.0 + github.com/google/go-github/v50 v50.1.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 diff --git a/go.sum b/go.sum index b025a0055..d0e679101 100644 --- a/go.sum +++ b/go.sum @@ -211,8 +211,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v44 v44.1.0 h1:shWPaufgdhr+Ad4eo/pZv9ORTxFpsxPEPEuuXAKIQGA= -github.com/google/go-github/v44 v44.1.0/go.mod h1:iWn00mWcP6PRWHhXm0zuFJ8wbEjE5AGO5D5HXYM4zgw= +github.com/google/go-github/v50 v50.1.0 h1:hMUpkZjklC5GJ+c3GquSqOP/T4BNsB7XohaPhtMOzRk= +github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/scm/github/access.go b/scm/github/access.go index c9f152cd1..cf292e5a7 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // OrgAccess captures the user's access level for an org. diff --git a/scm/github/authentication.go b/scm/github/authentication.go index fafc1be94..23f21eb4a 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -14,7 +14,7 @@ import ( "github.com/go-vela/server/random" "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // Authorize uses the given access token to authorize the user. diff --git a/scm/github/changeset.go b/scm/github/changeset.go index d2ad5187d..5c46960d8 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // Changeset captures the list of files changed for a commit. diff --git a/scm/github/deployment.go b/scm/github/deployment.go index a1a112efa..6617d1bf9 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/raw" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // GetDeployment gets a deployment from the GitHub repo. diff --git a/scm/github/github.go b/scm/github/github.go index 4bc9995b4..ef2854889 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" "github.com/sirupsen/logrus" "golang.org/x/oauth2" diff --git a/scm/github/github_test.go b/scm/github/github_test.go index 118f3be02..be1e084a0 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" "golang.org/x/oauth2" ) diff --git a/scm/github/repo.go b/scm/github/repo.go index cbc858e39..a3fc708fc 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // ConfigBackoff is a wrapper for Config that will retry five times if the function diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 2bf7c7b8b..d590eec12 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -19,7 +19,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v44/github" + "github.com/google/go-github/v50/github" ) // ProcessWebhook parses the webhook from a repo. From 56c313e4442eb496369f0855a0e65e0eaa975376 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:57:51 -0600 Subject: [PATCH 164/298] fix(deps): update module github.com/urfave/cli/v2 to v2.24.4 (#759) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4fd757986..507b729e1 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 - github.com/urfave/cli/v2 v2.23.7 + github.com/urfave/cli/v2 v2.24.4 go.starlark.net v0.0.0-20230224151120-c52844e64a10 golang.org/x/oauth2 v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index d0e679101..d0c5c869b 100644 --- a/go.sum +++ b/go.sum @@ -477,8 +477,8 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY= -github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU= +github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 8be8a48cb84dfbcf704be1a81e35cdab0f87a2e2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:07:36 -0600 Subject: [PATCH 165/298] fix(deps): update module golang.org/x/oauth2 to v0.5.0 (#760) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 507b729e1..c178d2b12 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.24.4 go.starlark.net v0.0.0-20230224151120-c52844e64a10 - golang.org/x/oauth2 v0.3.0 + golang.org/x/oauth2 v0.5.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.4.8 diff --git a/go.sum b/go.sum index d0c5c869b..aac772e16 100644 --- a/go.sum +++ b/go.sum @@ -600,8 +600,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 4c9778bc8be2a232075cfe3493bfc5dd08712f0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:17:32 -0600 Subject: [PATCH 166/298] fix(deps): update module github.com/joho/godotenv to v1.5.1 (#761) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c178d2b12..e1b856cc0 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/vault/api v1.8.2 - github.com/joho/godotenv v1.4.0 + github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index aac772e16..642ed710a 100644 --- a/go.sum +++ b/go.sum @@ -315,8 +315,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= From 0939253d31a867809ef8a91bd0bde8432492f960 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:23:38 -0600 Subject: [PATCH 167/298] fix(deps): update module github.com/hashicorp/vault/api to v1.9.0 (#762) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 20 +---------------- go.sum | 71 ++-------------------------------------------------------- 2 files changed, 3 insertions(+), 88 deletions(-) diff --git a/go.mod b/go.mod index e1b856cc0..a03edd23a 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.2 - github.com/hashicorp/vault/api v1.8.2 + github.com/hashicorp/vault/api v1.9.0 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 @@ -45,8 +45,6 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect - github.com/armon/go-metrics v0.3.9 // indirect - github.com/armon/go-radix v1.0.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect @@ -63,26 +61,16 @@ require ( github.com/goccy/go-json v0.9.7 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-hclog v0.16.2 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect - github.com/hashicorp/go-version v1.2.0 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/vault/sdk v0.6.0 // indirect - github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -101,14 +89,11 @@ require ( github.com/microcosm-cc/bluemonday v1.0.21 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/oklog/run v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect - github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect @@ -119,15 +104,12 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect - go.uber.org/atomic v1.9.0 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.6.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 // indirect - google.golang.org/grpc v1.41.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.80.1 // indirect diff --git a/go.sum b/go.sum index 642ed710a..2de520886 100644 --- a/go.sum +++ b/go.sum @@ -42,7 +42,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYIc= github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -66,12 +65,7 @@ github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGn github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= -github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.44.209 h1:wZuiaA4eaqYZmoZXqGgNHqVD7y7kUGFvACDGBgowTps= github.com/aws/aws-sdk-go v1.44.209/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -92,13 +86,10 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -114,13 +105,10 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= -github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -192,8 +180,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= @@ -243,31 +229,20 @@ 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/goware/urlx v0.3.2 h1:gdoo4kBHlkqZNaf6XlQ12LGtQOmpKJrR04Rc3RnpJEo= github.com/goware/urlx v0.3.2/go.mod h1:h8uwbJy68o+tQXCGZNa9D73WN8n0r9OBae5bUnLcgjw= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= -github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= @@ -275,23 +250,12 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.8.2 h1:C7OL9YtOtwQbTKI9ogB0A1wffRbCN+rH/LLCHO3d8HM= -github.com/hashicorp/vault/api v1.8.2/go.mod h1:ML8aYzBIhY5m1MD1B2Q0JV89cC85YVH4t5kBaZiyVaE= -github.com/hashicorp/vault/sdk v0.6.0 h1:6Z+In5DXHiUfZvIZdMx7e2loL1PPyDjA4bVh9ZTIAhs= -github.com/hashicorp/vault/sdk v0.6.0/go.mod h1:+DRpzoXIdMvKc88R4qxr+edwy/RvH5QK8itmxLiDHLc= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= +github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -305,7 +269,6 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZ github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -319,7 +282,6 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -349,12 +311,9 @@ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -370,8 +329,6 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -389,16 +346,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= -github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -410,7 +361,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= @@ -423,7 +373,6 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -431,13 +380,11 @@ github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8 github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= @@ -461,7 +408,6 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -473,7 +419,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= @@ -496,11 +441,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20230224151120-c52844e64a10 h1:lVljOiU1EFbXp5KnE9TBYNoV4zHQxkr4g9QbR9U6e04= go.starlark.net v0.0.0-20230224151120-c52844e64a10/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -620,7 +562,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -630,7 +571,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -799,7 +739,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -812,7 +751,6 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705 h1:PYBmACG+YEv8uQPW0r1kJj8tR+gkF0UWq7iFdUezwEw= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -827,13 +765,9 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -862,7 +796,6 @@ gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From 0f7bdd2b364f2a46c8608d9301d1ed59da5f554b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:32:00 -0600 Subject: [PATCH 168/298] fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.5.0 (#763) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a03edd23a..5ebf436c8 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 - github.com/golang-jwt/jwt/v4 v4.4.3 + github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 2de520886..16dfeda20 100644 --- a/go.sum +++ b/go.sum @@ -150,8 +150,8 @@ github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGF github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= -github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= From a44147916ec51a29e314a06bb9b3c6f1a34d39e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 08:50:32 -0600 Subject: [PATCH 169/298] chore(deps): bump golang.org/x/net (#766) --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 5ebf436c8..915cf4daf 100644 --- a/go.mod +++ b/go.mod @@ -105,7 +105,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect golang.org/x/crypto v0.6.0 // indirect - golang.org/x/net v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect diff --git a/go.sum b/go.sum index 16dfeda20..8f2e1b715 100644 --- a/go.sum +++ b/go.sum @@ -529,8 +529,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= From 822be06f677ad702baf3657bd6578ab537e5e630 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 09:02:19 -0600 Subject: [PATCH 170/298] fix(deps): update module github.com/gin-gonic/gin to v1.9.0 (#769) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- go.mod | 22 ++++++++++++++-------- go.sum | 54 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 915cf4daf..76ed677fb 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/aws/aws-sdk-go v1.44.209 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 - github.com/gin-gonic/gin v1.8.1 + github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 @@ -47,18 +47,20 @@ require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.8.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-logr/logr v1.2.3 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.10.0 // indirect - github.com/goccy/go-json v0.9.7 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect @@ -80,10 +82,11 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/lib/pq v1.10.7 // indirect github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/microcosm-cc/bluemonday v1.0.21 // indirect @@ -93,7 +96,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect @@ -101,9 +104,11 @@ require ( github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.3.1 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sys v0.5.0 // indirect @@ -112,5 +117,6 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.80.1 // indirect ) diff --git a/go.sum b/go.sum index 8f2e1b715..eed3d9d25 100644 --- a/go.sum +++ b/go.sum @@ -77,12 +77,18 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -114,8 +120,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -130,23 +136,22 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 h1:tdjas7NJLWlU2vmETaU36wjbd+zvWPLtznE4uwtnFlw= github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= -github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -292,6 +297,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -315,8 +322,8 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -348,9 +355,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -388,7 +394,6 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -419,9 +424,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU= github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= @@ -443,6 +449,8 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.starlark.net v0.0.0-20230224151120-c52844e64a10 h1:lVljOiU1EFbXp5KnE9TBYNoV4zHQxkr4g9QbR9U6e04= go.starlark.net v0.0.0-20230224151120-c52844e64a10/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -450,7 +458,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -603,13 +610,12 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= @@ -804,7 +810,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.4.8 h1:NDWizaclb7Q2aupT0jkwK8jx1HVCNzt+PQ8v/VnxviA= @@ -827,6 +832,7 @@ k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu7 k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= From d267ed2b4f80b269bc3f89a3906a7127381d6fc7 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:00:09 -0600 Subject: [PATCH 171/298] chore(queue): update go-redis to v9 (#771) --- go.mod | 4 ++-- go.sum | 14 ++++++-------- queue/redis/pop.go | 2 +- queue/redis/pop_test.go | 21 ++------------------- queue/redis/push.go | 9 +++++++++ queue/redis/push_test.go | 17 +++++++++++++++-- queue/redis/redis.go | 34 +++++++++++++++++----------------- 7 files changed, 52 insertions(+), 49 deletions(-) diff --git a/go.mod b/go.mod index 76ed677fb..257e157cc 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-redis/redis/v8 v8.11.5 github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 @@ -27,6 +26,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 + github.com/redis/go-redis/v9 v9.0.2 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.24.4 @@ -49,7 +49,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.8.0 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect diff --git a/go.sum b/go.sum index eed3d9d25..087576ceb 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ= +github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= @@ -84,8 +86,9 @@ github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3 github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -115,7 +118,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -144,8 +146,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 h1:tdjas7NJLWlU2vmETaU36wjbd+zvWPLtznE4uwtnFlw= @@ -352,9 +352,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -391,6 +388,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= +github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= @@ -798,7 +797,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/queue/redis/pop.go b/queue/redis/pop.go index 3f698a5f0..88151649b 100644 --- a/queue/redis/pop.go +++ b/queue/redis/pop.go @@ -9,8 +9,8 @@ import ( "encoding/json" "errors" - "github.com/go-redis/redis/v8" "github.com/go-vela/types" + "github.com/redis/go-redis/v9" ) // Pop grabs an item from the specified channel off the queue. diff --git a/queue/redis/pop_test.go b/queue/redis/pop_test.go index 772d98830..8ae6094b7 100644 --- a/queue/redis/pop_test.go +++ b/queue/redis/pop_test.go @@ -58,20 +58,8 @@ func TestRedis_Pop(t *testing.T) { // overwrite channel to be invalid badChannel.config.Channels = nil - // push nothing to queue - err = badChannel.Redis.RPush(context.Background(), "vela", nil).Err() - if err != nil { - t.Errorf("unable to push item to queue: %v", err) - } - - // setup badItem redis mock - badItem, err := NewTest("vela") - if err != nil { - t.Errorf("unable to create queue service: %v", err) - } - - // push nothing to queue - err = badItem.Redis.RPush(context.Background(), "vela", nil).Err() + // push something to badChannel queue + err = badChannel.Redis.RPush(context.Background(), "vela", bytes).Err() if err != nil { t.Errorf("unable to push item to queue: %v", err) } @@ -97,11 +85,6 @@ func TestRedis_Pop(t *testing.T) { redis: badChannel, want: nil, }, - { - failure: true, - redis: badItem, - want: nil, - }, } // run tests diff --git a/queue/redis/push.go b/queue/redis/push.go index 620e1174a..7ba97654f 100644 --- a/queue/redis/push.go +++ b/queue/redis/push.go @@ -6,12 +6,21 @@ package redis import ( "context" + "errors" ) // Push inserts an item to the specified channel in the queue. func (c *client) Push(ctx context.Context, channel string, item []byte) error { c.Logger.Tracef("pushing item to queue %s", channel) + // ensure the item to be pushed is valid + // go-redis RPush does not support nil as of v9.0.2 + // + // https://github.com/redis/go-redis/pull/1960 + if item == nil { + return errors.New("item is nil") + } + // build a redis queue command to push an item to queue // // https://pkg.go.dev/github.com/go-redis/redis?tab=doc#Client.RPush diff --git a/queue/redis/push_test.go b/queue/redis/push_test.go index 34980f0db..69af784e3 100644 --- a/queue/redis/push_test.go +++ b/queue/redis/push_test.go @@ -23,7 +23,7 @@ func TestRedis_Push(t *testing.T) { } // setup queue item - bytes, err := json.Marshal(_item) + _bytes, err := json.Marshal(_item) if err != nil { t.Errorf("unable to marshal queue item: %v", err) } @@ -34,20 +34,33 @@ func TestRedis_Push(t *testing.T) { t.Errorf("unable to create queue service: %v", err) } + // setup redis mock + badItem, err := NewTest("vela") + if err != nil { + t.Errorf("unable to create queue service: %v", err) + } + // setup tests tests := []struct { failure bool redis *client + bytes []byte }{ { failure: false, redis: _redis, + bytes: _bytes, + }, + { + failure: true, + redis: badItem, + bytes: nil, }, } // run tests for _, test := range tests { - err := _redis.Push(context.Background(), "vela", bytes) + err := test.redis.Push(context.Background(), "vela", test.bytes) if test.failure { if err == nil { diff --git a/queue/redis/redis.go b/queue/redis/redis.go index 2821e3cde..6ed111ec8 100644 --- a/queue/redis/redis.go +++ b/queue/redis/redis.go @@ -12,7 +12,7 @@ import ( "time" "github.com/alicebob/miniredis/v2" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" "github.com/sirupsen/logrus" ) @@ -97,22 +97,22 @@ func New(opts ...ClientOpt) (*client, error) { // the failover options from the parse options. func failoverFromOptions(source *redis.Options) *redis.FailoverOptions { target := &redis.FailoverOptions{ - OnConnect: source.OnConnect, - Password: source.Password, - DB: source.DB, - MaxRetries: source.MaxRetries, - MinRetryBackoff: source.MinRetryBackoff, - MaxRetryBackoff: source.MaxRetryBackoff, - DialTimeout: source.DialTimeout, - ReadTimeout: source.ReadTimeout, - WriteTimeout: source.WriteTimeout, - PoolSize: source.PoolSize, - MinIdleConns: source.MinIdleConns, - MaxConnAge: source.MaxConnAge, - PoolTimeout: source.PoolTimeout, - IdleTimeout: source.IdleTimeout, - IdleCheckFrequency: source.IdleCheckFrequency, - TLSConfig: source.TLSConfig, + OnConnect: source.OnConnect, + Password: source.Password, + DB: source.DB, + MaxRetries: source.MaxRetries, + MinRetryBackoff: source.MinRetryBackoff, + MaxRetryBackoff: source.MaxRetryBackoff, + DialTimeout: source.DialTimeout, + ReadTimeout: source.ReadTimeout, + WriteTimeout: source.WriteTimeout, + PoolSize: source.PoolSize, + MinIdleConns: source.MinIdleConns, + MaxIdleConns: source.MaxIdleConns, + ConnMaxLifetime: source.ConnMaxLifetime, + PoolTimeout: source.PoolTimeout, + ConnMaxIdleTime: source.ConnMaxIdleTime, + TLSConfig: source.TLSConfig, } // trim auto appended :6379 from address From 3c330f892d8de5c79900f1f7f38db52dbaf5ace9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:21:08 -0600 Subject: [PATCH 172/298] fix(deps): update go.starlark.net digest to dded032 (#774) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 257e157cc..facc909ca 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.24.4 - go.starlark.net v0.0.0-20230224151120-c52844e64a10 + go.starlark.net v0.0.0-20230228032650-dded03209ead golang.org/x/oauth2 v0.5.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 087576ceb..9b2b3a149 100644 --- a/go.sum +++ b/go.sum @@ -446,8 +446,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.starlark.net v0.0.0-20230224151120-c52844e64a10 h1:lVljOiU1EFbXp5KnE9TBYNoV4zHQxkr4g9QbR9U6e04= -go.starlark.net v0.0.0-20230224151120-c52844e64a10/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20230228032650-dded03209ead h1:qZOFk6/3JiKg5gjRTf4lShf/N0K3acJ95Bg70LsgnHI= +go.starlark.net v0.0.0-20230228032650-dded03209ead/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From 54689ef726e086ae9322d3561f640a8ffcc8f376 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:24:58 -0600 Subject: [PATCH 173/298] chore: v0.18.0-rc1 prep (#775) Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index facc909ca..a768e0e52 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 + github.com/go-vela/types v0.18.0-rc1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 @@ -89,7 +89,7 @@ require ( github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/microcosm-cc/bluemonday v1.0.21 // indirect + github.com/microcosm-cc/bluemonday v1.0.22 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/go.sum b/go.sum index 9b2b3a149..f7baad7d6 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyh github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425 h1:tdjas7NJLWlU2vmETaU36wjbd+zvWPLtznE4uwtnFlw= -github.com/go-vela/types v0.17.1-0.20230223155025-1c8a34f71425/go.mod h1:6KoRkvXMw9DkAcLdtI7PxPqMlT2Bl0DiigQamLGGjwo= +github.com/go-vela/types v0.18.0-rc1 h1:q93g+A/GOP56vmMi8AH1BKtgmqZy3gj5PD66Wqx8ej4= +github.com/go-vela/types v0.18.0-rc1/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -329,8 +329,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= -github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA= +github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= From 32522bb52a94ab76e2cdfe125f2616fbff6601c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 09:45:37 -0600 Subject: [PATCH 174/298] fix(deps): update deps (patch) (#777) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a768e0e52..125b5c082 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/alicebob/miniredis/v2 v2.30.0 - github.com/aws/aws-sdk-go v1.44.209 + github.com/aws/aws-sdk-go v1.44.211 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 @@ -37,7 +37,7 @@ require ( gorm.io/driver/postgres v1.4.8 gorm.io/driver/sqlite v1.4.4 gorm.io/gorm v1.24.5 - k8s.io/apimachinery v0.26.1 + k8s.io/apimachinery v0.26.2 ) require ( diff --git a/go.sum b/go.sum index f7baad7d6..fc8ebe276 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521I github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.209 h1:wZuiaA4eaqYZmoZXqGgNHqVD7y7kUGFvACDGBgowTps= -github.com/aws/aws-sdk-go v1.44.209/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzHK4= +github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -825,8 +825,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ= -k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= +k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 91f607ab5594abe08c918ef799773daae89c3344 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 1 Mar 2023 09:10:59 -0700 Subject: [PATCH 175/298] fix(perm): allow workers with build tokens to access MustRead() for private visibility repos (#776) * fix(perm): allow workers with build tokens to access MustRead() for private visibility repos * add error * user -> subject --- router/middleware/perm/perm.go | 16 ++++++ router/middleware/perm/perm_test.go | 82 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 560753ad8..fe7cea501 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -417,6 +417,7 @@ func MustWrite() gin.HandlerFunc { // MustRead ensures the user has admin, write or read access to the repo. func MustRead() gin.HandlerFunc { return func(c *gin.Context) { + cl := claims.Retrieve(c) o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) @@ -437,8 +438,23 @@ func MustRead() gin.HandlerFunc { return } + // return if request is from worker with build token access + if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { + b := build.Retrieve(c) + if cl.BuildID == b.GetID() { + return + } + + retErr := fmt.Errorf("subject %s does not have 'read' permissions for repo %s", cl.Subject, r.GetFullName()) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + logger.Debugf("verifying user %s has 'read' permissions for repo %s", u.GetName(), r.GetFullName()) + // return if user is platform admin if u.GetAdmin() { return } diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index a47dcef40..98b00aefd 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -1719,6 +1719,88 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { } } +func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { + // setup types + secret := "superSecret" + + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + } + + r := new(library.Repo) + r.SetID(1) + r.SetUserID(1) + r.SetHash("baz") + r.SetOrg("foo") + r.SetName("bar") + r.SetFullName("foo/bar") + r.SetVisibility("private") + + b := new(library.Build) + b.SetID(1) + b.SetRepoID(1) + b.SetNumber(1) + + mto := &token.MintTokenOpts{ + Hostname: "worker", + TokenDuration: time.Minute * 35, + TokenType: constants.WorkerBuildTokenType, + BuildID: 1, + Repo: "foo/bar", + } + + tok, _ := tm.MintToken(mto) + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + + // setup database + db, _ := sqlite.NewTest() + + defer func() { + db.Sqlite.Exec("delete from builds") + db.Sqlite.Exec("delete from repos;") + _sql, _ := db.Sqlite.DB() + _sql.Close() + }() + + _ = db.CreateBuild(b) + _ = db.CreateRepo(r) + + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(org.Establish()) + engine.Use(repo.Establish()) + engine.Use(build.Establish()) + engine.Use(MustRead()) + engine.GET("/test/:org/:repo/builds/:build", func(c *gin.Context) { + c.Status(http.StatusOK) + }) + + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustRead returned %v, want %v", resp.Code, http.StatusOK) + } +} + func TestPerm_MustRead_RepoAdmin(t *testing.T) { // setup types secret := "superSecret" From d24da14a8fa5a315b6446167237a888350c6b6a6 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Mon, 6 Mar 2023 11:01:29 -0600 Subject: [PATCH 176/298] chore: upgrade types to v0.18.0 (#783) * chore: upgrade types to v0.18.0 * fix: go mod tidy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 125b5c082..b8db472e6 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.18.0-rc1 + github.com/go-vela/types v0.18.0 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 diff --git a/go.sum b/go.sum index fc8ebe276..22d3d3f0d 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyh github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.18.0-rc1 h1:q93g+A/GOP56vmMi8AH1BKtgmqZy3gj5PD66Wqx8ej4= -github.com/go-vela/types v0.18.0-rc1/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/types v0.18.0 h1:GLKRphkpSZBl9Y62/1FyzZxSEvCLjzrlr0AQ+qhBcQo= +github.com/go-vela/types v0.18.0/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From d8995be22e7404fc57f23b7263f7618095d004d2 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:06:40 -0700 Subject: [PATCH 177/298] fix(database): revert column size bump to users token values (#784) --- database/user/table.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database/user/table.go b/database/user/table.go index 20a450b84..456853770 100644 --- a/database/user/table.go +++ b/database/user/table.go @@ -16,8 +16,8 @@ IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(250), - refresh_token VARCHAR(1000), - token VARCHAR(1000), + refresh_token VARCHAR(500), + token VARCHAR(500), hash VARCHAR(500), favorites VARCHAR(5000), active BOOLEAN, From a3ab6f02f60841a08ee12d695bf5a61311df310c Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:23:37 -0600 Subject: [PATCH 178/298] chore: v0.18.1 (#785) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b8db472e6..372f560f1 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.18.0 + github.com/go-vela/types v0.18.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 diff --git a/go.sum b/go.sum index 22d3d3f0d..9e3ba8725 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyh github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.18.0 h1:GLKRphkpSZBl9Y62/1FyzZxSEvCLjzrlr0AQ+qhBcQo= -github.com/go-vela/types v0.18.0/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/types v0.18.1 h1:V/luHLnCEaJhD1m9PZCZicIasg8Op6MCK+utkz+gQiU= +github.com/go-vela/types v0.18.1/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From 214b2bd1110beafcab9b1e318182f7d2c4930011 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 15 Mar 2023 12:05:28 -0500 Subject: [PATCH 179/298] chore: address #722 review feedback (#780) Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- database/hook/index.go | 2 +- database/log/get.go | 2 +- database/log/get_service.go | 2 +- database/log/get_step.go | 2 +- database/log/index.go | 2 +- database/log/list.go | 6 +++--- database/repo/index.go | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/database/hook/index.go b/database/hook/index.go index b81fd29f5..a2061eaf9 100644 --- a/database/hook/index.go +++ b/database/hook/index.go @@ -19,6 +19,6 @@ ON hooks (repo_id); func (e *engine) CreateHookIndexes() error { e.logger.Tracef("creating indexes for hooks table in the database") - // create the hostname and address columns index for the hooks table + // create the repo_id column index for the hooks table return e.client.Exec(CreateRepoIDIndex).Error } diff --git a/database/log/get.go b/database/log/get.go index d91a6687d..d31c6e1ef 100644 --- a/database/log/get.go +++ b/database/log/get.go @@ -34,7 +34,7 @@ func (e *engine) GetLog(id int64) (*library.Log, error) { if err != nil { // ensures that the change is backwards compatible // by logging the error instead of returning it - // which allowing us to fetch uncompressed logs + // which allows us to fetch uncompressed logs e.logger.Errorf("unable to decompress log %d: %v", id, err) // return the uncompressed log diff --git a/database/log/get_service.go b/database/log/get_service.go index 2d03bf127..38cf38a45 100644 --- a/database/log/get_service.go +++ b/database/log/get_service.go @@ -35,7 +35,7 @@ func (e *engine) GetLogForService(s *library.Service) (*library.Log, error) { if err != nil { // ensures that the change is backwards compatible // by logging the error instead of returning it - // which allowing us to fetch uncompressed logs + // which allows us to fetch uncompressed logs e.logger.Errorf("unable to decompress log for service %d for build %d: %v", s.GetID(), s.GetBuildID(), err) // return the uncompressed log diff --git a/database/log/get_step.go b/database/log/get_step.go index eb1b95c7f..92e503852 100644 --- a/database/log/get_step.go +++ b/database/log/get_step.go @@ -35,7 +35,7 @@ func (e *engine) GetLogForStep(s *library.Step) (*library.Log, error) { if err != nil { // ensures that the change is backwards compatible // by logging the error instead of returning it - // which allowing us to fetch uncompressed logs + // which allows us to fetch uncompressed logs e.logger.Errorf("unable to decompress log for step %d for build %d: %v", s.GetID(), s.GetBuildID(), err) // return the uncompressed log diff --git a/database/log/index.go b/database/log/index.go index 3ff3cdbc5..2ad50b642 100644 --- a/database/log/index.go +++ b/database/log/index.go @@ -19,6 +19,6 @@ ON logs (build_id); func (e *engine) CreateLogIndexes() error { e.logger.Tracef("creating indexes for logs table in the database") - // create the hostname and address columns index for the logs table + // create the build_id column index for the logs table return e.client.Exec(CreateBuildIDIndex).Error } diff --git a/database/log/list.go b/database/log/list.go index 703155a37..6a5381278 100644 --- a/database/log/list.go +++ b/database/log/list.go @@ -16,7 +16,7 @@ func (e *engine) ListLogs() ([]*library.Log, error) { // variables to store query results and return value count := int64(0) - h := new([]database.Log) + l := new([]database.Log) logs := []*library.Log{} // count the results @@ -33,14 +33,14 @@ func (e *engine) ListLogs() ([]*library.Log, error) { // send query to the database and store result in variable err = e.client. Table(constants.TableLog). - Find(&h). + Find(&l). Error if err != nil { return nil, err } // iterate through all query results - for _, log := range *h { + for _, log := range *l { // https://golang.org/doc/faq#closures_and_goroutines tmp := log diff --git a/database/repo/index.go b/database/repo/index.go index d112cccad..2bc7c5ffa 100644 --- a/database/repo/index.go +++ b/database/repo/index.go @@ -19,6 +19,6 @@ ON repos (org, name); func (e *engine) CreateRepoIndexes() error { e.logger.Tracef("creating indexes for repos table in the database") - // create the repo_id column index for the repos table + // create the org and name columns index for the repos table return e.client.Exec(CreateOrgNameIndex).Error } From 96b5d86f8833d0a36dbedd18682b3cd840e3edad Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 17 Mar 2023 09:37:37 -0600 Subject: [PATCH 180/298] fix(pipelines): support for file template type when gathering templates (#788) --- api/pipeline/template.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api/pipeline/template.go b/api/pipeline/template.go index 5529e3b74..4bb01cb19 100644 --- a/api/pipeline/template.go +++ b/api/pipeline/template.go @@ -7,6 +7,7 @@ package pipeline import ( "fmt" "net/http" + "strings" "github.com/gin-gonic/gin" "github.com/go-vela/server/compiler" @@ -127,8 +128,16 @@ func GetTemplates(c *gin.Context) { return } + // capture source path to template + source := template.Source + + // if type is file, compose a source string so the template can be found + if strings.EqualFold(template.Type, "file") { + source = fmt.Sprintf("%s%s/%s/%s@%s", registry.URL, o, r.GetName(), source, p.GetCommit()) + } + // parse the source for the template using the compiler registry client - src, err := registry.Parse(template.Source) + src, err := registry.Parse(source) if err != nil { util.HandleError(c, http.StatusBadRequest, fmt.Errorf("%s: unable to parse source for %s: %w", baseErr, template.Source, err)) From b42e80ff531b634232845aed1904f0255ce0bf0f Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 20 Mar 2023 21:05:05 -0500 Subject: [PATCH 181/298] refactor(api): move repo logic to separate package (#754) * refactor(api): move repo handlers to new package * enhance(perm): skip access checks for personal org * chore: changes from merge conflict * chore: address linter feedback * fix: failing tests for perms * chore: address review feedback * chore: address review feedback --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- api/repo.go | 1099 --------------------------- api/repo/chown.go | 81 ++ api/repo/create.go | 327 ++++++++ api/repo/delete.go | 109 +++ api/repo/get.go | 61 ++ api/repo/list.go | 130 ++++ api/repo/list_org.go | 163 ++++ api/repo/repair.go | 116 +++ api/repo/update.go | 255 +++++++ router/middleware/perm/perm.go | 14 +- router/middleware/perm/perm_test.go | 32 +- router/repo.go | 27 +- scm/github/access.go | 31 +- scm/github/repo.go | 8 +- 14 files changed, 1321 insertions(+), 1132 deletions(-) delete mode 100644 api/repo.go create mode 100644 api/repo/chown.go create mode 100644 api/repo/create.go create mode 100644 api/repo/delete.go create mode 100644 api/repo/get.go create mode 100644 api/repo/list.go create mode 100644 api/repo/list_org.go create mode 100644 api/repo/repair.go create mode 100644 api/repo/update.go diff --git a/api/repo.go b/api/repo.go deleted file mode 100644 index 375bb11fa..000000000 --- a/api/repo.go +++ /dev/null @@ -1,1099 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "encoding/base64" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/gin-gonic/gin" - "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/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/google/uuid" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/repos repos CreateRepo -// -// Create a repo in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Payload containing the repo to create -// required: true -// schema: -// "$ref": "#/definitions/Repo" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the repo -// schema: -// "$ref": "#/definitions/Repo" -// '400': -// description: Unable to create the repo -// schema: -// "$ref": "#/definitions/Error" -// '403': -// description: Unable to create the repo -// schema: -// "$ref": "#/definitions/Error" -// '409': -// description: Unable to create the repo -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the repo -// schema: -// "$ref": "#/definitions/Error" -// '503': -// description: Unable to create the repo -// schema: -// "$ref": "#/definitions/Error" - -// CreateRepo represents the API handler to -// create a repo in the configured backend. -// -//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity -func CreateRepo(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - allowlist := c.Value("allowlist").([]string) - defaultBuildLimit := c.Value("defaultBuildLimit").(int64) - defaultTimeout := c.Value("defaultTimeout").(int64) - maxBuildLimit := c.Value("maxBuildLimit").(int64) - defaultRepoEvents := c.Value("defaultRepoEvents").([]string) - - // capture body from API request - input := new(library.Repo) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new repo: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": input.GetOrg(), - "repo": input.GetName(), - "user": u.GetName(), - }).Infof("creating new repo %s", input.GetFullName()) - - // get repo information from the source - r, err := scm.FromContext(c).GetRepo(u, input) - if err != nil { - retErr := fmt.Errorf("unable to retrieve repo info for %s from source: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in repo object - r.SetUserID(u.GetID()) - - // set the active field based off the input provided - if input.Active == nil { - // default active field to true - r.SetActive(true) - } else { - r.SetActive(input.GetActive()) - } - - // set the build limit field based off the input provided - if input.GetBuildLimit() == 0 { - // default build limit to value configured by server - r.SetBuildLimit(defaultBuildLimit) - } else if input.GetBuildLimit() > maxBuildLimit { - // set build limit to value configured by server to prevent limit from exceeding max - r.SetBuildLimit(maxBuildLimit) - } else { - r.SetBuildLimit(input.GetBuildLimit()) - } - - // set the timeout field based off the input provided - if input.GetTimeout() == 0 && defaultTimeout == 0 { - // default build timeout to 30m - r.SetTimeout(constants.BuildTimeoutDefault) - } else if input.GetTimeout() == 0 { - r.SetTimeout(defaultTimeout) - } else { - r.SetTimeout(input.GetTimeout()) - } - - // set the visibility field based off the input provided - if len(input.GetVisibility()) == 0 { - // default visibility field to public - r.SetVisibility(constants.VisibilityPublic) - } else { - r.SetVisibility(input.GetVisibility()) - } - - // fields restricted to platform admins - if u.GetAdmin() { - // trusted default is false - if input.GetTrusted() != r.GetTrusted() { - r.SetTrusted(input.GetTrusted()) - } - } - - // set default events if no events are passed in - if !input.GetAllowPull() && !input.GetAllowPush() && - !input.GetAllowDeploy() && !input.GetAllowTag() && - !input.GetAllowComment() { - for _, event := range defaultRepoEvents { - switch event { - case constants.EventPull: - r.SetAllowPull(true) - case constants.EventPush: - r.SetAllowPush(true) - case constants.EventDeploy: - r.SetAllowDeploy(true) - case constants.EventTag: - r.SetAllowTag(true) - case constants.EventComment: - r.SetAllowComment(true) - } - } - } else { - r.SetAllowComment(input.GetAllowComment()) - r.SetAllowDeploy(input.GetAllowDeploy()) - r.SetAllowPull(input.GetAllowPull()) - r.SetAllowPush(input.GetAllowPush()) - r.SetAllowTag(input.GetAllowTag()) - } - - if len(input.GetPipelineType()) == 0 { - r.SetPipelineType(constants.PipelineTypeYAML) - } else { - // ensure the pipeline type matches one of the expected values - if input.GetPipelineType() != constants.PipelineTypeYAML && - input.GetPipelineType() != constants.PipelineTypeGo && - input.GetPipelineType() != constants.PipelineTypeStarlark { - retErr := fmt.Errorf("unable to create new repo %s: invalid pipeline_type provided %s", r.GetFullName(), input.GetPipelineType()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - r.SetPipelineType(input.GetPipelineType()) - } - - // create unique id for the repo - uid, err := uuid.NewRandom() - if err != nil { - retErr := fmt.Errorf("unable to create UID for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - r.SetHash( - base64.StdEncoding.EncodeToString( - []byte(strings.TrimSpace(uid.String())), - ), - ) - - // ensure repo is allowed to be activated - if !checkAllowlist(r, allowlist) { - retErr := fmt.Errorf("unable to activate repo: %s is not on allowlist", r.GetFullName()) - - util.HandleError(c, http.StatusForbidden, retErr) - - return - } - - // send API call to capture the repo from the database - dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) - if err == nil && dbRepo.GetActive() { - retErr := fmt.Errorf("unable to activate repo: %s is already active", r.GetFullName()) - - util.HandleError(c, http.StatusConflict, retErr) - - return - } - - // check if the repo already has a hash created - if len(dbRepo.GetHash()) > 0 { - // overwrite the new repo hash with the existing repo hash - r.SetHash(dbRepo.GetHash()) - } - - // send API call to create the webhook - if c.Value("webhookvalidation").(bool) { - _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) - if err != nil { - retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) - - switch err.Error() { - case "repo already enabled": - util.HandleError(c, http.StatusConflict, retErr) - return - case "repo not found": - util.HandleError(c, http.StatusNotFound, retErr) - return - } - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - // if the repo exists but is inactive - if len(dbRepo.GetOrg()) > 0 && !dbRepo.GetActive() { - // update the repo owner - dbRepo.SetUserID(u.GetID()) - // update the default branch - dbRepo.SetBranch(r.GetBranch()) - // activate the repo - dbRepo.SetActive(true) - - // send API call to update the repo - err = database.FromContext(c).UpdateRepo(dbRepo) - if err != nil { - retErr := fmt.Errorf("unable to set repo %s to active: %w", dbRepo.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepoForOrg(dbRepo.GetOrg(), dbRepo.GetName()) - } else { - // send API call to create the repo - err = database.FromContext(c).CreateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to create new repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created repo - r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) - } - - c.JSON(http.StatusCreated, r) -} - -// swagger:operation GET /api/v1/repos repos GetRepos -// -// Get all repos in the configured backend -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// parameters: -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// responses: -// '200': -// description: Successfully retrieved the repo -// schema: -// type: array -// items: -// "$ref": "#/definitions/Repo" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the repo -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the repo -// schema: -// "$ref": "#/definitions/Error" - -// GetRepos represents the API handler to capture a list -// of repos for a user from the configured backend. -func GetRepos(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("reading repos for user %s", u.GetName()) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // capture the sort_by query parameter if present - sortBy := util.QueryParameter(c, "sort_by", "name") - - // capture the query parameters if present: - // - // * active - filters := map[string]interface{}{ - "active": util.QueryParameter(c, "active", "true"), - } - - // send API call to capture the list of repos for the user - r, t, err := database.FromContext(c).ListReposForUser(u, sortBy, filters, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get repos for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, r) -} - -// swagger:operation GET /api/v1/repos/{org} repos GetOrgRepos -// -// Get all repos for the provided org in the configured backend -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: active -// description: Filter active repos -// type: boolean -// default: true -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// - in: query -// name: sort_by -// description: How to sort the results -// type: string -// enum: -// - name -// - latest -// default: name -// responses: -// '200': -// description: Successfully retrieved the repo -// schema: -// type: array -// items: -// "$ref": "#/definitions/Repo" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the org -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the org -// schema: -// "$ref": "#/definitions/Error" - -// GetOrgRepos represents the API handler to capture a list -// of repos for an org from the configured backend. -func GetOrgRepos(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "user": u.GetName(), - }).Infof("reading repos for org %s", o) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // capture the sort_by query parameter if present - sortBy := util.QueryParameter(c, "sort_by", "name") - - // capture the query parameters if present: - // - // * active - filters := map[string]interface{}{ - "active": util.QueryParameter(c, "active", "true"), - } - - // See if the user is an org admin to bypass individual permission checks - perm, err := scm.FromContext(c).OrgAccess(u, o) - if err != nil { - logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) - } - // Only show public repos to non-admins - if perm != "admin" { - filters["visibility"] = constants.VisibilityPublic - } - - // send API call to capture the list of repos for the org - r, t, err := database.FromContext(c).ListReposForOrg(o, sortBy, filters, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get repos for org %s: %w", o, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, r) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo} repos GetRepo -// -// Get a repo in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the repo -// schema: -// "$ref": "#/definitions/Repo" - -// GetRepo represents the API handler to -// capture a repo from the configured backend. -func GetRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading repo %s", r.GetFullName()) - - c.JSON(http.StatusOK, r) -} - -// swagger:operation PUT /api/v1/repos/{org}/{repo} repos UpdateRepo -// -// Update a repo in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: body -// name: body -// description: Payload containing the repo to update -// required: true -// schema: -// "$ref": "#/definitions/Repo" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the repo -// schema: -// "$ref": "#/definitions/Repo" -// '400': -// description: Unable to update the repo -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the repo -// schema: -// "$ref": "#/definitions/Error" -// '503': -// description: Unable to update the repo -// schema: -// "$ref": "#/definitions/Error" - -// UpdateRepo represents the API handler to update -// a repo in the configured backend. -// -//nolint:funlen // ignore line length -func UpdateRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - maxBuildLimit := c.Value("maxBuildLimit").(int64) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("updating repo %s", r.GetFullName()) - - // capture body from API request - input := new(library.Repo) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update repo fields if provided - if len(input.GetBranch()) > 0 { - // update branch if set - r.SetBranch(input.GetBranch()) - } - - // update build limit if set - if input.GetBuildLimit() > 0 { - // allow build limit between 1 - value configured by server - r.SetBuildLimit( - int64( - util.MaxInt( - constants.BuildLimitMin, - util.MinInt( - int(input.GetBuildLimit()), - int(maxBuildLimit), - ), // clamp max - ), // clamp min - ), - ) - } - - if input.GetTimeout() > 0 { - // update build timeout if set - r.SetTimeout( - int64( - util.MaxInt( - constants.BuildTimeoutMin, - util.MinInt( - int(input.GetTimeout()), - constants.BuildTimeoutMax, - ), // clamp max - ), // clamp min - ), - ) - } - - if input.GetCounter() > 0 { - if input.GetCounter() <= r.GetCounter() { - retErr := fmt.Errorf("unable to set counter for repo %s: must be greater than current %d", - r.GetFullName(), r.GetCounter()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - r.SetCounter(input.GetCounter()) - } - - if len(input.GetVisibility()) > 0 { - // update visibility if set - r.SetVisibility(input.GetVisibility()) - } - - if input.Private != nil { - // update private if set - r.SetPrivate(input.GetPrivate()) - } - - if input.Active != nil { - // update active if set - r.SetActive(input.GetActive()) - } - - if input.AllowPull != nil { - // update allow_pull if set - r.SetAllowPull(input.GetAllowPull()) - } - - if input.AllowPush != nil { - // update allow_push if set - r.SetAllowPush(input.GetAllowPush()) - } - - if input.AllowDeploy != nil { - // update allow_deploy if set - r.SetAllowDeploy(input.GetAllowDeploy()) - } - - if input.AllowTag != nil { - // update allow_tag if set - r.SetAllowTag(input.GetAllowTag()) - } - - if input.AllowComment != nil { - // update allow_comment if set - r.SetAllowComment(input.GetAllowComment()) - } - - // set default events if no events are enabled - if !r.GetAllowPull() && !r.GetAllowPush() && - !r.GetAllowDeploy() && !r.GetAllowTag() && - !r.GetAllowComment() { - r.SetAllowPull(true) - r.SetAllowPush(true) - } - - if len(input.GetPipelineType()) != 0 { - // ensure the pipeline type matches one of the expected values - if input.GetPipelineType() != constants.PipelineTypeYAML && - input.GetPipelineType() != constants.PipelineTypeGo && - input.GetPipelineType() != constants.PipelineTypeStarlark { - retErr := fmt.Errorf("pipeline_type of %s is invalid", input.GetPipelineType()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - r.SetPipelineType(input.GetPipelineType()) - } - - // set hash for repo if no hash is already set - if len(r.GetHash()) == 0 { - // create unique id for the repo - uid, err := uuid.NewRandom() - if err != nil { - retErr := fmt.Errorf("unable to create UID for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - r.SetHash( - base64.StdEncoding.EncodeToString( - []byte(strings.TrimSpace(uid.String())), - ), - ) - } - - // fields restricted to platform admins - if u.GetAdmin() { - // trusted - if input.GetTrusted() != r.GetTrusted() { - r.SetTrusted(input.GetTrusted()) - } - } - - // send API call to update the repo - err = database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) - - c.JSON(http.StatusOK, r) -} - -// swagger:operation DELETE /api/v1/repos/{org}/{repo} repos DeleteRepo -// -// Delete a repo in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the repo -// schema: -// type: string -// '500': -// description: Unable to deleted the repo -// schema: -// "$ref": "#/definitions/Error" -// '510': -// description: Unable to deleted the repo -// schema: -// "$ref": "#/definitions/Error" - -// DeleteRepo represents the API handler to remove -// a repo from the configured backend. -func DeleteRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("deleting repo %s", r.GetFullName()) - - // send API call to remove the webhook - err := scm.FromContext(c).Disable(u, r.GetOrg(), r.GetName()) - if err != nil { - retErr := fmt.Errorf("unable to delete webhook for %s: %w", r.GetFullName(), err) - - if err.Error() == "Repo not found" { - util.HandleError(c, http.StatusNotExtended, retErr) - - return - } - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // Mark the the repo as inactive - r.SetActive(false) - - err = database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to set repo %s to inactive: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // Comment out actual delete until delete mechanism is fleshed out - // err = database.FromContext(c).DeleteRepo(r.ID) - // if err != nil { - // retErr := fmt.Errorf("Error while deleting repo %s: %w", r.FullName, err) - // util.HandleError(c, http.StatusInternalServerError, retErr) - // return - // } - - c.JSON(http.StatusOK, fmt.Sprintf("repo %s deleted", r.GetFullName())) -} - -// swagger:operation PATCH /api/v1/repos/{org}/{repo}/repair repos RepairRepo -// -// Remove and recreate the webhook for a repo -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully repaired the repo -// schema: -// type: string -// '500': -// description: Unable to repair the repo -// schema: -// "$ref": "#/definitions/Error" - -// RepairRepo represents the API handler to remove -// and then create a webhook for a repo. -func RepairRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("repairing repo %s", r.GetFullName()) - - // send API call to remove the webhook - err := scm.FromContext(c).Disable(u, r.GetOrg(), r.GetName()) - if err != nil { - retErr := fmt.Errorf("unable to delete webhook for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to create the webhook - _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) - if err != nil { - retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // if the repo was previously inactive, mark it as active - if !r.GetActive() { - r.SetActive(true) - - // send API call to update the repo - err = database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to set repo %s to active: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - c.JSON(http.StatusOK, fmt.Sprintf("repo %s repaired", r.GetFullName())) -} - -// swagger:operation PATCH /api/v1/repos/{org}/{repo}/chown repos ChownRepo -// -// Change the owner of the webhook for a repo -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully changed the owner for the repo -// schema: -// type: string -// '500': -// description: Unable to change the owner for the repo -// schema: -// "$ref": "#/definitions/Error" - -// ChownRepo represents the API handler to change -// the owner of a repo in the configured backend. -func ChownRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("changing owner of repo %s to %s", r.GetFullName(), u.GetName()) - - // update repo owner - r.SetUserID(u.GetID()) - - // send API call to updated the repo - err := database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to change owner of repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("repo %s changed owner", r.GetFullName())) -} - -// checkAllowlist is a helper function to ensure only repos in the -// allowlist are allowed to enable repos. -// -// a single entry of '*' allows any repo to be enabled. -func checkAllowlist(r *library.Repo, allowlist []string) bool { - // check if all repos are allowed to be enabled - if len(allowlist) == 1 && allowlist[0] == "*" { - return true - } - - for _, repo := range allowlist { - // allow all repos in org - if strings.Contains(repo, "/*") { - if strings.HasPrefix(repo, r.GetOrg()) { - return true - } - } - - // allow specific repo within org - if repo == r.GetFullName() { - return true - } - } - - return false -} diff --git a/api/repo/chown.go b/api/repo/chown.go new file mode 100644 index 000000000..00e728128 --- /dev/null +++ b/api/repo/chown.go @@ -0,0 +1,81 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation PATCH /api/v1/repos/{org}/{repo}/chown repos ChownRepo +// +// Change the owner of the webhook for a repo +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully changed the owner for the repo +// schema: +// type: string +// '500': +// description: Unable to change the owner for the repo +// schema: +// "$ref": "#/definitions/Error" + +// ChownRepo represents the API handler to change +// the owner of a repo in the configured backend. +func ChownRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("changing owner of repo %s to %s", r.GetFullName(), u.GetName()) + + // update repo owner + r.SetUserID(u.GetID()) + + // send API call to update the repo + err := database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to change owner of repo %s to %s: %w", r.GetFullName(), u.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("repo %s changed owner to %s", r.GetFullName(), u.GetName())) +} diff --git a/api/repo/create.go b/api/repo/create.go new file mode 100644 index 000000000..d163d6320 --- /dev/null +++ b/api/repo/create.go @@ -0,0 +1,327 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "encoding/base64" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "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/constants" + "github.com/go-vela/types/library" + "github.com/google/uuid" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos repos CreateRepo +// +// Create a repo in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Payload containing the repo to create +// required: true +// schema: +// "$ref": "#/definitions/Repo" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the repo +// schema: +// "$ref": "#/definitions/Repo" +// '400': +// description: Unable to create the repo +// schema: +// "$ref": "#/definitions/Error" +// '403': +// description: Unable to create the repo +// schema: +// "$ref": "#/definitions/Error" +// '409': +// description: Unable to create the repo +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the repo +// schema: +// "$ref": "#/definitions/Error" +// '503': +// description: Unable to create the repo +// schema: +// "$ref": "#/definitions/Error" + +// CreateRepo represents the API handler to +// create a repo in the configured backend. +// +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity +func CreateRepo(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + allowlist := c.Value("allowlist").([]string) + defaultBuildLimit := c.Value("defaultBuildLimit").(int64) + defaultTimeout := c.Value("defaultTimeout").(int64) + maxBuildLimit := c.Value("maxBuildLimit").(int64) + defaultRepoEvents := c.Value("defaultRepoEvents").([]string) + + // capture body from API request + input := new(library.Repo) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new repo: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": input.GetOrg(), + "repo": input.GetName(), + "user": u.GetName(), + }).Infof("creating new repo %s", input.GetFullName()) + + // get repo information from the source + r, err := scm.FromContext(c).GetRepo(u, input) + if err != nil { + retErr := fmt.Errorf("unable to retrieve repo info for %s from source: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in repo object + r.SetUserID(u.GetID()) + + // set the active field based off the input provided + if input.Active == nil { + // default active field to true + r.SetActive(true) + } else { + r.SetActive(input.GetActive()) + } + + // set the build limit field based off the input provided + if input.GetBuildLimit() == 0 { + // default build limit to value configured by server + r.SetBuildLimit(defaultBuildLimit) + } else if input.GetBuildLimit() > maxBuildLimit { + // set build limit to value configured by server to prevent limit from exceeding max + r.SetBuildLimit(maxBuildLimit) + } else { + r.SetBuildLimit(input.GetBuildLimit()) + } + + // set the timeout field based off the input provided + if input.GetTimeout() == 0 && defaultTimeout == 0 { + // default build timeout to 30m + r.SetTimeout(constants.BuildTimeoutDefault) + } else if input.GetTimeout() == 0 { + r.SetTimeout(defaultTimeout) + } else { + r.SetTimeout(input.GetTimeout()) + } + + // set the visibility field based off the input provided + if len(input.GetVisibility()) == 0 { + // default visibility field to public + r.SetVisibility(constants.VisibilityPublic) + } else { + r.SetVisibility(input.GetVisibility()) + } + + // fields restricted to platform admins + if u.GetAdmin() { + // trusted default is false + if input.GetTrusted() != r.GetTrusted() { + r.SetTrusted(input.GetTrusted()) + } + } + + // set default events if no events are passed in + if !input.GetAllowPull() && !input.GetAllowPush() && + !input.GetAllowDeploy() && !input.GetAllowTag() && + !input.GetAllowComment() { + for _, event := range defaultRepoEvents { + switch event { + case constants.EventPull: + r.SetAllowPull(true) + case constants.EventPush: + r.SetAllowPush(true) + case constants.EventDeploy: + r.SetAllowDeploy(true) + case constants.EventTag: + r.SetAllowTag(true) + case constants.EventComment: + r.SetAllowComment(true) + } + } + } else { + r.SetAllowComment(input.GetAllowComment()) + r.SetAllowDeploy(input.GetAllowDeploy()) + r.SetAllowPull(input.GetAllowPull()) + r.SetAllowPush(input.GetAllowPush()) + r.SetAllowTag(input.GetAllowTag()) + } + + if len(input.GetPipelineType()) == 0 { + r.SetPipelineType(constants.PipelineTypeYAML) + } else { + // ensure the pipeline type matches one of the expected values + if input.GetPipelineType() != constants.PipelineTypeYAML && + input.GetPipelineType() != constants.PipelineTypeGo && + input.GetPipelineType() != constants.PipelineTypeStarlark { + retErr := fmt.Errorf("unable to create new repo %s: invalid pipeline_type provided %s", r.GetFullName(), input.GetPipelineType()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + r.SetPipelineType(input.GetPipelineType()) + } + + // create unique id for the repo + uid, err := uuid.NewRandom() + if err != nil { + retErr := fmt.Errorf("unable to create UID for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + r.SetHash( + base64.StdEncoding.EncodeToString( + []byte(strings.TrimSpace(uid.String())), + ), + ) + + // ensure repo is allowed to be activated + if !checkAllowlist(r, allowlist) { + retErr := fmt.Errorf("unable to activate repo: %s is not on allowlist", r.GetFullName()) + + util.HandleError(c, http.StatusForbidden, retErr) + + return + } + + // send API call to capture the repo from the database + dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + if err == nil && dbRepo.GetActive() { + retErr := fmt.Errorf("unable to activate repo: %s is already active", r.GetFullName()) + + util.HandleError(c, http.StatusConflict, retErr) + + return + } + + // check if the repo already has a hash created + if len(dbRepo.GetHash()) > 0 { + // overwrite the new repo hash with the existing repo hash + r.SetHash(dbRepo.GetHash()) + } + + // check if we should create the webhook + if c.Value("webhookvalidation").(bool) { + // send API call to create the webhook + _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) + if err != nil { + retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) + + switch err.Error() { + case "repo already enabled": + util.HandleError(c, http.StatusConflict, retErr) + return + case "repo not found": + util.HandleError(c, http.StatusNotFound, retErr) + return + } + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + // if the repo exists but is inactive + if len(dbRepo.GetOrg()) > 0 && !dbRepo.GetActive() { + // update the repo owner + dbRepo.SetUserID(u.GetID()) + // update the default branch + dbRepo.SetBranch(r.GetBranch()) + // activate the repo + dbRepo.SetActive(true) + + // send API call to update the repo + err = database.FromContext(c).UpdateRepo(dbRepo) + if err != nil { + retErr := fmt.Errorf("unable to set repo %s to active: %w", dbRepo.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated repo + r, _ = database.FromContext(c).GetRepoForOrg(dbRepo.GetOrg(), dbRepo.GetName()) + } else { + // send API call to create the repo + err = database.FromContext(c).CreateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to create new repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created repo + r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + } + + c.JSON(http.StatusCreated, r) +} + +// checkAllowlist is a helper function to ensure only repos in the +// allowlist are allowed to enable repos. +// +// a single entry of '*' allows any repo to be enabled. +func checkAllowlist(r *library.Repo, allowlist []string) bool { + // check if all repos are allowed to be enabled + if len(allowlist) == 1 && allowlist[0] == "*" { + return true + } + + for _, repo := range allowlist { + // allow all repos in org + if strings.Contains(repo, "/*") { + if strings.HasPrefix(repo, r.GetOrg()) { + return true + } + } + + // allow specific repo within org + if repo == r.GetFullName() { + return true + } + } + + return false +} diff --git a/api/repo/delete.go b/api/repo/delete.go new file mode 100644 index 000000000..63649f2eb --- /dev/null +++ b/api/repo/delete.go @@ -0,0 +1,109 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo} repos DeleteRepo +// +// Delete a repo in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the repo +// schema: +// type: string +// '500': +// description: Unable to deleted the repo +// schema: +// "$ref": "#/definitions/Error" +// '510': +// description: Unable to deleted the repo +// schema: +// "$ref": "#/definitions/Error" + +// DeleteRepo represents the API handler to remove +// a repo from the configured backend. +func DeleteRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("deleting repo %s", r.GetFullName()) + + // send API call to remove the webhook + err := scm.FromContext(c).Disable(u, r.GetOrg(), r.GetName()) + if err != nil { + retErr := fmt.Errorf("unable to delete webhook for %s: %w", r.GetFullName(), err) + + if err.Error() == "Repo not found" { + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // Mark the repo as inactive + r.SetActive(false) + + err = database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to set repo %s to inactive: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // Comment out actual delete until delete mechanism is fleshed out + // err = database.FromContext(c).DeleteRepo(r.ID) + // if err != nil { + // retErr := fmt.Errorf("Error while deleting repo %s: %w", r.FullName, err) + // util.HandleError(c, http.StatusInternalServerError, retErr) + // return + // } + + c.JSON(http.StatusOK, fmt.Sprintf("repo %s set to inactive", r.GetFullName())) +} diff --git a/api/repo/get.go b/api/repo/get.go new file mode 100644 index 000000000..65cbede1b --- /dev/null +++ b/api/repo/get.go @@ -0,0 +1,61 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo} repos GetRepo +// +// Get a repo in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the repo +// schema: +// "$ref": "#/definitions/Repo" + +// GetRepo represents the API handler to +// capture a repo from the configured backend. +func GetRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading repo %s", r.GetFullName()) + + c.JSON(http.StatusOK, r) +} diff --git a/api/repo/list.go b/api/repo/list.go new file mode 100644 index 000000000..c4ea06c54 --- /dev/null +++ b/api/repo/list.go @@ -0,0 +1,130 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos repos ListRepos +// +// Get all repos in the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// parameters: +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// responses: +// '200': +// description: Successfully retrieved the repo +// schema: +// type: array +// items: +// "$ref": "#/definitions/Repo" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the repo +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the repo +// schema: +// "$ref": "#/definitions/Error" + +// ListRepos represents the API handler to capture a list +// of repos for a user from the configured backend. +func ListRepos(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("listing repos for user %s", u.GetName()) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // capture the sort_by query parameter if present + sortBy := util.QueryParameter(c, "sort_by", "name") + + // capture the query parameters if present: + // + // * active + filters := map[string]interface{}{ + "active": util.QueryParameter(c, "active", "true"), + } + + // send API call to capture the list of repos for the user + r, t, err := database.FromContext(c).ListReposForUser(u, sortBy, filters, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get repos for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, r) +} diff --git a/api/repo/list_org.go b/api/repo/list_org.go new file mode 100644 index 000000000..2a8353d03 --- /dev/null +++ b/api/repo/list_org.go @@ -0,0 +1,163 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org} repos ListReposForOrg +// +// Get all repos for the provided org in the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: query +// name: active +// description: Filter active repos +// type: boolean +// default: true +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// - in: query +// name: sort_by +// description: How to sort the results +// type: string +// enum: +// - name +// - latest +// default: name +// responses: +// '200': +// description: Successfully retrieved the repo +// schema: +// type: array +// items: +// "$ref": "#/definitions/Repo" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the org +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the org +// schema: +// "$ref": "#/definitions/Error" + +// ListReposForOrg represents the API handler to capture a list +// of repos for an org from the configured backend. +func ListReposForOrg(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "user": u.GetName(), + }).Infof("listing repos for org %s", o) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // capture the sort_by query parameter if present + sortBy := util.QueryParameter(c, "sort_by", "name") + + // capture the query parameters if present: + // + // * active + filters := map[string]interface{}{ + "active": util.QueryParameter(c, "active", "true"), + } + + // See if the user is an org admin to bypass individual permission checks + perm, err := scm.FromContext(c).OrgAccess(u, o) + if err != nil { + logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) + } + // Only show public repos to non-admins + if perm != "admin" { + filters["visibility"] = constants.VisibilityPublic + } + + // send API call to capture the list of repos for the org + r, t, err := database.FromContext(c).ListReposForOrg(o, sortBy, filters, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get repos for org %s: %w", o, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, r) +} diff --git a/api/repo/repair.go b/api/repo/repair.go new file mode 100644 index 000000000..cbe5295e1 --- /dev/null +++ b/api/repo/repair.go @@ -0,0 +1,116 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation PATCH /api/v1/repos/{org}/{repo}/repair repos RepairRepo +// +// Remove and recreate the webhook for a repo +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully repaired the repo +// schema: +// type: string +// '500': +// description: Unable to repair the repo +// schema: +// "$ref": "#/definitions/Error" + +// RepairRepo represents the API handler to remove +// and then create a webhook for a repo. +func RepairRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("repairing repo %s", r.GetFullName()) + + // check if we should create the webhook + if c.Value("webhookvalidation").(bool) { + // send API call to remove the webhook + err := scm.FromContext(c).Disable(u, r.GetOrg(), r.GetName()) + if err != nil { + retErr := fmt.Errorf("unable to delete webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to create the webhook + _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) + if err != nil { + retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) + + switch err.Error() { + case "repo already enabled": + util.HandleError(c, http.StatusConflict, retErr) + return + case "repo not found": + util.HandleError(c, http.StatusNotFound, retErr) + return + } + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + // if the repo was previously inactive, mark it as active + if !r.GetActive() { + r.SetActive(true) + + // send API call to update the repo + err := database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to set repo %s to active: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + c.JSON(http.StatusOK, fmt.Sprintf("repo %s repaired", r.GetFullName())) +} diff --git a/api/repo/update.go b/api/repo/update.go new file mode 100644 index 000000000..9ca114270 --- /dev/null +++ b/api/repo/update.go @@ -0,0 +1,255 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package repo + +import ( + "encoding/base64" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "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" + "github.com/google/uuid" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/repos/{org}/{repo} repos UpdateRepo +// +// Update a repo in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the repo to update +// required: true +// schema: +// "$ref": "#/definitions/Repo" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the repo +// schema: +// "$ref": "#/definitions/Repo" +// '400': +// description: Unable to update the repo +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the repo +// schema: +// "$ref": "#/definitions/Error" +// '503': +// description: Unable to update the repo +// schema: +// "$ref": "#/definitions/Error" + +// UpdateRepo represents the API handler to update +// a repo in the configured backend. +// +//nolint:funlen // ignore function length +func UpdateRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + maxBuildLimit := c.Value("maxBuildLimit").(int64) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("updating repo %s", r.GetFullName()) + + // capture body from API request + input := new(library.Repo) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update repo fields if provided + if len(input.GetBranch()) > 0 { + // update branch if set + r.SetBranch(input.GetBranch()) + } + + // update build limit if set + if input.GetBuildLimit() > 0 { + // allow build limit between 1 - value configured by server + r.SetBuildLimit( + int64( + util.MaxInt( + constants.BuildLimitMin, + util.MinInt( + int(input.GetBuildLimit()), + int(maxBuildLimit), + ), // clamp max + ), // clamp min + ), + ) + } + + if input.GetTimeout() > 0 { + // update build timeout if set + r.SetTimeout( + int64( + util.MaxInt( + constants.BuildTimeoutMin, + util.MinInt( + int(input.GetTimeout()), + constants.BuildTimeoutMax, + ), // clamp max + ), // clamp min + ), + ) + } + + if input.GetCounter() > 0 { + if input.GetCounter() <= r.GetCounter() { + retErr := fmt.Errorf("unable to set counter for repo %s: must be greater than current %d", + r.GetFullName(), r.GetCounter()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + r.SetCounter(input.GetCounter()) + } + + if len(input.GetVisibility()) > 0 { + // update visibility if set + r.SetVisibility(input.GetVisibility()) + } + + if input.Private != nil { + // update private if set + r.SetPrivate(input.GetPrivate()) + } + + if input.Active != nil { + // update active if set + r.SetActive(input.GetActive()) + } + + if input.AllowPull != nil { + // update allow_pull if set + r.SetAllowPull(input.GetAllowPull()) + } + + if input.AllowPush != nil { + // update allow_push if set + r.SetAllowPush(input.GetAllowPush()) + } + + if input.AllowDeploy != nil { + // update allow_deploy if set + r.SetAllowDeploy(input.GetAllowDeploy()) + } + + if input.AllowTag != nil { + // update allow_tag if set + r.SetAllowTag(input.GetAllowTag()) + } + + if input.AllowComment != nil { + // update allow_comment if set + r.SetAllowComment(input.GetAllowComment()) + } + + // set default events if no events are enabled + if !r.GetAllowPull() && !r.GetAllowPush() && + !r.GetAllowDeploy() && !r.GetAllowTag() && + !r.GetAllowComment() { + r.SetAllowPull(true) + r.SetAllowPush(true) + } + + if len(input.GetPipelineType()) != 0 { + // ensure the pipeline type matches one of the expected values + if input.GetPipelineType() != constants.PipelineTypeYAML && + input.GetPipelineType() != constants.PipelineTypeGo && + input.GetPipelineType() != constants.PipelineTypeStarlark { + retErr := fmt.Errorf("pipeline_type of %s is invalid", input.GetPipelineType()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + r.SetPipelineType(input.GetPipelineType()) + } + + // set hash for repo if no hash is already set + if len(r.GetHash()) == 0 { + // create unique id for the repo + uid, err := uuid.NewRandom() + if err != nil { + retErr := fmt.Errorf("unable to create UID for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + r.SetHash( + base64.StdEncoding.EncodeToString( + []byte(strings.TrimSpace(uid.String())), + ), + ) + } + + // fields restricted to platform admins + if u.GetAdmin() { + // trusted + if input.GetTrusted() != r.GetTrusted() { + r.SetTrusted(input.GetTrusted()) + } + } + + // send API call to update the repo + err = database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated repo + r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + + c.JSON(http.StatusOK, r) +} diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index fe7cea501..1cc6e397d 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -78,7 +78,7 @@ func MustWorker() gin.HandlerFunc { // validate claims as worker switch { - case (strings.EqualFold(cl.Subject, "vela-worker") && strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType)): + case strings.EqualFold(cl.Subject, "vela-worker") && strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType): return default: @@ -136,6 +136,8 @@ func MustBuildAccess() gin.HandlerFunc { } // MustSecretAdmin ensures the user has admin access to the org, repo or team. +// +//nolint:funlen // ignore function length func MustSecretAdmin() gin.HandlerFunc { return func(c *gin.Context) { cl := claims.Retrieve(c) @@ -256,6 +258,16 @@ func MustSecretAdmin() gin.HandlerFunc { } case constants.SecretShared: if n == "*" && m == "GET" { + // check if user is accessing shared secrets in personal org + if strings.EqualFold(o, u.GetName()) { + logger.WithFields(logrus.Fields{ + "org": o, + "user": u.GetName(), + }).Debugf("skipping gathering teams for user %s with org %s", u.GetName(), o) + + return + } + logger.Debugf("gathering teams user %s is a member of in the org %s", u.GetName(), o) teams, err := scm.FromContext(c).ListUsersTeamsForOrg(u, o) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 98b00aefd..93f4ddff9 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -41,7 +41,7 @@ func TestPerm_MustPlatformAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(true) @@ -121,7 +121,7 @@ func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -877,7 +877,7 @@ func TestPerm_MustAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -973,7 +973,7 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(true) @@ -1069,7 +1069,7 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1165,7 +1165,7 @@ func TestPerm_MustWrite(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1261,7 +1261,7 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(true) @@ -1357,7 +1357,7 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1453,7 +1453,7 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1549,7 +1549,7 @@ func TestPerm_MustRead(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1645,7 +1645,7 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(true) @@ -1823,7 +1823,7 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -1919,7 +1919,7 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -2015,7 +2015,7 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -2111,7 +2111,7 @@ func TestPerm_MustRead_NotRead(t *testing.T) { u := new(library.User) u.SetID(1) - u.SetName("foo") + u.SetName("foob") u.SetToken("bar") u.SetHash("baz") u.SetAdmin(false) @@ -2291,7 +2291,7 @@ const permNonePayload = ` const userPayload = ` { - "login": "foo", + "login": "foob", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", diff --git a/router/repo.go b/router/repo.go index 0ebbb3522..1383d71c2 100644 --- a/router/repo.go +++ b/router/repo.go @@ -7,10 +7,11 @@ package router import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/api" + "github.com/go-vela/server/api/repo" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/perm" - "github.com/go-vela/server/router/middleware/repo" + rmiddleware "github.com/go-vela/server/router/middleware/repo" ) // RepoHandlers is a function that extends the provided base router group @@ -52,32 +53,32 @@ import ( // DELETE /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs . func RepoHandlers(base *gin.RouterGroup) { // Repos endpoints - repos := base.Group("/repos") + _repos := base.Group("/repos") { - repos.POST("", middleware.Payload(), api.CreateRepo) - repos.GET("", api.GetRepos) + _repos.POST("", middleware.Payload(), repo.CreateRepo) + _repos.GET("", repo.ListRepos) // Org endpoints - org := repos.Group("/:org", org.Establish()) + org := _repos.Group("/:org", org.Establish()) { - org.GET("", api.GetOrgRepos) + org.GET("", repo.ListReposForOrg) org.GET("/builds", api.GetOrgBuilds) // Repo endpoints - repo := org.Group("/:repo", repo.Establish()) + _repo := org.Group("/:repo", rmiddleware.Establish()) { - repo.GET("", perm.MustRead(), api.GetRepo) - repo.PUT("", perm.MustAdmin(), middleware.Payload(), api.UpdateRepo) - repo.DELETE("", perm.MustAdmin(), api.DeleteRepo) - repo.PATCH("/repair", perm.MustAdmin(), api.RepairRepo) - repo.PATCH("/chown", perm.MustAdmin(), api.ChownRepo) + _repo.GET("", perm.MustRead(), repo.GetRepo) + _repo.PUT("", perm.MustAdmin(), middleware.Payload(), repo.UpdateRepo) + _repo.DELETE("", perm.MustAdmin(), repo.DeleteRepo) + _repo.PATCH("/repair", perm.MustAdmin(), repo.RepairRepo) + _repo.PATCH("/chown", perm.MustAdmin(), repo.ChownRepo) // Build endpoints // * Service endpoints // * Log endpoints // * Step endpoints // * Log endpoints - BuildHandlers(repo) + BuildHandlers(_repo) } // end of repo endpoints } // end of org endpoints } // end of repos endpoints diff --git a/scm/github/access.go b/scm/github/access.go index cf292e5a7..e9a276662 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -20,8 +20,13 @@ func (c *client) OrgAccess(u *library.User, org string) (string, error) { "user": u.GetName(), }).Tracef("capturing %s access level to org %s", u.GetName(), org) - // if user is accessing personal org - if strings.EqualFold(org, *u.Name) { + // check if user is accessing personal org + if strings.EqualFold(org, u.GetName()) { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "user": u.GetName(), + }).Debugf("skipping access level check for user %s with org %s", u.GetName(), org) + //nolint:goconst // ignore making constant return "admin", nil } @@ -51,6 +56,17 @@ func (c *client) RepoAccess(u *library.User, token, org, repo string) (string, e "user": u.GetName(), }).Tracef("capturing %s access level to repo %s/%s", u.GetName(), org, repo) + // check if user is accessing repo in personal org + if strings.EqualFold(org, u.GetName()) { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": repo, + "user": u.GetName(), + }).Debugf("skipping access level check for user %s with repo %s/%s", u.GetName(), org, repo) + + return "admin", nil + } + // create github oauth client with the given token client := c.newClientToken(token) @@ -71,6 +87,17 @@ func (c *client) TeamAccess(u *library.User, org, team string) (string, error) { "user": u.GetName(), }).Tracef("capturing %s access level to team %s/%s", u.GetName(), org, team) + // check if user is accessing team in personal org + if strings.EqualFold(org, u.GetName()) { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "team": team, + "user": u.GetName(), + }).Debugf("skipping access level check for user %s with team %s/%s", u.GetName(), org, team) + + return "admin", nil + } + // create GitHub OAuth client with user's token client := c.newClientToken(u.GetToken()) teams := []*github.Team{} diff --git a/scm/github/repo.go b/scm/github/repo.go index a3fc708fc..924d36000 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -98,7 +98,7 @@ func (c *client) Disable(u *library.User, org, name string) error { "org": org, "repo": name, "user": u.GetName(), - }).Tracef("deleting repository webhook for %s/%s", org, name) + }).Tracef("deleting repository webhooks for %s/%s", org, name) // create GitHub OAuth client with user's token client := c.newClientToken(*u.Token) @@ -132,6 +132,12 @@ func (c *client) Disable(u *library.User, org, name string) error { // skip if we have no hook IDs if len(ids) == 0 { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + "user": u.GetName(), + }).Warnf("no repository webhooks matching %s/webhook found for %s/%s", c.config.ServerWebhookAddress, org, name) + return nil } From b37567d9dba6c3d48a7b7717ed65c5cb70632b91 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 23 Mar 2023 09:09:04 -0600 Subject: [PATCH 182/298] enhance(scm/repo): mirror allowed events with sent events (#679) * enhance(scm/repo): mirror allowed events with sent events * change auto push to utilize or logic * update comments * move init hook db creation to after repo db creation * add required source id field and enable testing * chore(release): v0.16.2 prep * allow plat admins to update webhooks on owner's behalf * update last hook func * add logging for admin override * move logging to capture owner too --------- Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> Co-authored-by: Jordan Brockopp Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/repo/create.go | 18 ++++++- api/repo/repair.go | 13 ++++- api/repo/update.go | 45 +++++++++++++++++ scm/github/github.go | 1 + scm/github/repo.go | 106 +++++++++++++++++++++++++++++++++------- scm/github/repo_test.go | 69 +++++++++++++++++++++++++- scm/service.go | 5 +- 7 files changed, 236 insertions(+), 21 deletions(-) diff --git a/api/repo/create.go b/api/repo/create.go index d163d6320..b1abe89de 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -238,10 +238,11 @@ func CreateRepo(c *gin.Context) { r.SetHash(dbRepo.GetHash()) } + hook := new(library.Hook) // check if we should create the webhook if c.Value("webhookvalidation").(bool) { // send API call to create the webhook - _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) + hook, _, err = scm.FromContext(c).Enable(u, r) if err != nil { retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) @@ -296,6 +297,21 @@ func CreateRepo(c *gin.Context) { r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) } + // create init hook in the DB after repo has been added in order to capture its ID + if c.Value("webhookvalidation").(bool) { + // update initialization hook + hook.SetRepoID(r.GetID()) + // create first hook for repo in the database + err = database.FromContext(c).CreateHook(hook) + if err != nil { + retErr := fmt.Errorf("unable to create initialization webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + c.JSON(http.StatusCreated, r) } diff --git a/api/repo/repair.go b/api/repo/repair.go index cbe5295e1..0a5b7022a 100644 --- a/api/repo/repair.go +++ b/api/repo/repair.go @@ -78,7 +78,7 @@ func RepairRepo(c *gin.Context) { } // send API call to create the webhook - _, err = scm.FromContext(c).Enable(u, r.GetOrg(), r.GetName(), r.GetHash()) + hook, _, err := scm.FromContext(c).Enable(u, r) if err != nil { retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) @@ -95,6 +95,17 @@ func RepairRepo(c *gin.Context) { return } + + hook.SetRepoID(r.GetID()) + + err = database.FromContext(c).CreateHook(hook) + if err != nil { + retErr := fmt.Errorf("unable to create initialization webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } } // if the repo was previously inactive, mark it as active diff --git a/api/repo/update.go b/api/repo/update.go index 9ca114270..dbe1333ba 100644 --- a/api/repo/update.go +++ b/api/repo/update.go @@ -15,6 +15,7 @@ import ( "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/scm" "github.com/go-vela/server/util" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -238,6 +239,50 @@ func UpdateRepo(c *gin.Context) { } } + // grab last hook from repo to fetch the webhook ID + lastHook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // if repo has no hook deliveries, skip webhook update + if lastHook.GetWebhookID() != 0 { + // if user is platform admin, fetch the repo owner token to make changes to webhook + if u.GetAdmin() { + // capture admin name for logging + admn := u.GetName() + + u, err = database.FromContext(c).GetUser(r.GetUserID()) + if err != nil { + retErr := fmt.Errorf("unable to get repo owner of %s for platform admin webhook update: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // log admin override update repo hook + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("platform admin %s updating repo webhook events for repo %s", admn, r.GetFullName()) + } + // update webhook with new events + err = scm.FromContext(c).Update(u, r, lastHook.GetWebhookID()) + if err != nil { + retErr := fmt.Errorf("unable to update repo webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + // send API call to update the repo err = database.FromContext(c).UpdateRepo(r) if err != nil { diff --git a/scm/github/github.go b/scm/github/github.go index ef2854889..2bad8eca3 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -25,6 +25,7 @@ const ( eventDeployment = "deployment" eventIssueComment = "issue_comment" eventRepository = "repository" + eventInitialize = "initialize" ) var ctx = context.Background() diff --git a/scm/github/repo.go b/scm/github/repo.go index 924d36000..de39ca07b 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -151,47 +151,119 @@ func (c *client) Disable(u *library.User, org, name string) error { } // Enable activates a repo by creating the webhook. -func (c *client) Enable(u *library.User, org, name, secret string) (string, error) { +func (c *client) Enable(u *library.User, r *library.Repo) (*library.Hook, string, error) { c.Logger.WithFields(logrus.Fields{ - "org": org, - "repo": name, + "org": r.GetOrg(), + "repo": r.GetName(), "user": u.GetName(), - }).Tracef("creating repository webhook for %s/%s", org, name) + }).Tracef("creating repository webhook for %s/%s", r.GetOrg(), r.GetName()) // create GitHub OAuth client with user's token client := c.newClientToken(*u.Token) + // always listen to repository events in case of repo name change + events := []string{eventRepository} + + if r.GetAllowComment() { + events = append(events, eventIssueComment) + } + + if r.GetAllowDeploy() { + events = append(events, eventDeployment) + } + + if r.GetAllowPull() { + events = append(events, eventPullRequest) + } + + if r.GetAllowPush() || r.GetAllowTag() { + events = append(events, eventPush) + } + // create the hook object to make the API call hook := &github.Hook{ - Events: []string{ - eventPush, - eventPullRequest, - eventDeployment, - eventIssueComment, - eventRepository, - }, + Events: events, Config: map[string]interface{}{ "url": fmt.Sprintf("%s/webhook", c.config.ServerWebhookAddress), "content_type": "form", - "secret": secret, + "secret": r.GetHash(), }, Active: github.Bool(true), } // send API call to create the webhook - _, resp, err := client.Repositories.CreateHook(ctx, org, name, hook) + hookInfo, resp, err := client.Repositories.CreateHook(ctx, r.GetOrg(), r.GetName(), hook) + + // create the first hook for the repo and record its ID from GitHub + webhook := new(library.Hook) + webhook.SetWebhookID(hookInfo.GetID()) + webhook.SetSourceID(r.GetName() + "-" + eventInitialize) + webhook.SetCreated(hookInfo.GetCreatedAt().Unix()) + webhook.SetEvent(eventInitialize) + webhook.SetNumber(1) switch resp.StatusCode { case http.StatusUnprocessableEntity: - return "", fmt.Errorf("repo already enabled") + return nil, "", fmt.Errorf("repo already enabled") case http.StatusNotFound: - return "", fmt.Errorf("repo not found") + return nil, "", fmt.Errorf("repo not found") } // create the URL for the repo - url := fmt.Sprintf("%s/%s/%s", c.config.Address, org, name) + url := fmt.Sprintf("%s/%s/%s", c.config.Address, r.GetOrg(), r.GetName()) + + return webhook, url, err +} + +// Update edits a repo webhook. +func (c *client) Update(u *library.User, r *library.Repo, hookID int64) error { + c.Logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "user": u.GetName(), + }).Tracef("updating repository webhook for %s/%s", r.GetOrg(), r.GetName()) + + // create GitHub OAuth client with user's token + client := c.newClientToken(*u.Token) + + // always listen to repository events in case of repo name change + events := []string{eventRepository} + + if r.GetAllowComment() { + events = append(events, eventIssueComment) + } + + if r.GetAllowDeploy() { + events = append(events, eventDeployment) + } + + if r.GetAllowPull() { + events = append(events, eventPullRequest) + } + + if r.GetAllowPush() || r.GetAllowTag() { + events = append(events, eventPush) + } + + // create the hook object to make the API call + hook := &github.Hook{ + Events: events, + Config: map[string]interface{}{ + "url": fmt.Sprintf("%s/webhook", c.config.ServerWebhookAddress), + "content_type": "form", + "secret": r.GetHash(), + }, + Active: github.Bool(true), + } + + // send API call to update the webhook + _, _, err := client.Repositories.EditHook(ctx, r.GetOrg(), r.GetName(), hookID, hook) + + if err != nil { + return err + } - return url, err + return nil } // Status sends the commit status for the given SHA from the GitHub repo. diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 2d1d63ad9..6b56b6903 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -602,10 +602,26 @@ func TestGithub_Enable(t *testing.T) { u.SetName("foo") u.SetToken("bar") + wantHook := new(library.Hook) + wantHook.SetWebhookID(1) + wantHook.SetSourceID("bar-initialize") + wantHook.SetCreated(1315329987) + wantHook.SetNumber(1) + wantHook.SetEvent("initialize") + + r := new(library.Repo) + r.SetID(1) + r.SetName("bar") + r.SetOrg("foo") + r.SetHash("secret") + r.SetAllowPush(true) + r.SetAllowPull(true) + r.SetAllowDeploy(true) + client, _ := NewTest(s.URL) // run test - _, err := client.Enable(u, "foo", "bar", "secret") + got, _, err := client.Enable(u, r) if resp.Code != http.StatusOK { t.Errorf("Enable returned %v, want %v", resp.Code, http.StatusOK) @@ -614,6 +630,57 @@ func TestGithub_Enable(t *testing.T) { if err != nil { t.Errorf("Enable returned err: %v", err) } + + if !reflect.DeepEqual(wantHook, got) { + t.Errorf("Enable returned hook %v, want %v", got, wantHook) + } +} + +func TestGithub_Update(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.PATCH("/api/v3/repos/:org/:repo/hooks/:hook_id", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/hook.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + r := new(library.Repo) + r.SetID(1) + r.SetName("bar") + r.SetOrg("foo") + r.SetHash("secret") + r.SetAllowPush(true) + r.SetAllowPull(true) + r.SetAllowDeploy(true) + + hookID := int64(1) + + client, _ := NewTest(s.URL) + + // run test + err := client.Update(u, r, hookID) + + if resp.Code != http.StatusOK { + t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) + } + + if err != nil { + t.Errorf("Update returned err: %v", err) + } } func TestGithub_Status_Deployment(t *testing.T) { diff --git a/scm/service.go b/scm/service.go index b6e2fa781..5c42105ba 100644 --- a/scm/service.go +++ b/scm/service.go @@ -98,7 +98,10 @@ type Service interface { Disable(*library.User, string, string) error // Enable defines a function that activates // a repo by creating the webhook. - Enable(*library.User, string, string, string) (string, error) + Enable(*library.User, *library.Repo) (*library.Hook, string, error) + // Update defines a function that updates + // a webhook for a specified repo. + Update(*library.User, *library.Repo, int64) error // Status defines a function that sends the // commit status for the given SHA from a repo. Status(*library.User, *library.Build, string, string) error From 5ffbe819aa2947f952c8847ee33320514d1c98b6 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 23 Mar 2023 15:37:47 -0600 Subject: [PATCH 183/298] feat(auth): server side changes for new worker auth flow (#790) * initial work * adding symmetric token handling * incorporating constants * convert admin register token endpoint to be POST * pulling in types update * add server mocks and json tags to check in resp * handle symmetric token in worker endpoints * appease linter overlord * return properly when met with server worker token * add proper return to update worker too * add back actually updating the worker * add comments to create and update worker api func * add new endpoint for refresh, remove plat admin access to worker auth perm * mocks mocks mocks * fix mock, fix status returns, move check in update to refresh * update mock validate http method * use authorization not token in mock * retrieve plat admin for logging in register token + swagger updates * change return type of validate token * getting mocked by mock * update validate token mock comment --- api/admin/worker.go | 73 +++++++++++ api/build.go | 20 ++- api/token.go | 37 ++++++ api/worker.go | 159 +++++++++++++++++++++-- cmd/vela-server/main.go | 12 ++ cmd/vela-server/token.go | 12 +- cmd/vela-server/validate.go | 4 - go.mod | 2 +- go.sum | 4 +- internal/token/manager.go | 6 + internal/token/mint.go | 7 + mock/server/authentication.go | 14 ++ mock/server/server.go | 3 + mock/server/worker.go | 65 ++++++++- router/admin.go | 3 + router/build.go | 2 +- router/middleware/claims/claims.go | 21 +-- router/middleware/claims/claims_test.go | 60 ++++++--- router/middleware/executors/executors.go | 24 +++- router/middleware/perm/perm.go | 57 ++++++-- router/middleware/perm/perm_test.go | 123 +++++++++++------- router/router.go | 3 + router/worker.go | 6 +- 23 files changed, 599 insertions(+), 118 deletions(-) create mode 100644 api/admin/worker.go diff --git a/api/admin/worker.go b/api/admin/worker.go new file mode 100644 index 000000000..8c0f9978a --- /dev/null +++ b/api/admin/worker.go @@ -0,0 +1,73 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package admin + +import ( + "fmt" + "net/http" + + "github.com/go-vela/server/internal/token" + "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" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/admin/workers/{worker}/register-token admin RegisterToken +// +// Get a worker registration token +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: worker +// description: Hostname of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully generated registration token +// schema: +// "$ref": "#/definitions/Token" +// '401': +// description: Unauthorized +// schema: +// "$ref": "#/definitions/Error" + +// RegisterToken represents the API handler to +// generate a registration token for onboarding a worker. +func RegisterToken(c *gin.Context) { + // retrieve user from context + u := user.Retrieve(c) + + logrus.Infof("Platform admin %s: generating registration token", u.GetName()) + + host := util.PathParameter(c, "worker") + + tm := c.MustGet("token-manager").(*token.Manager) + rmto := &token.MintTokenOpts{ + Hostname: host, + TokenType: constants.WorkerRegisterTokenType, + TokenDuration: tm.WorkerRegisterTokenDuration, + } + + rt, err := tm.MintToken(rmto) + if err != nil { + retErr := fmt.Errorf("unable to generate registration token: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, library.Token{Token: &rt}) +} diff --git a/api/build.go b/api/build.go index 5be0c08d6..cb27dab14 100644 --- a/api/build.go +++ b/api/build.go @@ -1764,8 +1764,26 @@ func CancelBuild(c *gin.Context) { return } + tm := c.MustGet("token-manager").(*token.Manager) + + // set mint token options + mto := &token.MintTokenOpts{ + Hostname: "vela-server", + TokenType: constants.WorkerAuthTokenType, + TokenDuration: time.Minute * 1, + } + + // mint token + tkn, err := tm.MintToken(mto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // add the token to authenticate to the worker - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.MustGet("secret").(string))) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) // perform the request to the worker resp, err := client.Do(req) diff --git a/api/token.go b/api/token.go index 87a49288a..6c76439ec 100644 --- a/api/token.go +++ b/api/token.go @@ -7,9 +7,11 @@ package api import ( "fmt" "net/http" + "strings" "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/auth" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/util" "github.com/go-vela/types/library" @@ -65,3 +67,38 @@ func RefreshAccessToken(c *gin.Context) { c.JSON(http.StatusOK, library.Token{Token: &newAccessToken}) } + +// swagger:operation GET /validate-token authenticate ValidateServerToken +// +// Validate a server token +// +// --- +// produces: +// - application/json +// security: +// - CookieAuth: [] +// responses: +// '200': +// description: Successfully validated a token +// schema: +// type: string +// '401': +// description: Unauthorized +// schema: +// "$ref": "#/definitions/Error" + +// ValidateServerToken will return the claims of a valid server token +// if it is provided in the auth header. +func ValidateServerToken(c *gin.Context) { + cl := claims.Retrieve(c) + + if !strings.EqualFold(cl.Subject, "vela-server") { + retErr := fmt.Errorf("token is not a valid server token") + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + c.JSON(http.StatusOK, "valid server token") +} diff --git a/api/worker.go b/api/worker.go index 4951b182a..4ef613e78 100644 --- a/api/worker.go +++ b/api/worker.go @@ -7,8 +7,12 @@ package api import ( "fmt" "net/http" + "time" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/types/constants" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/worker" @@ -38,9 +42,9 @@ import ( // - ApiKeyAuth: [] // responses: // '201': -// description: Successfully created the worker +// description: Successfully created the worker and retrieved auth token // schema: -// type: string +// "$ref": "#definitions/Token" // '400': // description: Unable to create the worker // schema: @@ -55,6 +59,7 @@ import ( func CreateWorker(c *gin.Context) { // capture middleware values u := user.Retrieve(c) + cl := claims.Retrieve(c) // capture body from API request input := new(library.Worker) @@ -85,7 +90,46 @@ func CreateWorker(c *gin.Context) { return } - c.JSON(http.StatusCreated, fmt.Sprintf("worker %s created", input.GetHostname())) + switch cl.TokenType { + // if symmetric token configured, send back symmetric token + case constants.ServerWorkerTokenType: + if secret, ok := c.Value("secret").(string); ok { + tkn := new(library.Token) + tkn.SetToken(secret) + c.JSON(http.StatusCreated, tkn) + + return + } + + retErr := fmt.Errorf("symmetric token provided but not configured in server") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + // if worker register token, send back auth token + default: + tm := c.MustGet("token-manager").(*token.Manager) + + wmto := &token.MintTokenOpts{ + TokenType: constants.WorkerAuthTokenType, + TokenDuration: tm.WorkerAuthTokenDuration, + Hostname: cl.Subject, + } + + tkn := new(library.Token) + + wt, err := tm.MintToken(wmto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", input.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + tkn.SetToken(wt) + + c.JSON(http.StatusCreated, tkn) + } } // swagger:operation GET /api/v1/workers workers GetWorkers @@ -226,7 +270,7 @@ func GetWorker(c *gin.Context) { // "$ref": "#/definitions/Error" // UpdateWorker represents the API handler to -// create a worker in the configured backend. +// update a worker in the configured backend. func UpdateWorker(c *gin.Context) { // capture middleware values u := user.Retrieve(c) @@ -267,11 +311,6 @@ func UpdateWorker(c *gin.Context) { w.SetActive(input.GetActive()) } - if input.GetLastCheckedIn() > 0 { - // update LastCheckedIn if set - w.SetLastCheckedIn(input.GetLastCheckedIn()) - } - // send API call to update the worker err = database.FromContext(c).UpdateWorker(w) if err != nil { @@ -288,6 +327,108 @@ func UpdateWorker(c *gin.Context) { c.JSON(http.StatusOK, w) } +// swagger:operation POST /api/v1/workers/{worker}/refresh workers RefreshWorkerAuth +// +// Refresh authorization token for worker +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: worker +// description: Name of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully refreshed auth +// schema: +// "$ref": "#/definitions/Token" +// '400': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" + +// RefreshWorkerAuth represents the API handler to +// refresh the auth token for a worker. +func RefreshWorkerAuth(c *gin.Context) { + // capture middleware values + w := worker.Retrieve(c) + cl := claims.Retrieve(c) + + // set last checked in time + w.SetLastCheckedIn(time.Now().Unix()) + + // send API call to update the worker + err := database.FromContext(c).UpdateWorker(w) + if err != nil { + retErr := fmt.Errorf("unable to update worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "worker": w.GetHostname(), + }).Infof("refreshing worker %s authentication", w.GetHostname()) + + switch cl.TokenType { + // if symmetric token configured, send back symmetric token + case constants.ServerWorkerTokenType: + if secret, ok := c.Value("secret").(string); ok { + tkn := new(library.Token) + tkn.SetToken(secret) + c.JSON(http.StatusOK, tkn) + + return + } + + retErr := fmt.Errorf("symmetric token provided but not configured in server") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + // if worker auth / register token, send back auth token + case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: + tm := c.MustGet("token-manager").(*token.Manager) + + wmto := &token.MintTokenOpts{ + TokenType: constants.WorkerAuthTokenType, + TokenDuration: tm.WorkerAuthTokenDuration, + Hostname: cl.Subject, + } + + tkn := new(library.Token) + + wt, err := tm.MintToken(wmto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + tkn.SetToken(wt) + + c.JSON(http.StatusOK, tkn) + } +} + // swagger:operation DELETE /api/v1/workers/{worker} workers DeleteWorker // // Delete a worker for the configured backend diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index fd1ebfedf..0dff41473 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -147,6 +147,18 @@ func main() { Usage: "sets the duration of the buffer for build token expiration based on repo build timeout", Value: 5 * time.Minute, }, + &cli.DurationFlag{ + EnvVars: []string{"VELA_WORKER_AUTH_TOKEN_DURATION", "WORKER_AUTH_TOKEN_DURATION"}, + Name: "worker-auth-token-duration", + Usage: "sets the duration of the worker auth token", + Value: 20 * time.Minute, + }, + &cli.DurationFlag{ + EnvVars: []string{"VELA_WORKER_REGISTER_TOKEN_DURATION", "WORKER_REGISTER_TOKEN_DURATION"}, + Name: "worker-register-token-duration", + Usage: "sets the duration of the worker register token", + Value: 1 * time.Minute, + }, // Compiler Flags &cli.BoolFlag{ EnvVars: []string{"VELA_COMPILER_GITHUB", "COMPILER_GITHUB"}, diff --git a/cmd/vela-server/token.go b/cmd/vela-server/token.go index eae471373..2f406a16b 100644 --- a/cmd/vela-server/token.go +++ b/cmd/vela-server/token.go @@ -19,11 +19,13 @@ func setupTokenManager(c *cli.Context) *token.Manager { logrus.Debug("Creating token manager from CLI configuration") tm := &token.Manager{ - PrivateKey: c.String("vela-server-private-key"), - SignMethod: jwt.SigningMethodHS256, - UserAccessTokenDuration: c.Duration("user-access-token-duration"), - UserRefreshTokenDuration: c.Duration("user-refresh-token-duration"), - BuildTokenBufferDuration: c.Duration("build-token-buffer-duration"), + PrivateKey: c.String("vela-server-private-key"), + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: c.Duration("user-access-token-duration"), + UserRefreshTokenDuration: c.Duration("user-refresh-token-duration"), + BuildTokenBufferDuration: c.Duration("build-token-buffer-duration"), + WorkerAuthTokenDuration: c.Duration("worker-auth-token-duration"), + WorkerRegisterTokenDuration: c.Duration("worker-register-token-duration"), } return tm diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index 6b82e6b4e..bce8b12fb 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -52,10 +52,6 @@ func validateCore(c *cli.Context) error { return fmt.Errorf("clone-image (VELA_CLONE_IMAGE) flag is not properly configured") } - if len(c.String("vela-secret")) == 0 { - return fmt.Errorf("vela-secret (VELA_SECRET) flag is not properly configured") - } - if len(c.String("vela-server-private-key")) == 0 { return fmt.Errorf("vela-server-private-key (VELA_SERVER_PRIVATE_KEY) flag is not properly configured") } diff --git a/go.mod b/go.mod index 372f560f1..01e869534 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.18.1 + github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 diff --git a/go.sum b/go.sum index 9e3ba8725..9b8e2d8a7 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyh github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.18.1 h1:V/luHLnCEaJhD1m9PZCZicIasg8Op6MCK+utkz+gQiU= -github.com/go-vela/types v0.18.1/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c h1:lnCL1knUGvgZQG4YBHSs/CZnxNBfqFUBlGhyq9LO9uk= +github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/internal/token/manager.go b/internal/token/manager.go index 121e4fa0f..71d82fb49 100644 --- a/internal/token/manager.go +++ b/internal/token/manager.go @@ -25,4 +25,10 @@ type Manager struct { // BuildTokenBufferDuration specifies the additional token duration of build tokens beyond repo timeout BuildTokenBufferDuration time.Duration + + // WorkerAuthTokenDuration specifies the token duration for worker auth (check in) + WorkerAuthTokenDuration time.Duration + + // WorkerRegisterTokenDuration specifies the token duration for worker register + WorkerRegisterTokenDuration time.Duration } diff --git a/internal/token/mint.go b/internal/token/mint.go index e90c0c34f..6f1a23941 100644 --- a/internal/token/mint.go +++ b/internal/token/mint.go @@ -69,6 +69,13 @@ func (tm *Manager) MintToken(mto *MintTokenOpts) (string, error) { claims.Repo = mto.Repo claims.Subject = mto.Hostname + case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: + if len(mto.Hostname) == 0 { + return "", fmt.Errorf("missing host name for %s token", mto.TokenType) + } + + claims.Subject = mto.Hostname + default: return "", errors.New("invalid token type") } diff --git a/mock/server/authentication.go b/mock/server/authentication.go index e75217565..ea7bb76a1 100644 --- a/mock/server/authentication.go +++ b/mock/server/authentication.go @@ -73,3 +73,17 @@ func getAuthenticateFromToken(c *gin.Context) { c.JSON(http.StatusOK, body) } + +// validateToken returns mock response for a http GET. +// +// Don't pass "Authorization" in header to receive an unauthorized error message. +func validateToken(c *gin.Context) { + err := "error" + + token := c.Request.Header.Get("Authorization") + if len(token) == 0 { + c.AbortWithStatusJSON(http.StatusUnauthorized, types.Error{Message: &err}) + } + + c.JSON(http.StatusOK, "vela-server") +} diff --git a/mock/server/server.go b/mock/server/server.go index 1b1ebd7c7..e13368711 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -37,6 +37,7 @@ func FakeHandler() http.Handler { e.PUT("/api/v1/admin/step", updateStep) e.GET("/api/v1/admin/users", getUsers) e.PUT("/api/v1/admin/user", updateUser) + e.POST("/api/v1/admin/workers/:worker/register-token", registerToken) // mock endpoints for build calls e.GET("/api/v1/repos/:org/:repo/builds/:build", getBuild) @@ -128,12 +129,14 @@ func FakeHandler() http.Handler { e.GET("/api/v1/workers/:worker", getWorker) e.POST("/api/v1/workers", addWorker) e.PUT("/api/v1/workers/:worker", updateWorker) + e.POST("/api/v1/workers/:worker/refresh", refreshWorkerAuth) e.DELETE("/api/v1/workers/:worker", removeWorker) // mock endpoints for authentication calls e.GET("/token-refresh", getTokenRefresh) e.GET("/authenticate", getAuthenticate) e.POST("/authenticate/token", getAuthenticateFromToken) + e.GET("/validate-token", validateToken) return e } diff --git a/mock/server/worker.go b/mock/server/worker.go index ed79507bb..51aedfa80 100644 --- a/mock/server/worker.go +++ b/mock/server/worker.go @@ -58,6 +58,23 @@ const ( "last_checked_in": 1602612590 } ]` + + // AddWorkerResp represents a JSON return for adding a worker. + AddWorkerResp = `{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3b3JrZXIiLCJpYXQiOjE1MTYyMzkwMjIsInRva2VuX3R5cGUiOiJXb3JrZXJBdXRoIn0.qeULIimCJlrwsE0JykNpzBmMaHUbvfk0vkyAz2eEo38" + }` + + // RefreshWorkerAuthResp represents a JSON return for refreshing a worker's authentication. + RefreshWorkerAuthResp = `{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3b3JrZXIiLCJpYXQiOjE1MTYyMzkwMjIsInRva2VuX3R5cGUiOiJXb3JrZXJBdXRoIn0.qeULIimCJlrwsE0JykNpzBmMaHUbvfk0vkyAz2eEo38" + }` + + // RegisterTokenResp represents a JSON return for an admin requesting a registration token. + // + //nolint:gosec // not actual credentials + RegisterTokenResp = `{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3b3JrZXIiLCJpYXQiOjE1MTYyMzkwMjIsInRva2VuX3R5cGUiOiJXb3JrZXJSZWdpc3RlciJ9.gEzKaZB-sDd_gFCVF5uGo2mcf3iy9CrXDTLPZ6PTsTc" + }` ) // getWorkers returns mock JSON for a http GET. @@ -92,9 +109,9 @@ func getWorker(c *gin.Context) { // addWorker returns mock JSON for a http POST. func addWorker(c *gin.Context) { - data := []byte(WorkerResp) + data := []byte(AddWorkerResp) - var body library.Worker + var body library.Token _ = json.Unmarshal(data, &body) c.JSON(http.StatusCreated, body) @@ -122,6 +139,28 @@ func updateWorker(c *gin.Context) { c.JSON(http.StatusOK, body) } +// refreshWorkerAuth has a param :worker returns mock JSON for a http PUT. +// +// Pass "0" to :worker to test receiving a http 404 response. +func refreshWorkerAuth(c *gin.Context) { + w := c.Param("worker") + + if strings.EqualFold(w, "0") { + msg := fmt.Sprintf("Worker %s does not exist", w) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(RefreshWorkerAuthResp) + + var body library.Token + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + // removeWorker has a param :worker returns mock JSON for a http DELETE. // // Pass "0" to :worker to test receiving a http 404 response. @@ -138,3 +177,25 @@ func removeWorker(c *gin.Context) { c.JSON(http.StatusOK, fmt.Sprintf("Worker %s removed", w)) } + +// registerToken has a param :worker returns mock JSON for a http POST. +// +// Pass "0" to :worker to test receiving a http 401 response. +func registerToken(c *gin.Context) { + w := c.Param("worker") + + if strings.EqualFold(w, "0") { + msg := fmt.Sprintf("user %s is not a platform admin", w) + + c.AbortWithStatusJSON(http.StatusUnauthorized, types.Error{Message: &msg}) + + return + } + + data := []byte(RegisterTokenResp) + + var body library.Token + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusCreated, body) +} diff --git a/router/admin.go b/router/admin.go index f3dbb680f..f7fddf95f 100644 --- a/router/admin.go +++ b/router/admin.go @@ -53,5 +53,8 @@ func AdminHandlers(base *gin.RouterGroup) { // Admin user endpoint _admin.PUT("/user", admin.UpdateUser) + + // Admin worker endpoint + _admin.POST("/workers/:worker/register-token", admin.RegisterToken) } // end of admin endpoints } diff --git a/router/build.go b/router/build.go index 3abf130d9..c2e34e188 100644 --- a/router/build.go +++ b/router/build.go @@ -58,7 +58,7 @@ func BuildHandlers(base *gin.RouterGroup) { build.DELETE("", perm.MustPlatformAdmin(), api.DeleteBuild) build.DELETE("/cancel", executors.Establish(), perm.MustWrite(), api.CancelBuild) build.GET("/logs", perm.MustRead(), api.GetBuildLogs) - build.GET("/token", perm.MustWorker(), api.GetBuildToken) + build.GET("/token", perm.MustWorkerAuthToken(), api.GetBuildToken) // Service endpoints // * Log endpoints diff --git a/router/middleware/claims/claims.go b/router/middleware/claims/claims.go index bc0726c7a..5ba2784f6 100644 --- a/router/middleware/claims/claims.go +++ b/router/middleware/claims/claims.go @@ -24,8 +24,6 @@ func Retrieve(c *gin.Context) *token.Claims { // Establish sets the claims in the given context. func Establish() gin.HandlerFunc { return func(c *gin.Context) { - claims := new(token.Claims) - tm := c.MustGet("token-manager").(*token.Manager) // get the access token from the request at, err := auth.RetrieveAccessToken(c.Request) @@ -34,15 +32,18 @@ func Establish() gin.HandlerFunc { return } - // special handling for workers - secret := c.MustGet("secret").(string) - if strings.EqualFold(at, secret) { - claims.Subject = "vela-worker" - claims.TokenType = constants.ServerWorkerTokenType - ToContext(c, claims) - c.Next() + claims := new(token.Claims) - return + // special handling for workers if symmetric token is provided + if secret, ok := c.Value("secret").(string); ok { + if strings.EqualFold(at, secret) { + claims.Subject = "vela-worker" + claims.TokenType = constants.ServerWorkerTokenType + ToContext(c, claims) + c.Next() + + return + } } // parse and validate the token and return the associated the user diff --git a/router/middleware/claims/claims_test.go b/router/middleware/claims/claims_test.go index 239c97296..914c5882e 100644 --- a/router/middleware/claims/claims_test.go +++ b/router/middleware/claims/claims_test.go @@ -65,10 +65,12 @@ func TestClaims_Establish(t *testing.T) { user.SetFavorites([]string{}) tm := &token.Manager{ - PrivateKey: "123abc", - SignMethod: jwt.SigningMethodHS256, - UserAccessTokenDuration: time.Minute * 5, - UserRefreshTokenDuration: time.Minute * 30, + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + WorkerAuthTokenDuration: time.Minute * 20, + WorkerRegisterTokenDuration: time.Minute * 1, } now := time.Now() @@ -122,6 +124,42 @@ func TestClaims_Establish(t *testing.T) { CtxRequest: "/repos/foo/bar/builds/1", Endpoint: "repos/:org/:repo/builds/:build", }, + { + TokenType: constants.WorkerAuthTokenType, + WantClaims: &token.Claims{ + TokenType: constants.WorkerAuthTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "host", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerAuthTokenDuration)), + }, + }, + Mto: &token.MintTokenOpts{ + Hostname: "host", + TokenDuration: tm.WorkerAuthTokenDuration, + TokenType: constants.WorkerAuthTokenType, + }, + CtxRequest: "/workers/host", + Endpoint: "/workers/:hostname", + }, + { + TokenType: constants.WorkerRegisterTokenType, + WantClaims: &token.Claims{ + TokenType: constants.WorkerRegisterTokenType, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "host", + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerRegisterTokenDuration)), + }, + }, + Mto: &token.MintTokenOpts{ + Hostname: "host", + TokenDuration: tm.WorkerRegisterTokenDuration, + TokenType: constants.WorkerRegisterTokenType, + }, + CtxRequest: "/workers/host/register", + Endpoint: "workers/:hostname/register", + }, { TokenType: constants.ServerWorkerTokenType, WantClaims: &token.Claims{ @@ -135,17 +173,6 @@ func TestClaims_Establish(t *testing.T) { }, } - // setup database - db, _ := sqlite.NewTest() - - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() - - _ = db.CreateUser(user) - got := new(token.Claims) gin.SetMode(gin.TestMode) @@ -160,6 +187,7 @@ func TestClaims_Establish(t *testing.T) { if strings.EqualFold(tt.TokenType, constants.ServerWorkerTokenType) { tkn = "very-secret" + engine.Use(func(c *gin.Context) { c.Set("secret", "very-secret") }) } else { tkn, _ = tm.MintToken(tt.Mto) } @@ -171,8 +199,6 @@ func TestClaims_Establish(t *testing.T) { // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) - engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) - engine.Use(func(c *gin.Context) { c.Set("secret", "very-secret") }) engine.Use(Establish()) engine.PUT(tt.Endpoint, func(c *gin.Context) { got = Retrieve(c) diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index 96155eacb..145d134fb 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -14,8 +14,10 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" ) @@ -51,8 +53,26 @@ func Establish() gin.HandlerFunc { return } - // add the token to authenticate to the worker as a header - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.MustGet("secret").(string))) + tm := c.MustGet("token-manager").(*token.Manager) + + // set mint token options + mto := &token.MintTokenOpts{ + Hostname: "vela-server", + TokenType: constants.WorkerAuthTokenType, + TokenDuration: time.Minute * 1, + } + + // mint token + tkn, err := tm.MintToken(mto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // add the token to authenticate to the worker + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) // make the request to the worker and check the response resp, err := client.Do(req) diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 1cc6e397d..812c9a8fd 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -55,34 +55,65 @@ func MustPlatformAdmin() gin.HandlerFunc { } } -// MustWorker ensures the request is coming from an agent. -func MustWorker() gin.HandlerFunc { +// MustWorkerRegisterToken ensures the token is a registration token retrieved by a platform admin. +func MustWorkerRegisterToken() gin.HandlerFunc { return func(c *gin.Context) { cl := claims.Retrieve(c) - // global permissions bypass - if cl.IsAdmin { - logrus.WithFields(logrus.Fields{ - "user": cl.Subject, - }).Debugf("user %s has platform admin permissions", cl.Subject) + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + }).Debugf("verifying user %s has a registration token for worker", cl.Subject) + + switch cl.TokenType { + case constants.WorkerRegisterTokenType: + return + case constants.ServerWorkerTokenType: + if strings.EqualFold(cl.Subject, "vela-worker") { + return + } + + retErr := fmt.Errorf("server-worker token provided but does not match configuration") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + default: + retErr := fmt.Errorf("invalid token type: must provide a worker registration token") + util.HandleError(c, http.StatusUnauthorized, retErr) return } + } +} + +// MustWorkerAuthToken ensures the token is a worker auth token. +func MustWorkerAuthToken() gin.HandlerFunc { + return func(c *gin.Context) { + cl := claims.Retrieve(c) // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields logrus.WithFields(logrus.Fields{ - "subject": cl.Subject, - }).Debugf("verifying user %s is a worker", cl.Subject) + "worker": cl.Subject, + }).Debugf("verifying worker %s has a valid auth token", cl.Subject) - // validate claims as worker - switch { - case strings.EqualFold(cl.Subject, "vela-worker") && strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType): + switch cl.TokenType { + case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: return + case constants.ServerWorkerTokenType: + if strings.EqualFold(cl.Subject, "vela-worker") { + return + } + + retErr := fmt.Errorf("server-worker token provided but does not match configuration") + util.HandleError(c, http.StatusBadRequest, retErr) + return default: - retErr := fmt.Errorf("user %s is not a worker", cl.Subject) + retErr := fmt.Errorf("invalid token type: must provide a worker auth token") util.HandleError(c, http.StatusUnauthorized, retErr) return diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 93f4ddff9..61ebf596e 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -188,17 +188,25 @@ func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { } } -func TestPerm_MustWorker(t *testing.T) { +func TestPerm_MustWorkerRegisterToken(t *testing.T) { // setup types - secret := "superSecret" - tm := &token.Manager{ - PrivateKey: "123abc", - SignMethod: jwt.SigningMethodHS256, - UserAccessTokenDuration: time.Minute * 5, - UserRefreshTokenDuration: time.Minute * 30, + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + WorkerRegisterTokenDuration: time.Minute * 1, + WorkerAuthTokenDuration: time.Minute * 15, + } + + mto := &token.MintTokenOpts{ + Hostname: "worker", + TokenDuration: tm.WorkerRegisterTokenDuration, + TokenType: constants.WorkerRegisterTokenType, } + tok, _ := tm.MintToken(mto) + // setup context gin.SetMode(gin.TestMode) @@ -206,14 +214,13 @@ func TestPerm_MustWorker(t *testing.T) { context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) - context.Request.Header.Add("Authorization", fmt.Sprint(secret)) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(claims.Establish()) engine.Use(user.Establish()) - engine.Use(MustWorker()) + engine.Use(MustWorkerRegisterToken()) engine.GET("/test/:org/:repo", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -225,14 +232,11 @@ func TestPerm_MustWorker(t *testing.T) { engine.ServeHTTP(context.Writer, context.Request) if resp.Code != http.StatusOK { - t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusOK) + t.Errorf("MustWorkerRegisterToken returned %v, want %v", resp.Code, http.StatusOK) } } -func TestPerm_MustWorker_PlatAdmin(t *testing.T) { - // setup types - secret := "superSecret" - +func TestPerm_MustWorkerRegisterToken_PlatAdmin(t *testing.T) { tm := &token.Manager{ PrivateKey: "123abc", SignMethod: jwt.SigningMethodHS256, @@ -276,12 +280,11 @@ func TestPerm_MustWorker_PlatAdmin(t *testing.T) { context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) // setup vela mock server - engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) engine.Use(claims.Establish()) engine.Use(user.Establish()) - engine.Use(MustWorker()) + engine.Use(MustWorkerRegisterToken()) engine.GET("/test/:org/:repo", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -292,33 +295,26 @@ func TestPerm_MustWorker_PlatAdmin(t *testing.T) { // run test engine.ServeHTTP(context.Writer, context.Request) - if resp.Code != http.StatusOK { - t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusOK) + if resp.Code != http.StatusUnauthorized { + t.Errorf("MustWorkerRegisterToken returned %v, want %v", resp.Code, http.StatusUnauthorized) } } -func TestPerm_MustWorker_UserNamedVelaWorker(t *testing.T) { +func TestPerm_MustWorkerAuthToken(t *testing.T) { // setup types - secret := "superSecret" - tm := &token.Manager{ - PrivateKey: "123abc", - SignMethod: jwt.SigningMethodHS256, - UserAccessTokenDuration: time.Minute * 5, - UserRefreshTokenDuration: time.Minute * 30, + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + WorkerRegisterTokenDuration: time.Minute * 1, + WorkerAuthTokenDuration: time.Minute * 15, } - u := new(library.User) - u.SetID(1) - u.SetName("vela-worker") - u.SetToken("bar") - u.SetHash("baz") - u.SetAdmin(false) - mto := &token.MintTokenOpts{ - User: u, - TokenDuration: tm.UserAccessTokenDuration, - TokenType: constants.UserAccessTokenType, + Hostname: "worker", + TokenDuration: tm.WorkerAuthTokenDuration, + TokenType: constants.WorkerAuthTokenType, } tok, _ := tm.MintToken(mto) @@ -329,27 +325,56 @@ func TestPerm_MustWorker_UserNamedVelaWorker(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) - // setup database - db, _ := sqlite.NewTest() + context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) - defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() - }() + // setup vela mock server + engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) + engine.Use(claims.Establish()) + engine.Use(user.Establish()) + engine.Use(MustWorkerAuthToken()) + engine.GET("/test/:org/:repo", func(c *gin.Context) { + c.Status(http.StatusOK) + }) - _ = db.CreateUser(u) + s1 := httptest.NewServer(engine) + defer s1.Close() + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("MustWorkerAuthToken returned %v, want %v", resp.Code, http.StatusOK) + } +} + +func TestPerm_MustWorkerAuth_ServerWorkerToken(t *testing.T) { + // setup types + secret := "superSecret" + tm := &token.Manager{ + PrivateKey: "123abc", + SignMethod: jwt.SigningMethodHS256, + UserAccessTokenDuration: time.Minute * 5, + UserRefreshTokenDuration: time.Minute * 30, + WorkerRegisterTokenDuration: time.Minute * 1, + WorkerAuthTokenDuration: time.Minute * 15, + } + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) - context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) + context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", secret)) // setup vela mock server engine.Use(func(c *gin.Context) { c.Set("secret", secret) }) engine.Use(func(c *gin.Context) { c.Set("token-manager", tm) }) - engine.Use(func(c *gin.Context) { database.ToContext(c, db) }) engine.Use(claims.Establish()) engine.Use(user.Establish()) - engine.Use(MustWorker()) + engine.Use(MustWorkerAuthToken()) engine.GET("/test/:org/:repo", func(c *gin.Context) { c.Status(http.StatusOK) }) @@ -360,8 +385,8 @@ func TestPerm_MustWorker_UserNamedVelaWorker(t *testing.T) { // run test engine.ServeHTTP(context.Writer, context.Request) - if resp.Code != http.StatusUnauthorized { - t.Errorf("MustWorker returned %v, want %v", resp.Code, http.StatusUnauthorized) + if resp.Code != http.StatusOK { + t.Errorf("MustWorkerAuthToken returned %v, want %v", resp.Code, http.StatusOK) } } diff --git a/router/router.go b/router/router.go index 3327e4a7b..f9d1f7b24 100644 --- a/router/router.go +++ b/router/router.go @@ -77,6 +77,9 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // Metric endpoint r.GET("/metrics", api.CustomMetrics, gin.WrapH(api.BaseMetrics())) + // Validate Server Token endpoint + r.GET("/validate-token", claims.Establish(), api.ValidateServerToken) + // Version endpoint r.GET("/version", api.Version) diff --git a/router/worker.go b/router/worker.go index 7853c2a82..100a24975 100644 --- a/router/worker.go +++ b/router/worker.go @@ -19,19 +19,21 @@ import ( // GET /api/v1/workers // GET /api/v1/workers/:worker // PUT /api/v1/workers/:worker +// POST /api/v1/workers/:worker/refresh // DELETE /api/v1/workers/:worker . func WorkerHandlers(base *gin.RouterGroup) { // Workers endpoints workers := base.Group("/workers") { - workers.POST("", perm.MustWorker(), middleware.Payload(), api.CreateWorker) + workers.POST("", perm.MustWorkerRegisterToken(), middleware.Payload(), api.CreateWorker) workers.GET("", api.GetWorkers) // Worker endpoints w := workers.Group("/:worker") { w.GET("", worker.Establish(), api.GetWorker) - w.PUT("", perm.MustWorker(), worker.Establish(), api.UpdateWorker) + w.PUT("", perm.MustPlatformAdmin(), worker.Establish(), api.UpdateWorker) + w.POST("/refresh", perm.MustWorkerAuthToken(), worker.Establish(), api.RefreshWorkerAuth) w.DELETE("", perm.MustPlatformAdmin(), worker.Establish(), api.DeleteWorker) } // end of worker endpoints } // end of workers endpoints From aa0b68ef8923767bdce590f25384d5e33f889d8c Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Fri, 24 Mar 2023 09:47:20 -0500 Subject: [PATCH 184/298] fix: Misc typos (#797) --- api/deployment.go | 2 +- api/step.go | 2 +- compiler/native/substitute.go | 4 ++-- mock/server/stream.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/deployment.go b/api/deployment.go index 293dbbc6e..82433b613 100644 --- a/api/deployment.go +++ b/api/deployment.go @@ -212,7 +212,7 @@ func GetDeployments(c *gin.Context) { return } - // send API call to capture the list of steps for the build + // send API call to capture the list of deployments for the repo d, err := scm.FromContext(c).GetDeploymentList(u, r, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get deployments for %s: %w", r.GetFullName(), err) diff --git a/api/step.go b/api/step.go index acde0f666..ba7ec6119 100644 --- a/api/step.go +++ b/api/step.go @@ -292,7 +292,7 @@ func GetSteps(c *gin.Context) { // type: integer // - in: path // name: step -// description: Build number +// description: Step number // required: true // type: string // security: diff --git a/compiler/native/substitute.go b/compiler/native/substitute.go index 35f458b81..fcfd2b263 100644 --- a/compiler/native/substitute.go +++ b/compiler/native/substitute.go @@ -16,7 +16,7 @@ import ( ) // SubstituteStages replaces every declared environment -// variable with it's corresponding value for each step +// variable with its corresponding value for each step // in every stage in a yaml configuration. func (c *client) SubstituteStages(s types.StageSlice) (types.StageSlice, error) { // iterate through all stages @@ -34,7 +34,7 @@ func (c *client) SubstituteStages(s types.StageSlice) (types.StageSlice, error) } // SubstituteSteps replaces every declared environment -// variable with it's corresponding value for each step +// variable with its corresponding value for each step // in a yaml configuration. func (c *client) SubstituteSteps(s types.StepSlice) (types.StepSlice, error) { // iterate through all steps diff --git a/mock/server/stream.go b/mock/server/stream.go index 05209fb1a..5598992a3 100644 --- a/mock/server/stream.go +++ b/mock/server/stream.go @@ -10,12 +10,12 @@ import ( "github.com/gin-gonic/gin" ) -// postServiceStream returns a nock response for an http POST. +// postServiceStream returns a mock response for an http POST. func postServiceStream(c *gin.Context) { c.JSON(http.StatusNoContent, nil) } -// postStepStream returns a nock response for an http POST. +// postStepStream returns a mock response for an http POST. func postStepStream(c *gin.Context) { c.JSON(http.StatusNoContent, nil) } From 73f83fcfd00461ac3f5097b6fa83acbd469b4bb8 Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:57:39 -0500 Subject: [PATCH 185/298] chore(docker-compose): remove unsupported log method flag (#791) Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b0d7c5f72..91c830d0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,7 +66,6 @@ services: - vela environment: EXECUTOR_DRIVER: linux - EXECUTOR_LOG_METHOD: 'time-chunks' QUEUE_DRIVER: redis QUEUE_ADDR: 'redis://redis:6379' VELA_BUILD_LIMIT: 1 From 8b1b8575e5398054058ab524b015efd5fe6a69ed Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 27 Mar 2023 13:58:17 -0500 Subject: [PATCH 186/298] chore: Delete unused /stream endpoints (#799) --- api/stream.go | 338 ------------------------------------------ mock/server/server.go | 2 - mock/server/stream.go | 21 --- router/service.go | 3 - router/step.go | 3 - 5 files changed, 367 deletions(-) delete mode 100644 api/stream.go delete mode 100644 mock/server/stream.go diff --git a/api/stream.go b/api/stream.go deleted file mode 100644 index 701758f14..000000000 --- a/api/stream.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "bufio" - "bytes" - "fmt" - "net/http" - "time" - - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/build" - "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/service" - "github.com/go-vela/server/router/middleware/step" - "github.com/go-vela/server/util" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -const logUpdateInterval = 1 * time.Second - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/service/{service}/stream stream PostServiceStream -// -// Stream the logs for a service -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: Service number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing logs -// required: true -// schema: -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '204': -// description: Successfully received logs -// '400': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" - -// PostServiceStream represents the API handler that -// streams service logs to the database. -// -//nolint:dupl // separate service/step functions for consistency with API -func PostServiceStream(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logger := logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }) - - logger.Infof("streaming logs for service %s/%d", entry, s.GetNumber()) - - // create new buffer for uploading logs - logs := new(bytes.Buffer) - // create new channel for processing logs - done := make(chan bool) - // defer closing channel to stop processing logs - defer close(done) - - // send API call to capture the service logs - _log, err := database.FromContext(c).GetLogForService(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for service %s/%d: %w", entry, s.GetNumber(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - go func() { - logger.Debugf("polling request body buffer for service %s/%d", entry, s.GetNumber()) - - // spawn "infinite" loop that will upload logs - // from the buffer until the channel is closed - for { - // sleep before attempting to upload logs - time.Sleep(logUpdateInterval) - - // create a non-blocking select to check if the channel is closed - select { - // after repo timeout of idle (no response) end the stream - // - // this is a safety mechanism - case <-time.After(time.Duration(r.GetTimeout()) * time.Minute): - logger.Tracef("repo timeout of %d exceeded", r.GetTimeout()) - - return - // channel is closed - case <-done: - logger.Trace("channel closed for polling container logs") - - // return out of the go routine - return - // channel is not closed - default: - // get the current size of log data - currBytesSize := len(_log.GetData()) - - // update the existing log with the new bytes if there is new data to add - if len(logs.Bytes()) > currBytesSize { - // https://pkg.go.dev/github.com/go-vela/types/library?tab=doc#Log.SetData - _log.SetData(logs.Bytes()) - - // update the log in the database - err = database.FromContext(c).UpdateLog(_log) - if err != nil { - retErr := fmt.Errorf("unable to update logs for service %s/%d: %w", entry, s.GetNumber(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - } - } - }() - - logger.Debugf("scanning request body for service %s/%d", entry, s.GetNumber()) - - scanner := bufio.NewScanner(c.Request.Body) - for scanner.Scan() { - // write all the logs from the scanner - logs.Write(append(scanner.Bytes(), []byte("\n")...)) - } - - c.JSON(http.StatusNoContent, nil) -} - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/stream stream PostStepStream -// -// Stream the logs for a step -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing logs -// required: true -// schema: -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '204': -// description: Successfully received logs -// '400': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to stream the logs -// schema: -// "$ref": "#/definitions/Error" - -// PostStepStream represents the API handler that -// streams service logs to the database. -// -//nolint:dupl // separate service/step functions for consistency with API -func PostStepStream(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logger := logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }) - - logger.Infof("streaming logs for step %s/%d", entry, s.GetNumber()) - - // create new buffer for uploading logs - logs := new(bytes.Buffer) - // create new channel for processing logs - done := make(chan bool) - // defer closing channel to stop processing logs - defer close(done) - - // send API call to capture the step logs - _log, err := database.FromContext(c).GetLogForStep(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for step %s/%d: %w", entry, s.GetNumber(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - go func() { - logger.Debugf("polling request body buffer for step %s/%d", entry, s.GetNumber()) - - // spawn "infinite" loop that will upload logs - // from the buffer until the channel is closed - for { - // sleep before attempting to upload logs - time.Sleep(logUpdateInterval) - - // create a non-blocking select to check if the channel is closed - select { - // after repo timeout of idle (no response) end the stream - // - // this is a safety mechanism - case <-time.After(time.Duration(r.GetTimeout()) * time.Minute): - logger.Tracef("repo timeout of %d exceeded", r.GetTimeout()) - - return - // channel is closed - case <-done: - logger.Trace("channel closed for polling container logs") - - // return out of the go routine - return - // channel is not closed - default: - // get the current size of log data - currBytesSize := len(_log.GetData()) - - // update the existing log with the new bytes if there is new data to add - if len(logs.Bytes()) > currBytesSize { - // https://pkg.go.dev/github.com/go-vela/types/library?tab=doc#Log.SetData - _log.SetData(logs.Bytes()) - - // update the log in the database - err = database.FromContext(c).UpdateLog(_log) - if err != nil { - retErr := fmt.Errorf("unable to update logs for step %s/%d: %w", entry, s.GetNumber(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - } - } - }() - - logger.Debugf("scanning request body for step %s/%d", entry, s.GetNumber()) - - scanner := bufio.NewScanner(c.Request.Body) - for scanner.Scan() { - // write all the logs from the scanner - logs.Write(append(scanner.Bytes(), []byte("\n")...)) - } - - c.JSON(http.StatusNoContent, nil) -} diff --git a/mock/server/server.go b/mock/server/server.go index e13368711..b7a77640f 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -107,7 +107,6 @@ func FakeHandler() http.Handler { e.POST("/api/v1/repos/:org/:repo/builds/:build/steps", addStep) e.PUT("/api/v1/repos/:org/:repo/builds/:build/steps/:step", updateStep) e.DELETE("/api/v1/repos/:org/:repo/builds/:build/steps/:step", removeStep) - e.POST("/api/v1/repos/:org/:repo/builds/:build/steps/:step/stream", postStepStream) // mock endpoints for service calls e.GET("/api/v1/repos/:org/:repo/builds/:build/services/:service", getService) @@ -115,7 +114,6 @@ func FakeHandler() http.Handler { e.POST("/api/v1/repos/:org/:repo/builds/:build/services", addService) e.PUT("/api/v1/repos/:org/:repo/builds/:build/services/:service", updateService) e.DELETE("/api/v1/repos/:org/:repo/builds/:build/services/:service", removeService) - e.POST("/api/v1/repos/:org/:repo/builds/:build/services/:service/stream", postServiceStream) // mock endpoints for user calls e.GET("/api/v1/users/:user", getUser) diff --git a/mock/server/stream.go b/mock/server/stream.go deleted file mode 100644 index 5598992a3..000000000 --- a/mock/server/stream.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package server - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -// postServiceStream returns a mock response for an http POST. -func postServiceStream(c *gin.Context) { - c.JSON(http.StatusNoContent, nil) -} - -// postStepStream returns a mock response for an http POST. -func postStepStream(c *gin.Context) { - c.JSON(http.StatusNoContent, nil) -} diff --git a/router/service.go b/router/service.go index 7fe39d0e9..f344e03eb 100644 --- a/router/service.go +++ b/router/service.go @@ -25,7 +25,6 @@ import ( // GET /api/v1/repos/:org/:repo/builds/:build/services/:service/logs // PUT /api/v1/repos/:org/:repo/builds/:build/services/:service/logs // DELETE /api/v1/repos/:org/:repo/builds/:build/services/:service/logs -// POST /api/v1/repos/:org/:repo/builds/:build/services/:service/stream . func ServiceHandlers(base *gin.RouterGroup) { // Services endpoints services := base.Group("/services") @@ -40,8 +39,6 @@ func ServiceHandlers(base *gin.RouterGroup) { service.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateService) service.DELETE("", perm.MustPlatformAdmin(), api.DeleteService) - service.POST("/stream", perm.MustPlatformAdmin(), api.PostServiceStream) - // Log endpoints LogServiceHandlers(service) } // end of service endpoints diff --git a/router/step.go b/router/step.go index 80aad489a..82719ddf7 100644 --- a/router/step.go +++ b/router/step.go @@ -25,7 +25,6 @@ import ( // GET /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs // PUT /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs // DELETE /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs -// POST /api/v1/repos/:org/:repo/builds/:build/steps/:step/stream . func StepHandlers(base *gin.RouterGroup) { // Steps endpoints steps := base.Group("/steps") @@ -40,8 +39,6 @@ func StepHandlers(base *gin.RouterGroup) { step.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateStep) step.DELETE("", perm.MustPlatformAdmin(), api.DeleteStep) - step.POST("/stream", perm.MustPlatformAdmin(), api.PostStepStream) - // Log endpoints LogStepHandlers(step) } // end of step endpoints From 3d5b219785d9a0d9b9ded4229543c752d84b21f5 Mon Sep 17 00:00:00 2001 From: Colin Dean Date: Wed, 29 Mar 2023 15:37:27 -0400 Subject: [PATCH 187/298] feat(compiler): Enables Starlark structs (#781) --- compiler/template/starlark/render.go | 10 +++++--- compiler/template/starlark/render_test.go | 1 + .../testdata/build/with_struct/build.star | 25 +++++++++++++++++++ .../testdata/build/with_struct/want.yml | 16 ++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 compiler/template/starlark/testdata/build/with_struct/build.star create mode 100644 compiler/template/starlark/testdata/build/with_struct/want.yml diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index dd30f073f..0be1063f5 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -8,8 +8,8 @@ import ( "bytes" "errors" "fmt" - "github.com/go-vela/types/raw" + "go.starlark.net/starlarkstruct" yaml "github.com/buildkite/yaml" types "github.com/go-vela/types/yaml" @@ -40,7 +40,9 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details thread.SetMaxExecutionSteps(5000) - globals, err := starlark.ExecFile(thread, tName, tmpl, nil) + predeclared := starlark.StringDict{"struct": starlark.NewBuiltin("struct", starlarkstruct.Make)} + + globals, err := starlark.ExecFile(thread, tName, tmpl, predeclared) if err != nil { return nil, err @@ -146,7 +148,9 @@ func RenderBuild(tmpl string, b string, envs map[string]string, variables map[st // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details thread.SetMaxExecutionSteps(5000) - globals, err := starlark.ExecFile(thread, "templated-base", b, nil) + predeclared := starlark.StringDict{"struct": starlark.NewBuiltin("struct", starlarkstruct.Make)} + + globals, err := starlark.ExecFile(thread, "templated-base", b, predeclared) if err != nil { return nil, err } diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index 8749593c2..8cc089e47 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -105,6 +105,7 @@ func TestNative_RenderBuild(t *testing.T) { {"steps", args{velaFile: "testdata/build/basic/build.star"}, "testdata/build/basic/want.yml", false}, {"stages", args{velaFile: "testdata/build/basic_stages/build.star"}, "testdata/build/basic_stages/want.yml", false}, {"conditional match", args{velaFile: "testdata/build/conditional/build.star"}, "testdata/build/conditional/want.yml", false}, + {"steps, with structs", args{velaFile: "testdata/build/with_struct/build.star"}, "testdata/build/with_struct/want.yml", false}, } for _, tt := range tests { diff --git a/compiler/template/starlark/testdata/build/with_struct/build.star b/compiler/template/starlark/testdata/build/with_struct/build.star new file mode 100644 index 000000000..d344b64cb --- /dev/null +++ b/compiler/template/starlark/testdata/build/with_struct/build.star @@ -0,0 +1,25 @@ +def main(ctx): + step_list = [ + struct(name="foo"), + struct(name="bar"), + struct(name="star") + ] + + steps = [] + + for step in step_list: + steps.append(build_step(step)) + + return { + 'version': '1', + 'steps': steps + } + +def build_step(step): + return { + "name": "build_%s" % step.name, + "image": "alpine:latest", + 'commands': [ + "echo %s" % step.name + ] + } diff --git a/compiler/template/starlark/testdata/build/with_struct/want.yml b/compiler/template/starlark/testdata/build/with_struct/want.yml new file mode 100644 index 000000000..6297ea2b9 --- /dev/null +++ b/compiler/template/starlark/testdata/build/with_struct/want.yml @@ -0,0 +1,16 @@ +version: 1 +steps: + - name: build_foo + image: alpine:latest + commands: + - echo foo + + - name: build_bar + image: alpine:latest + commands: + - echo bar + + - name: build_star + image: alpine:latest + commands: + - echo star From f8a9aa116391bcde0b4772c0974b97aef2617ea3 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:12:56 -0600 Subject: [PATCH 188/298] enhance(queue): validate queue route and add error wrapping to clean build (#801) --- api/build.go | 10 ++++---- api/webhook.go | 6 ++--- queue/redis/route.go | 10 +++++++- queue/redis/route_test.go | 48 +++++++++++++++++++++++++++------------ 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/api/build.go b/api/build.go index cb27dab14..523825a26 100644 --- a/api/build.go +++ b/api/build.go @@ -1585,7 +1585,7 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r // of UPDATE-ing the existing build - which results in // a constraint error (repo_id, number) // - do we want to update the build or just delete it? - cleanBuild(database, b, nil, nil) + cleanBuild(database, b, nil, nil, err) return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) } @@ -1602,7 +1602,7 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r services, err := planServices(database, p, b) if err != nil { // clean up the objects from the pipeline in the database - cleanBuild(database, b, services, nil) + cleanBuild(database, b, services, nil, err) return err } @@ -1611,7 +1611,7 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r steps, err := planSteps(database, p, b) if err != nil { // clean up the objects from the pipeline in the database - cleanBuild(database, b, services, steps) + cleanBuild(database, b, services, steps, err) return err } @@ -1623,9 +1623,9 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r // without execution. This will kill all resources, // like steps and services, for the build in the // configured backend. -func cleanBuild(database database.Service, b *library.Build, services []*library.Service, steps []*library.Step) { +func cleanBuild(database database.Service, b *library.Build, services []*library.Service, steps []*library.Step, e error) { // update fields in build object - b.SetError("unable to publish build to queue") + b.SetError(fmt.Sprintf("unable to publish to queue: %s", e.Error())) b.SetStatus(constants.StatusError) b.SetFinished(time.Now().UTC().Unix()) diff --git a/api/webhook.go b/api/webhook.go index d624e22dc..36e521d91 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -748,7 +748,7 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, logrus.Errorf("Failed to convert item to json for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - cleanBuild(db, b, nil, nil) + cleanBuild(db, b, nil, nil, err) return } @@ -760,7 +760,7 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, logrus.Errorf("unable to set route for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - cleanBuild(db, b, nil, nil) + cleanBuild(db, b, nil, nil, err) return } @@ -776,7 +776,7 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, logrus.Errorf("Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - cleanBuild(db, b, nil, nil) + cleanBuild(db, b, nil, nil, err) return } diff --git a/queue/redis/route.go b/queue/redis/route.go index 58e10b78f..1da4b19db 100644 --- a/queue/redis/route.go +++ b/queue/redis/route.go @@ -37,5 +37,13 @@ func (c *client) Route(w *pipeline.Worker) (string, error) { buf.WriteString(fmt.Sprintf(":%s", w.Platform)) } - return strings.TrimLeft(buf.String(), ":"), nil + route := strings.TrimLeft(buf.String(), ":") + + for _, r := range c.config.Channels { + if strings.EqualFold(route, r) { + return route, nil + } + } + + return "", fmt.Errorf("invalid route %s provided", route) } diff --git a/queue/redis/route_test.go b/queue/redis/route_test.go index 9956ca02d..de3f99fc9 100644 --- a/queue/redis/route_test.go +++ b/queue/redis/route_test.go @@ -14,32 +14,48 @@ import ( func TestRedis_Client_Route(t *testing.T) { // setup - client, _ := NewTest("vela") + client, _ := NewTest("vela", "16cpu8gb", "16cpu8gb:gcp", "gcp") tests := []struct { - want string - worker pipeline.Worker + success bool + want string + worker pipeline.Worker }{ // pipeline with not worker passed { - want: constants.DefaultRoute, - worker: pipeline.Worker{}, + success: true, + want: constants.DefaultRoute, + worker: pipeline.Worker{}, }, { - want: "vela", - worker: pipeline.Worker{}, + success: true, + want: "vela", + worker: pipeline.Worker{}, }, { - want: "16cpu8gb", - worker: pipeline.Worker{Flavor: "16cpu8gb"}, + success: true, + want: "16cpu8gb", + worker: pipeline.Worker{Flavor: "16cpu8gb"}, }, { - want: "16cpu8gb:gcp", - worker: pipeline.Worker{Flavor: "16cpu8gb", Platform: "gcp"}, + success: true, + want: "16cpu8gb:gcp", + worker: pipeline.Worker{Flavor: "16cpu8gb", Platform: "gcp"}, }, { - want: "gcp", - worker: pipeline.Worker{Platform: "gcp"}, + success: true, + want: "gcp", + worker: pipeline.Worker{Platform: "gcp"}, + }, + { + success: false, + want: "", + worker: pipeline.Worker{Flavor: "bad", Platform: "route"}, + }, + { + success: false, + want: "", + worker: pipeline.Worker{Flavor: "bad"}, }, } @@ -47,10 +63,14 @@ func TestRedis_Client_Route(t *testing.T) { for _, test := range tests { got, err := client.Route(&test.worker) - if err != nil { + if test.success && err != nil { t.Errorf("Route returned err: %v", err) } + if !test.success && err == nil { + t.Errorf("Route returned %s, want err", got) + } + if !strings.EqualFold(got, test.want) { t.Errorf("Route is %v, want %v", got, test.want) } From 34164d0412e2bf5f966829420c325180f851e9c1 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 5 Apr 2023 08:08:22 -0600 Subject: [PATCH 189/298] enhance(api/scm): expand sync to align SCM subscribed events with allowed events (#800) * enhance(api/scm): expand sync to align SCM subscribed events with allowed events * do not update the webhook at every repo update --- api/repo/update.go | 33 ++++++++++------ api/scm.go | 93 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/api/repo/update.go b/api/repo/update.go index dbe1333ba..374772d42 100644 --- a/api/repo/update.go +++ b/api/repo/update.go @@ -70,7 +70,7 @@ import ( // UpdateRepo represents the API handler to update // a repo in the configured backend. // -//nolint:funlen // ignore function length +//nolint:funlen,gocyclo // ignore function length func UpdateRepo(c *gin.Context) { // capture middleware values o := org.Retrieve(c) @@ -99,6 +99,8 @@ func UpdateRepo(c *gin.Context) { return } + eventsChanged := false + // update repo fields if provided if len(input.GetBranch()) > 0 { // update branch if set @@ -167,26 +169,36 @@ func UpdateRepo(c *gin.Context) { if input.AllowPull != nil { // update allow_pull if set r.SetAllowPull(input.GetAllowPull()) + + eventsChanged = true } if input.AllowPush != nil { // update allow_push if set r.SetAllowPush(input.GetAllowPush()) + + eventsChanged = true } if input.AllowDeploy != nil { // update allow_deploy if set r.SetAllowDeploy(input.GetAllowDeploy()) + + eventsChanged = true } if input.AllowTag != nil { // update allow_tag if set r.SetAllowTag(input.GetAllowTag()) + + eventsChanged = true } if input.AllowComment != nil { // update allow_comment if set r.SetAllowComment(input.GetAllowComment()) + + eventsChanged = true } // set default events if no events are enabled @@ -239,18 +251,17 @@ func UpdateRepo(c *gin.Context) { } } - // grab last hook from repo to fetch the webhook ID - lastHook, err := database.FromContext(c).LastHookForRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) + // if webhook validation is not set or events didn't change, skip webhook update + if c.Value("webhookvalidation").(bool) && eventsChanged { + // grab last hook from repo to fetch the webhook ID + lastHook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) - return - } + util.HandleError(c, http.StatusInternalServerError, retErr) - // if repo has no hook deliveries, skip webhook update - if lastHook.GetWebhookID() != 0 { + return + } // if user is platform admin, fetch the repo owner token to make changes to webhook if u.GetAdmin() { // capture admin name for logging diff --git a/api/scm.go b/api/scm.go index b497768cd..ee0898ff8 100644 --- a/api/scm.go +++ b/api/scm.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. @@ -7,6 +7,7 @@ package api import ( "fmt" "net/http" + "strings" "github.com/gin-gonic/gin" "github.com/go-vela/server/database" @@ -15,7 +16,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/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) @@ -48,7 +48,8 @@ import ( // SyncRepos represents the API handler to // synchronize organization repositories between // SCM Service and the database should a discrepancy -// exist. Common after deleting SCM repos. +// exist. Primarily used for deleted repos or to align +// subscribed events with allowed events. func SyncRepos(c *gin.Context) { // capture middleware values o := org.Retrieve(c) @@ -64,20 +65,23 @@ func SyncRepos(c *gin.Context) { logger.Infof("syncing repos for org %s", o) - // See if the user is an org admin to bypass individual permission checks + // see if the user is an org admin perm, err := scm.FromContext(c).OrgAccess(u, o) if err != nil { logger.Errorf("unable to get user %s access level for org %s", u.GetName(), o) } - filters := map[string]interface{}{} - // Only show public repos to non-admins + // only allow org-wide syncing if user is admin of org if perm != "admin" { - filters["visibility"] = constants.VisibilityPublic + retErr := fmt.Errorf("unable to sync repos in org %s: must be an org admin", o) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return } // send API call to capture the total number of repos for the org - t, err := database.FromContext(c).CountReposForOrg(o, filters) + t, err := database.FromContext(c).CountReposForOrg(o, map[string]interface{}{}) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) @@ -90,7 +94,7 @@ func SyncRepos(c *gin.Context) { page := 0 // capture all repos belonging to a certain org in database for orgRepos := int64(0); orgRepos < t; orgRepos += 100 { - r, _, err := database.FromContext(c).ListReposForOrg(o, "name", filters, page, 100) + r, _, err := database.FromContext(c).ListReposForOrg(o, "name", map[string]interface{}{}, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) @@ -120,6 +124,29 @@ func SyncRepos(c *gin.Context) { return } } + + // if we have webhook validation, update the repo hook in the SCM + if c.Value("webhookvalidation").(bool) { + // grab last hook from repo to fetch the webhook ID + lastHook, err := database.FromContext(c).LastHookForRepo(repo) + if err != nil { + retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", repo.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update webhook + err = scm.FromContext(c).Update(u, repo, lastHook.GetWebhookID()) + if err != nil { + retErr := fmt.Errorf("unable to update repo webhook for %s: %w", repo.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } } c.JSON(http.StatusOK, fmt.Sprintf("org %s repos synced", o)) @@ -158,7 +185,8 @@ func SyncRepos(c *gin.Context) { // SyncRepo represents the API handler to // synchronize a single repository between // SCM service and the database should a discrepancy -// exist. Common after deleting SCM repos. +// exist. Primarily used for deleted repos or to align +// subscribed events with allowed events. func SyncRepo(c *gin.Context) { // capture middleware values o := org.Retrieve(c) @@ -179,7 +207,7 @@ func SyncRepo(c *gin.Context) { // retrieve repo from source code manager service _, err := scm.FromContext(c).GetRepo(u, r) - // if there is an error retrieving repo, we know it is deleted: sync time + // if there is an error retrieving repo, we know it is deleted: set to inactive if err != nil { // set repo to inactive - do not delete r.SetActive(false) @@ -193,6 +221,49 @@ func SyncRepo(c *gin.Context) { return } + + // exit with success as hook sync will be unnecessary + c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) + + return + } + + // verify the user is an admin of the repo + // we cannot use our normal permissions check due to the possibility the repo was deleted + perm, err := scm.FromContext(c).RepoAccess(u, u.GetToken(), o, r.GetName()) + if err != nil { + logger.Errorf("unable to get user %s access level for org %s", u.GetName(), o) + } + + if !strings.EqualFold(perm, "admin") { + retErr := fmt.Errorf("user %s does not have 'admin' permissions for the repo %s", u.GetName(), r.GetFullName()) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + // if we have webhook validation, update the repo hook in the SCM + if c.Value("webhookvalidation").(bool) { + // grab last hook from repo to fetch the webhook ID + lastHook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update webhook + err = scm.FromContext(c).Update(u, r, lastHook.GetWebhookID()) + if err != nil { + retErr := fmt.Errorf("unable to update repo webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } } c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) From 17c53400b2d5f834d0ad2dde7d57eafa317ca325 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 6 Apr 2023 09:27:33 -0600 Subject: [PATCH 190/298] enhance(metrics): gather queued builds (#802) --- api/metrics.go | 14 +++++++ queue/redis/length.go | 27 ++++++++++++++ queue/redis/length_test.go | 75 ++++++++++++++++++++++++++++++++++++++ queue/service.go | 4 ++ 4 files changed, 120 insertions(+) create mode 100644 queue/redis/length.go create mode 100644 queue/redis/length_test.go diff --git a/api/metrics.go b/api/metrics.go index b5f6fe942..cf059d324 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -10,6 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" + "github.com/go-vela/server/queue" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -29,6 +30,8 @@ type MetricsQueryParameters struct { RunningBuildCount bool `form:"running_build_count"` // PendingBuildCount represents total number of builds with status==pending PendingBuildCount bool `form:"pending_build_count"` + // QueuedBuildCount represents total number of builds currently in the queue + QueuedBuildCount bool `form:"queued_build_count"` // FailureBuildCount represents total number of builds with status==failure FailureBuildCount bool `form:"failure_build_count"` // KilledBuildCount represents total number of builds with status==killed @@ -258,6 +261,17 @@ func recordGauges(c *gin.Context) { totals.WithLabelValues("build", "status", "pending").Set(float64(bPen)) } + // queued_build_count + if q.QueuedBuildCount { + // send API call to capture the total number of queued builds + t, err := queue.FromContext(c).Length(c) + if err != nil { + logrus.Errorf("unable to get count of all queued builds: %v", err) + } + + totals.WithLabelValues("build", "status", "queued").Set(float64(t)) + } + // failure_build_count if q.FailureBuildCount { // send API call to capture the total number of failure builds diff --git a/queue/redis/length.go b/queue/redis/length.go new file mode 100644 index 000000000..7ed4ecd8b --- /dev/null +++ b/queue/redis/length.go @@ -0,0 +1,27 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package redis + +import ( + "context" +) + +// Length tallies all items present in the configured channels in the queue. +func (c *client) Length(ctx context.Context) (int64, error) { + c.Logger.Tracef("reading length of all configured channels in queue") + + total := int64(0) + + for _, channel := range c.config.Channels { + items, err := c.Redis.LLen(ctx, channel).Result() + if err != nil { + return 0, err + } + + total += items + } + + return total, nil +} diff --git a/queue/redis/length_test.go b/queue/redis/length_test.go new file mode 100644 index 000000000..95cb21423 --- /dev/null +++ b/queue/redis/length_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package redis + +import ( + "context" + "reflect" + "testing" + + "github.com/go-vela/types" + "gopkg.in/square/go-jose.v2/json" +) + +func TestRedis_Length(t *testing.T) { + // setup types + // use global variables in redis_test.go + _item := &types.Item{ + Build: _build, + Pipeline: _steps, + Repo: _repo, + User: _user, + } + + // setup queue item + bytes, err := json.Marshal(_item) + if err != nil { + t.Errorf("unable to marshal queue item: %v", err) + } + + // setup redis mock + _redis, err := NewTest("vela", "vela:second", "vela:third") + if err != nil { + t.Errorf("unable to create queue service: %v", err) + } + + // setup tests + tests := []struct { + channels []string + want int64 + }{ + { + channels: []string{"vela"}, + want: 1, + }, + { + channels: []string{"vela", "vela:second", "vela:third"}, + want: 4, + }, + { + channels: []string{"vela", "vela:second", "phony"}, + want: 6, + }, + } + + // run tests + for _, test := range tests { + for _, channel := range test.channels { + err := _redis.Push(context.Background(), channel, bytes) + if err != nil { + t.Errorf("unable to push item to queue: %v", err) + } + } + got, err := _redis.Length(context.Background()) + + if err != nil { + t.Errorf("Length returned err: %v", err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Length is %v, want %v", got, test.want) + } + } +} diff --git a/queue/service.go b/queue/service.go index 3974b76a3..418b3a919 100644 --- a/queue/service.go +++ b/queue/service.go @@ -20,6 +20,10 @@ type Service interface { // the configured queue driver. Driver() string + // Length defines a function that outputs + // the length of a queue channel + Length(context.Context) (int64, error) + // Pop defines a function that grabs an // item off the queue. Pop(context.Context) (*types.Item, error) From 3335f6a0134a3dc561491810d0f46db3451f8f83 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 7 Apr 2023 08:39:35 -0600 Subject: [PATCH 191/298] enhance(api/worker): validate host name in claims against input (#806) --- api/worker.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/api/worker.go b/api/worker.go index 4ef613e78..5d949779e 100644 --- a/api/worker.go +++ b/api/worker.go @@ -7,6 +7,7 @@ package api import ( "fmt" "net/http" + "strings" "time" "github.com/go-vela/server/internal/token" @@ -73,6 +74,17 @@ func CreateWorker(c *gin.Context) { return } + // verify input host name matches worker hostname + if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, input.GetHostname()) { + retErr := fmt.Errorf("unable to add worker; claims subject %s does not match worker hostname %s", cl.Subject, input.GetHostname()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + input.SetLastCheckedIn(time.Now().Unix()) + // update engine logger with API metadata // // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields @@ -367,6 +379,20 @@ func RefreshWorkerAuth(c *gin.Context) { w := worker.Retrieve(c) cl := claims.Retrieve(c) + // if we are not using a symmetric token, and the subject does not match the input, request should be denied + if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, w.GetHostname()) { + retErr := fmt.Errorf("unable to refresh worker auth: claims subject %s does not match worker hostname %s", cl.Subject, w.GetHostname()) + + logrus.WithFields(logrus.Fields{ + "subject": cl.Subject, + "worker": w.GetHostname(), + }).Warnf("attempted refresh of worker %s using token from worker %s", w.GetHostname(), cl.Subject) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + // set last checked in time w.SetLastCheckedIn(time.Now().Unix()) From b5777e5ec1d1e0ae9bba89f38d8ce4a43a646729 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Sat, 8 Apr 2023 00:16:48 -0500 Subject: [PATCH 192/298] refactor(api): move user handlers to new package (#809) --- api/user.go | 766 ------------------------------------- api/user/create.go | 88 +++++ api/user/create_token.go | 78 ++++ api/user/delete.go | 82 ++++ api/user/delete_token.go | 78 ++++ api/user/get.go | 68 ++++ api/user/get_current.go | 44 +++ api/user/get_source.go | 125 ++++++ api/user/list.go | 120 ++++++ api/user/update.go | 124 ++++++ api/user/update_current.go | 105 +++++ router/user.go | 26 +- 12 files changed, 925 insertions(+), 779 deletions(-) delete mode 100644 api/user.go create mode 100644 api/user/create.go create mode 100644 api/user/create_token.go create mode 100644 api/user/delete.go create mode 100644 api/user/delete_token.go create mode 100644 api/user/get.go create mode 100644 api/user/get_current.go create mode 100644 api/user/get_source.go create mode 100644 api/user/list.go create mode 100644 api/user/update.go create mode 100644 api/user/update_current.go diff --git a/api/user.go b/api/user.go deleted file mode 100644 index c73fe17e4..000000000 --- a/api/user.go +++ /dev/null @@ -1,766 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/server/internal/token" - "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" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/users users CreateUser -// -// Create a user for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Payload containing the user to create -// required: true -// schema: -// "$ref": "#/definitions/User" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the user -// schema: -// "$ref": "#/definitions/User" -// '400': -// description: Unable to create the user -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the user -// schema: -// "$ref": "#/definitions/Error" - -// CreateUser represents the API handler to create -// a user in the configured backend. -func CreateUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // capture body from API request - input := new(library.User) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new user: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("creating new user %s", input.GetName()) - - // send API call to create the user - err = database.FromContext(c).CreateUser(input) - if err != nil { - retErr := fmt.Errorf("unable to create user: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created user - user, _ := database.FromContext(c).GetUserForName(input.GetName()) - - c.JSON(http.StatusCreated, user) -} - -// swagger:operation GET /api/v1/users users GetUsers -// -// Retrieve a list of users for the configured backend -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// parameters: -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// responses: -// '200': -// description: Successfully retrieved the list of users -// schema: -// type: array -// items: -// "$ref": "#/definitions/User" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of users -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of users -// schema: -// "$ref": "#/definitions/Error" - -// GetUsers represents the API handler to capture a list -// of users from the configured backend. -func GetUsers(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Info("reading lite users") - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for users: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for users: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of users - users, t, err := database.FromContext(c).ListLiteUsers(page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get users: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, users) -} - -// swagger:operation GET /api/v1/user users GetCurrentUser -// -// Retrieve the current authenticated user from the configured backend -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the current user -// schema: -// "$ref": "#/definitions/User" - -// GetCurrentUser represents the API handler to capture the -// currently authenticated user from the configured backend. -func GetCurrentUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("reading current user %s", u.GetName()) - - c.JSON(http.StatusOK, u) -} - -// swagger:operation PUT /api/v1/user users UpdateCurrentUser -// -// Update the current authenticated user in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Payload containing the user to update -// required: true -// schema: -// "$ref": "#/definitions/User" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the current user -// schema: -// "$ref": "#/definitions/User" -// '400': -// description: Unable to update the current user -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to update the current user -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the current user -// schema: -// "$ref": "#/definitions/Error" - -// UpdateCurrentUser represents the API handler to capture and -// update the currently authenticated user from the configured backend. -func UpdateCurrentUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("updating current user %s", u.GetName()) - - // capture body from API request - input := new(library.User) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update user fields if provided - if input.Favorites != nil { - // update favorites if set - u.SetFavorites(input.GetFavorites()) - } - - // send API call to update the user - err = database.FromContext(c).UpdateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated user - u, err = database.FromContext(c).GetUserForName(u.GetName()) - if err != nil { - retErr := fmt.Errorf("unable to get updated user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - c.JSON(http.StatusOK, u) -} - -// swagger:operation GET /api/v1/users/{user} users GetUser -// -// Retrieve a user for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: user -// description: Name of the user -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the user -// schema: -// "$ref": "#/definitions/User" -// '404': -// description: Unable to retrieve the user -// schema: -// "$ref": "#/definitions/Error" - -// GetUser represents the API handler to capture a -// user from the configured backend. -func GetUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - user := util.PathParameter(c, "user") - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("reading user %s", user) - - // send API call to capture the user - u, err := database.FromContext(c).GetUserForName(user) - if err != nil { - retErr := fmt.Errorf("unable to get user %s: %w", user, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - c.JSON(http.StatusOK, u) -} - -// swagger:operation GET /api/v1/user/source/repos users GetUserSourceRepos -// -// Retrieve a list of repos for the current authenticated user -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved a list of repos for the current user -// schema: -// "$ref": "#/definitions/Repo" -// '404': -// description: Unable to retrieve a list of repos for the current user -// schema: -// "$ref": "#/definitions/Error" - -// GetUserSourceRepos represents the API handler to capture -// the list of repos for a user from the configured backend. -func GetUserSourceRepos(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("reading available SCM repos for user %s", u.GetName()) - - // variables to capture requested data - dbRepos := []*library.Repo{} - output := make(map[string][]library.Repo) - - // send API call to capture the list of repos for the user - srcRepos, err := scm.FromContext(c).ListUserRepos(u) - if err != nil { - retErr := fmt.Errorf("unable to get SCM repos for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // create a map - // TODO: clean this up - for _, srepo := range srcRepos { - // local variables to avoid bad memory address de-referencing - // initialize active to false - org := srepo.Org - name := srepo.Name - active := false - - // library struct to omit optional fields - repo := library.Repo{ - Org: org, - Name: name, - Active: &active, - } - output[srepo.GetOrg()] = append(output[srepo.GetOrg()], repo) - } - - for org := range output { - // capture source repos from the database backend, grouped by org - page := 1 - filters := map[string]interface{}{} - - for page > 0 { - // send API call to capture the list of repos for the org - dbReposPart, _, err := database.FromContext(c).ListReposForOrg(org, "name", filters, page, 100) - if err != nil { - retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // add repos to list of database org repos - dbRepos = append(dbRepos, dbReposPart...) - - // assume no more pages exist if under 100 results are returned - if len(dbReposPart) < 100 { - page = 0 - } else { - page++ - } - } - - // apply org repos active status to output map - for _, dbRepo := range dbRepos { - if orgRepos, ok := output[dbRepo.GetOrg()]; ok { - for i := range orgRepos { - if orgRepos[i].GetName() == dbRepo.GetName() { - active := dbRepo.GetActive() - (&orgRepos[i]).Active = &active - } - } - } - } - } - - c.JSON(http.StatusOK, output) -} - -// swagger:operation PUT /api/v1/users/{user} users UpdateUser -// -// Update a user for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: user -// description: Name of the user -// required: true -// type: string -// - in: body -// name: body -// description: Payload containing the user to update -// required: true -// schema: -// "$ref": "#/definitions/User" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the user -// schema: -// "$ref": "#/definitions/User" -// '400': -// description: Unable to update the user -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to update the user -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the user -// schema: -// "$ref": "#/definitions/Error" - -// UpdateUser represents the API handler to update -// a user in the configured backend. -func UpdateUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - user := util.PathParameter(c, "user") - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("updating user %s", user) - - // capture body from API request - input := new(library.User) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for user %s: %w", user, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the user - u, err = database.FromContext(c).GetUserForName(user) - if err != nil { - retErr := fmt.Errorf("unable to get user %s: %w", user, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // update user fields if provided - if input.GetActive() { - // update active if set to true - u.SetActive(input.GetActive()) - } - - if input.GetAdmin() { - // update admin if set to true - u.SetAdmin(input.GetAdmin()) - } - - if input.Favorites != nil { - // update favorites if set - u.SetFavorites(input.GetFavorites()) - } - - // send API call to update the user - err = database.FromContext(c).UpdateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to update user %s: %w", user, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated user - u, _ = database.FromContext(c).GetUserForName(user) - - c.JSON(http.StatusOK, u) -} - -// swagger:operation DELETE /api/v1/users/{user} users DeleteUser -// -// Delete a user for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: user -// description: Name of the user -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted of user -// schema: -// type: string -// '404': -// description: Unable to delete user -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to delete user -// schema: -// "$ref": "#/definitions/Error" - -// DeleteUser represents the API handler to remove -// a user from the configured backend. -func DeleteUser(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - user := util.PathParameter(c, "user") - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("deleting user %s", user) - - // send API call to capture the user - u, err := database.FromContext(c).GetUserForName(user) - if err != nil { - retErr := fmt.Errorf("unable to get user %s: %w", user, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // send API call to remove the user - err = database.FromContext(c).DeleteUser(u) - if err != nil { - retErr := fmt.Errorf("unable to delete user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("user %s deleted", u.GetName())) -} - -// swagger:operation POST /api/v1/user/token users CreateToken -// -// Create a token for the current authenticated user -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully created a token for the current user -// schema: -// "$ref": "#/definitions/Token" -// '503': -// description: Unable to create a token for the current user -// schema: -// "$ref": "#/definitions/Error" - -// CreateToken represents the API handler to create -// a user token in the configured backend. -// -//nolint:dupl // ignore duplicate flag with delete token -func CreateToken(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("composing token for user %s", u.GetName()) - - tm := c.MustGet("token-manager").(*token.Manager) - - // compose JWT token for user - rt, at, err := tm.Compose(c, u) - if err != nil { - retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - u.SetRefreshToken(rt) - - // send API call to update the user - err = database.FromContext(c).UpdateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - c.JSON(http.StatusOK, library.Token{Token: &at}) -} - -// swagger:operation DELETE /api/v1/user/token users DeleteToken -// -// Delete a token for the current authenticated user -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully delete a token for the current user -// schema: -// type: string -// '500': -// description: Unable to delete a token for the current user -// schema: -// "$ref": "#/definitions/Error" - -// DeleteToken represents the API handler to revoke -// and recreate a user token in the configured backend. -// -//nolint:dupl // ignore duplicate flag with create token -func DeleteToken(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Infof("revoking token for user %s", u.GetName()) - - tm := c.MustGet("token-manager").(*token.Manager) - - // compose JWT token for user - rt, at, err := tm.Compose(c, u) - if err != nil { - retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - u.SetRefreshToken(rt) - - // send API call to update the user - err = database.FromContext(c).UpdateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - c.JSON(http.StatusOK, library.Token{Token: &at}) -} diff --git a/api/user/create.go b/api/user/create.go new file mode 100644 index 000000000..d6348810e --- /dev/null +++ b/api/user/create.go @@ -0,0 +1,88 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/users users CreateUser +// +// Create a user for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Payload containing the user to create +// required: true +// schema: +// "$ref": "#/definitions/User" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the user +// schema: +// "$ref": "#/definitions/User" +// '400': +// description: Unable to create the user +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the user +// schema: +// "$ref": "#/definitions/Error" + +// CreateUser represents the API handler to create +// a user in the configured backend. +func CreateUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // capture body from API request + input := new(library.User) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new user: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("creating new user %s", input.GetName()) + + // send API call to create the user + err = database.FromContext(c).CreateUser(input) + if err != nil { + retErr := fmt.Errorf("unable to create user: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created user + user, _ := database.FromContext(c).GetUserForName(input.GetName()) + + c.JSON(http.StatusCreated, user) +} diff --git a/api/user/create_token.go b/api/user/create_token.go new file mode 100644 index 000000000..dee7044cb --- /dev/null +++ b/api/user/create_token.go @@ -0,0 +1,78 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with delete token +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/user/token users CreateToken +// +// Create a token for the current authenticated user +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully created a token for the current user +// schema: +// "$ref": "#/definitions/Token" +// '503': +// description: Unable to create a token for the current user +// schema: +// "$ref": "#/definitions/Error" + +// CreateToken represents the API handler to create +// a user token in the configured backend. +func CreateToken(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("composing token for user %s", u.GetName()) + + tm := c.MustGet("token-manager").(*token.Manager) + + // compose JWT token for user + rt, at, err := tm.Compose(c, u) + if err != nil { + retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + u.SetRefreshToken(rt) + + // send API call to update the user + err = database.FromContext(c).UpdateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + c.JSON(http.StatusOK, library.Token{Token: &at}) +} diff --git a/api/user/delete.go b/api/user/delete.go new file mode 100644 index 000000000..9e0651e7e --- /dev/null +++ b/api/user/delete.go @@ -0,0 +1,82 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/users/{user} users DeleteUser +// +// Delete a user for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: user +// description: Name of the user +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted of user +// schema: +// type: string +// '404': +// description: Unable to delete user +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to delete user +// schema: +// "$ref": "#/definitions/Error" + +// DeleteUser represents the API handler to remove +// a user from the configured backend. +func DeleteUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + user := util.PathParameter(c, "user") + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("deleting user %s", user) + + // send API call to capture the user + u, err := database.FromContext(c).GetUserForName(user) + if err != nil { + retErr := fmt.Errorf("unable to get user %s: %w", user, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // send API call to remove the user + err = database.FromContext(c).DeleteUser(u) + if err != nil { + retErr := fmt.Errorf("unable to delete user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("user %s deleted", u.GetName())) +} diff --git a/api/user/delete_token.go b/api/user/delete_token.go new file mode 100644 index 000000000..22fa9724d --- /dev/null +++ b/api/user/delete_token.go @@ -0,0 +1,78 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create token +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/user/token users DeleteToken +// +// Delete a token for the current authenticated user +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully delete a token for the current user +// schema: +// type: string +// '500': +// description: Unable to delete a token for the current user +// schema: +// "$ref": "#/definitions/Error" + +// DeleteToken represents the API handler to revoke +// and recreate a user token in the configured backend. +func DeleteToken(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("revoking token for user %s", u.GetName()) + + tm := c.MustGet("token-manager").(*token.Manager) + + // compose JWT token for user + rt, at, err := tm.Compose(c, u) + if err != nil { + retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + u.SetRefreshToken(rt) + + // send API call to update the user + err = database.FromContext(c).UpdateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + c.JSON(http.StatusOK, library.Token{Token: &at}) +} diff --git a/api/user/get.go b/api/user/get.go new file mode 100644 index 000000000..9f0b723d3 --- /dev/null +++ b/api/user/get.go @@ -0,0 +1,68 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/users/{user} users GetUser +// +// Retrieve a user for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: user +// description: Name of the user +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the user +// schema: +// "$ref": "#/definitions/User" +// '404': +// description: Unable to retrieve the user +// schema: +// "$ref": "#/definitions/Error" + +// GetUser represents the API handler to capture a +// user from the configured backend. +func GetUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + user := util.PathParameter(c, "user") + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("reading user %s", user) + + // send API call to capture the user + u, err := database.FromContext(c).GetUserForName(user) + if err != nil { + retErr := fmt.Errorf("unable to get user %s: %w", user, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + c.JSON(http.StatusOK, u) +} diff --git a/api/user/get_current.go b/api/user/get_current.go new file mode 100644 index 000000000..b4b1ef4c3 --- /dev/null +++ b/api/user/get_current.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/user" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/user users GetCurrentUser +// +// Retrieve the current authenticated user from the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the current user +// schema: +// "$ref": "#/definitions/User" + +// GetCurrentUser represents the API handler to capture the +// currently authenticated user from the configured backend. +func GetCurrentUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("reading current user %s", u.GetName()) + + c.JSON(http.StatusOK, u) +} diff --git a/api/user/get_source.go b/api/user/get_source.go new file mode 100644 index 000000000..2ea8734c3 --- /dev/null +++ b/api/user/get_source.go @@ -0,0 +1,125 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/user/source/repos users GetSourceRepos +// +// Retrieve a list of repos for the current authenticated user +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved a list of repos for the current user +// schema: +// "$ref": "#/definitions/Repo" +// '404': +// description: Unable to retrieve a list of repos for the current user +// schema: +// "$ref": "#/definitions/Error" + +// GetSourceRepos represents the API handler to capture +// the list of repos for a user from the configured backend. +func GetSourceRepos(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("reading available SCM repos for user %s", u.GetName()) + + // variables to capture requested data + dbRepos := []*library.Repo{} + output := make(map[string][]library.Repo) + + // send API call to capture the list of repos for the user + srcRepos, err := scm.FromContext(c).ListUserRepos(u) + if err != nil { + retErr := fmt.Errorf("unable to get SCM repos for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // create a map + // TODO: clean this up + for _, srepo := range srcRepos { + // local variables to avoid bad memory address de-referencing + // initialize active to false + org := srepo.Org + name := srepo.Name + active := false + + // library struct to omit optional fields + repo := library.Repo{ + Org: org, + Name: name, + Active: &active, + } + output[srepo.GetOrg()] = append(output[srepo.GetOrg()], repo) + } + + for org := range output { + // capture source repos from the database backend, grouped by org + page := 1 + filters := map[string]interface{}{} + + for page > 0 { + // send API call to capture the list of repos for the org + dbReposPart, _, err := database.FromContext(c).ListReposForOrg(org, "name", filters, page, 100) + if err != nil { + retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // add repos to list of database org repos + dbRepos = append(dbRepos, dbReposPart...) + + // assume no more pages exist if under 100 results are returned + if len(dbReposPart) < 100 { + page = 0 + } else { + page++ + } + } + + // apply org repos active status to output map + for _, dbRepo := range dbRepos { + if orgRepos, ok := output[dbRepo.GetOrg()]; ok { + for i := range orgRepos { + if orgRepos[i].GetName() == dbRepo.GetName() { + active := dbRepo.GetActive() + (&orgRepos[i]).Active = &active + } + } + } + } + } + + c.JSON(http.StatusOK, output) +} diff --git a/api/user/list.go b/api/user/list.go new file mode 100644 index 000000000..1f879bfef --- /dev/null +++ b/api/user/list.go @@ -0,0 +1,120 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/users users ListUsers +// +// Retrieve a list of users for the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// parameters: +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// responses: +// '200': +// description: Successfully retrieved the list of users +// schema: +// type: array +// items: +// "$ref": "#/definitions/User" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of users +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of users +// schema: +// "$ref": "#/definitions/Error" + +// ListUsers represents the API handler to capture a list +// of users from the configured backend. +func ListUsers(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Info("reading lite users") + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for users: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for users: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of users + users, t, err := database.FromContext(c).ListLiteUsers(page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get users: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, users) +} diff --git a/api/user/update.go b/api/user/update.go new file mode 100644 index 000000000..d2fb631ab --- /dev/null +++ b/api/user/update.go @@ -0,0 +1,124 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/users/{user} users UpdateUser +// +// Update a user for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: user +// description: Name of the user +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the user to update +// required: true +// schema: +// "$ref": "#/definitions/User" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the user +// schema: +// "$ref": "#/definitions/User" +// '400': +// description: Unable to update the user +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to update the user +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the user +// schema: +// "$ref": "#/definitions/Error" + +// UpdateUser represents the API handler to update +// a user in the configured backend. +func UpdateUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + user := util.PathParameter(c, "user") + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("updating user %s", user) + + // capture body from API request + input := new(library.User) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for user %s: %w", user, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the user + u, err = database.FromContext(c).GetUserForName(user) + if err != nil { + retErr := fmt.Errorf("unable to get user %s: %w", user, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // update user fields if provided + if input.GetActive() { + // update active if set to true + u.SetActive(input.GetActive()) + } + + if input.GetAdmin() { + // update admin if set to true + u.SetAdmin(input.GetAdmin()) + } + + if input.Favorites != nil { + // update favorites if set + u.SetFavorites(input.GetFavorites()) + } + + // send API call to update the user + err = database.FromContext(c).UpdateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to update user %s: %w", user, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated user + u, _ = database.FromContext(c).GetUserForName(user) + + c.JSON(http.StatusOK, u) +} diff --git a/api/user/update_current.go b/api/user/update_current.go new file mode 100644 index 000000000..ed861ae61 --- /dev/null +++ b/api/user/update_current.go @@ -0,0 +1,105 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package user + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/user users UpdateCurrentUser +// +// Update the current authenticated user in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Payload containing the user to update +// required: true +// schema: +// "$ref": "#/definitions/User" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the current user +// schema: +// "$ref": "#/definitions/User" +// '400': +// description: Unable to update the current user +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to update the current user +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the current user +// schema: +// "$ref": "#/definitions/Error" + +// UpdateCurrentUser represents the API handler to capture and +// update the currently authenticated user from the configured backend. +func UpdateCurrentUser(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Infof("updating current user %s", u.GetName()) + + // capture body from API request + input := new(library.User) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update user fields if provided + if input.Favorites != nil { + // update favorites if set + u.SetFavorites(input.GetFavorites()) + } + + // send API call to update the user + err = database.FromContext(c).UpdateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated user + u, err = database.FromContext(c).GetUserForName(u.GetName()) + if err != nil { + retErr := fmt.Errorf("unable to get updated user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + c.JSON(http.StatusOK, u) +} diff --git a/router/user.go b/router/user.go index 1b91836b1..64f6e9b63 100644 --- a/router/user.go +++ b/router/user.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/user" "github.com/go-vela/server/router/middleware/perm" ) @@ -28,22 +28,22 @@ import ( // DELETE /api/v1/user/token . func UserHandlers(base *gin.RouterGroup) { // Users endpoints - users := base.Group("/users") + _users := base.Group("/users") { - users.POST("", perm.MustPlatformAdmin(), api.CreateUser) - users.GET("", api.GetUsers) - users.GET("/:user", perm.MustPlatformAdmin(), api.GetUser) - users.PUT("/:user", perm.MustPlatformAdmin(), api.UpdateUser) - users.DELETE("/:user", perm.MustPlatformAdmin(), api.DeleteUser) + _users.POST("", perm.MustPlatformAdmin(), user.CreateUser) + _users.GET("", user.ListUsers) + _users.GET("/:user", perm.MustPlatformAdmin(), user.GetUser) + _users.PUT("/:user", perm.MustPlatformAdmin(), user.UpdateUser) + _users.DELETE("/:user", perm.MustPlatformAdmin(), user.DeleteUser) } // end of users endpoints // User endpoints - user := base.Group("/user") + _user := base.Group("/user") { - user.GET("", api.GetCurrentUser) - user.PUT("", api.UpdateCurrentUser) - user.GET("/source/repos", api.GetUserSourceRepos) - user.POST("/token", api.CreateToken) - user.DELETE("/token", api.DeleteToken) + _user.GET("", user.GetCurrentUser) + _user.PUT("", user.UpdateCurrentUser) + _user.GET("/source/repos", user.GetSourceRepos) + _user.POST("/token", user.CreateToken) + _user.DELETE("/token", user.DeleteToken) } // end of user endpoints } From a7d3686b53f12b60a3a0350ceb3994a3c5955317 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 10 Apr 2023 13:41:43 -0500 Subject: [PATCH 193/298] feat(api/log)!: support paging on `GetBuildLogs` (#798) * feat(api/log): support paging on GetBuildLogs Adds support for the page and per_page query parameters for GetBuildLogs /api/v1/repos/+/+/builds/+/logs This resolves an in-code TODO. * Update api/log.go * refactor(api/log): cap max per_page at 100 * enhance(api/log)!: lower default per_page to 10 from 100 (the max) --------- Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> Co-authored-by: Kelly Merrick Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/log.go | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/api/log.go b/api/log.go index fe593c40d..9cb02b0d9 100644 --- a/api/log.go +++ b/api/log.go @@ -7,15 +7,15 @@ package api import ( "fmt" "net/http" - - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" + "strconv" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/service" "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/util" "github.com/go-vela/types/library" @@ -47,6 +47,17 @@ import ( // description: Build number // required: true // type: integer +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 // security: // - ApiKeyAuth: [] // responses: @@ -82,10 +93,30 @@ func GetBuildLogs(c *gin.Context) { "user": u.GetName(), }).Infof("reading logs for build %s", entry) + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + //nolint:lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + // send API call to capture the list of logs for the build - // - // TODO: add page and per_page query parameters - l, t, err := database.FromContext(c).ListLogsForBuild(b, 1, 100) + l, t, err := database.FromContext(c).ListLogsForBuild(b, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get logs for build %s: %w", entry, err) @@ -96,8 +127,8 @@ func GetBuildLogs(c *gin.Context) { // create pagination object pagination := Pagination{ - Page: 1, - PerPage: 100, + Page: page, + PerPage: perPage, Total: t, } // set pagination headers From ba3dd47b687f71778d063cd7d7f9b2b3cd467150 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 10 Apr 2023 13:57:49 -0500 Subject: [PATCH 194/298] chore(mock+router): Cleanup endpoints (#796) * fix: Adjust mock to reflect removed API endpoints * fix: cleanup router add missing routes to swagger docs del spurious non-existent routes from swagger docs --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: Kelly Merrick --- mock/server/server.go | 8 -------- router/build.go | 1 + router/repo.go | 2 ++ router/user.go | 3 --- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/mock/server/server.go b/mock/server/server.go index b7a77640f..0eb70188d 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -20,22 +20,14 @@ func FakeHandler() http.Handler { e := gin.New() // mock endpoints for admin calls - e.GET("/api/v1/admin/builds", getBuilds) e.PUT("/api/v1/admin/build", updateBuild) e.GET("/api/v1/admin/builds/queue", buildQueue) - e.GET("/api/v1/admin/deployments", getDeployments) e.PUT("/api/v1/admin/deployment", updateDeployment) - e.GET("/api/v1/admin/hooks", getHooks) e.PUT("/api/v1/admin/hook", updateHook) - e.GET("/api/v1/admin/repos", getRepos) e.PUT("/api/v1/admin/repo", updateRepo) - e.GET("/api/v1/admin/secrets", getSecrets) e.PUT("/api/v1/admin/secret", updateSecret) - e.GET("/api/v1/admin/services", getServices) e.PUT("/api/v1/admin/service", updateService) - e.GET("/api/v1/admin/steps", getSteps) e.PUT("/api/v1/admin/step", updateStep) - e.GET("/api/v1/admin/users", getUsers) e.PUT("/api/v1/admin/user", updateUser) e.POST("/api/v1/admin/workers/:worker/register-token", registerToken) diff --git a/router/build.go b/router/build.go index c2e34e188..4c922bcb0 100644 --- a/router/build.go +++ b/router/build.go @@ -24,6 +24,7 @@ import ( // DELETE /api/v1/repos/:org/:repo/builds/:build // DELETE /api/v1/repos/:org/:repo/builds/:build/cancel // GET /api/v1/repos/:org/:repo/builds/:build/logs +// GET /api/v1/repos/:org/:repo/builds/:build/token // POST /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services/:service diff --git a/router/repo.go b/router/repo.go index 1383d71c2..6d0dbf240 100644 --- a/router/repo.go +++ b/router/repo.go @@ -32,7 +32,9 @@ import ( // GET /api/v1/repos/:org/:repo/builds/:build // PUT /api/v1/repos/:org/:repo/builds/:build // DELETE /api/v1/repos/:org/:repo/builds/:build +// DELETE /api/v1/repos/:org/:repo/builds/:build/cancel // GET /api/v1/repos/:org/:repo/builds/:build/logs +// GET /api/v1/repos/:org/:repo/builds/:build/token // POST /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services/:service diff --git a/router/user.go b/router/user.go index 64f6e9b63..31abe2d92 100644 --- a/router/user.go +++ b/router/user.go @@ -18,9 +18,6 @@ import ( // GET /api/v1/users/:user // PUT /api/v1/users/:user // DELETE /api/v1/users/:user -// GET /api/v1/users/:user/source/repos -// POST /api/v1/users/:user/token -// DELETE /api/v1/users/:user/token // GET /api/v1/user // PUT /api/v1/user // GET /api/v1/user/source/repos From 71240b4f1e474cbe488fd8c67afe7ffd76f466eb Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 10 Apr 2023 14:49:02 -0500 Subject: [PATCH 195/298] refactor(database): move secret logic into separate package (#782) * feat(database): add user engine * chore(database): remove old user logic * refactor(database): restructure DDL functions * chore: updates for database user engine * feat(database): add repo engine * chore: save work * fix: Scan() -> Take() * fix: sort by for listing repos * feat(database): add worker engine * chore(database): remove old worker logic * chore: updates for database worker engine * fix: issues from merge conflict * chore: address linter feedback * chore: address linter feedback v2 * feat(database): add hook engine * chore: remove Limit(1) with Take() * chore(database): remove old hook logic * chore: updates for database hook engine * refactor(database/worker): name of index * feat(database): add log engine * chore(database): remove old log logic * chore: updates for database log engine * chore: update copyright year * chore: address linter feedback * chore: address linter feedback * chore: save work * chore: save work * chore: finalize testing * chore: save work * chore: finalize changes * fix: failing tests * chore: address linter feedback * chore: add missing tests * chore: address linter feedback * chore: address review feedback * chore: address review feedback --------- Co-authored-by: Jacob Floyd Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- api/webhook.go | 4 +- database/postgres/ddl/secret.go | 65 ---- database/postgres/dml/secret.go | 146 --------- database/postgres/postgres.go | 45 ++- database/postgres/postgres_test.go | 19 +- database/postgres/secret.go | 216 ------------- database/postgres/secret_count.go | 78 ----- database/postgres/secret_count_test.go | 295 ----------------- database/postgres/secret_list.go | 150 --------- database/postgres/secret_list_test.go | 417 ------------------------ database/postgres/secret_test.go | 423 ------------------------- database/repo/get_org_test.go | 2 +- database/secret/count.go | 25 ++ database/secret/count_org.go | 32 ++ database/secret/count_org_test.go | 109 +++++++ database/secret/count_repo.go | 35 ++ database/secret/count_repo_test.go | 120 +++++++ database/secret/count_team.go | 68 ++++ database/secret/count_team_test.go | 216 +++++++++++++ database/secret/count_test.go | 105 ++++++ database/secret/create.go | 68 ++++ database/secret/create_test.go | 145 +++++++++ database/secret/delete.go | 46 +++ database/secret/delete_test.go | 151 +++++++++ database/secret/get.go | 52 +++ database/secret/get_org.go | 59 ++++ database/secret/get_org_test.go | 93 ++++++ database/secret/get_repo.go | 61 ++++ database/secret/get_repo_test.go | 103 ++++++ database/secret/get_team.go | 61 ++++ database/secret/get_team_test.go | 93 ++++++ database/secret/get_test.go | 91 ++++++ database/secret/index.go | 52 +++ database/secret/index_test.go | 61 ++++ database/secret/list.go | 67 ++++ database/secret/list_org.go | 82 +++++ database/secret/list_org_test.go | 120 +++++++ database/secret/list_repo.go | 84 +++++ database/secret/list_repo_test.go | 131 ++++++++ database/secret/list_team.go | 162 ++++++++++ database/secret/list_team_test.go | 227 +++++++++++++ database/secret/list_test.go | 115 +++++++ database/secret/opts.go | 54 ++++ database/secret/opts_test.go | 210 ++++++++++++ database/secret/secret.go | 82 +++++ database/secret/secret_test.go | 240 ++++++++++++++ database/secret/service.go | 63 ++++ database/secret/table.go | 74 +++++ database/secret/table_test.go | 59 ++++ database/secret/update.go | 68 ++++ database/secret/update_test.go | 158 +++++++++ database/service.go | 27 +- database/sqlite/ddl/secret.go | 65 ---- database/sqlite/dml/secret.go | 146 --------- database/sqlite/secret.go | 216 ------------- database/sqlite/secret_count.go | 78 ----- database/sqlite/secret_count_test.go | 352 -------------------- database/sqlite/secret_list.go | 151 --------- database/sqlite/secret_list_test.go | 399 ----------------------- database/sqlite/secret_test.go | 417 ------------------------ database/sqlite/sqlite.go | 40 +-- secret/native/count.go | 64 ++-- secret/native/create.go | 52 +-- secret/native/delete.go | 55 ++-- secret/native/get.go | 58 ++-- secret/native/list.go | 83 +++-- secret/native/update.go | 72 +++-- 67 files changed, 4140 insertions(+), 3837 deletions(-) delete mode 100644 database/postgres/ddl/secret.go delete mode 100644 database/postgres/dml/secret.go delete mode 100644 database/postgres/secret.go delete mode 100644 database/postgres/secret_count.go delete mode 100644 database/postgres/secret_count_test.go delete mode 100644 database/postgres/secret_list.go delete mode 100644 database/postgres/secret_list_test.go delete mode 100644 database/postgres/secret_test.go create mode 100644 database/secret/count.go create mode 100644 database/secret/count_org.go create mode 100644 database/secret/count_org_test.go create mode 100644 database/secret/count_repo.go create mode 100644 database/secret/count_repo_test.go create mode 100644 database/secret/count_team.go create mode 100644 database/secret/count_team_test.go create mode 100644 database/secret/count_test.go create mode 100644 database/secret/create.go create mode 100644 database/secret/create_test.go create mode 100644 database/secret/delete.go create mode 100644 database/secret/delete_test.go create mode 100644 database/secret/get.go create mode 100644 database/secret/get_org.go create mode 100644 database/secret/get_org_test.go create mode 100644 database/secret/get_repo.go create mode 100644 database/secret/get_repo_test.go create mode 100644 database/secret/get_team.go create mode 100644 database/secret/get_team_test.go create mode 100644 database/secret/get_test.go create mode 100644 database/secret/index.go create mode 100644 database/secret/index_test.go create mode 100644 database/secret/list.go create mode 100644 database/secret/list_org.go create mode 100644 database/secret/list_org_test.go create mode 100644 database/secret/list_repo.go create mode 100644 database/secret/list_repo_test.go create mode 100644 database/secret/list_team.go create mode 100644 database/secret/list_team_test.go create mode 100644 database/secret/list_test.go create mode 100644 database/secret/opts.go create mode 100644 database/secret/opts_test.go create mode 100644 database/secret/secret.go create mode 100644 database/secret/secret_test.go create mode 100644 database/secret/service.go create mode 100644 database/secret/table.go create mode 100644 database/secret/table_test.go create mode 100644 database/secret/update.go create mode 100644 database/secret/update_test.go delete mode 100644 database/sqlite/ddl/secret.go delete mode 100644 database/sqlite/dml/secret.go delete mode 100644 database/sqlite/secret.go delete mode 100644 database/sqlite/secret_count.go delete mode 100644 database/sqlite/secret_count_test.go delete mode 100644 database/sqlite/secret_list.go delete mode 100644 database/sqlite/secret_list_test.go delete mode 100644 database/sqlite/secret_test.go diff --git a/api/webhook.go b/api/webhook.go index 36e521d91..56794fe57 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -854,7 +854,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types } // get total number of secrets associated with repository - t, err := database.FromContext(c).GetTypeSecretCount(constants.SecretRepo, r.GetOrg(), previousName, []string{}) + t, err := database.FromContext(c).CountSecretsForRepo(dbR, map[string]interface{}{}) if err != nil { return fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) } @@ -863,7 +863,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types page := 1 // capture all secrets belonging to certain repo in database for repoSecrets := int64(0); repoSecrets < t; repoSecrets += 100 { - s, err := database.FromContext(c).GetTypeSecretList(constants.SecretRepo, r.GetOrg(), previousName, page, 100, []string{}) + s, _, err := database.FromContext(c).ListSecretsForRepo(dbR, map[string]interface{}{}, page, 100) if err != nil { return fmt.Errorf("unable to get secret list for repo %s/%s: %w", r.GetOrg(), previousName, err) } diff --git a/database/postgres/ddl/secret.go b/database/postgres/ddl/secret.go deleted file mode 100644 index e6bbcc6a0..000000000 --- a/database/postgres/ddl/secret.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateSecretTable represents a query to - // create the secrets table for Vela. - CreateSecretTable = ` -CREATE TABLE -IF NOT EXISTS -secrets ( - id SERIAL PRIMARY KEY, - type VARCHAR(100), - org VARCHAR(250), - repo VARCHAR(250), - team VARCHAR(250), - name VARCHAR(250), - value BYTEA, - images VARCHAR(1000), - events VARCHAR(1000), - allow_command BOOLEAN, - created_at INTEGER, - created_by VARCHAR(250), - updated_at INTEGER, - updated_by VARCHAR(250), - UNIQUE(type, org, repo, name), - UNIQUE(type, org, team, name) -); -` - - // CreateSecretTypeOrgRepo represents a query to create an - // index on the secrets table for the type, org and repo columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrgRepo = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org_repo -ON secrets (type, org, repo); -` - - // CreateSecretTypeOrgTeam represents a query to create an - // index on the secrets table for the type, org and team columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrgTeam = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org_team -ON secrets (type, org, team); -` - - // CreateSecretTypeOrg represents a query to create an - // index on the secrets table for the type, and org columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrg = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org -ON secrets (type, org); -` -) diff --git a/database/postgres/dml/secret.go b/database/postgres/dml/secret.go deleted file mode 100644 index 28d7607bc..000000000 --- a/database/postgres/dml/secret.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListSecrets represents a query to - // list all secrets in the database. - // - //nolint:gosec // ignore false positive - ListSecrets = ` -SELECT * -FROM secrets; -` - - // ListOrgSecrets represents a query to list all - // secrets for a type and org in the database. - // - //nolint:gosec // ignore false positive - ListOrgSecrets = ` -SELECT * -FROM secrets -WHERE type = 'org' -AND org = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // ListRepoSecrets represents a query to list all - // secrets for a type, org and repo in the database. - // - //nolint:gosec // ignore false positive - ListRepoSecrets = ` -SELECT * -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // ListSharedSecrets represents a query to list all - // secrets for a type, org and team in the database. - // - //nolint:gosec // ignore false positive - ListSharedSecrets = ` -SELECT * -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectOrgSecretsCount represents a query to select the - // count of org secrets for an org in the database. - // - //nolint:gosec // ignore false positive - SelectOrgSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'org' -AND org = ?; -` - - // SelectRepoSecretsCount represents a query to select the - // count of repo secrets for an org and repo in the database. - // - //nolint:gosec // ignore false positive - SelectRepoSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ?; -` - - // SelectSharedSecretsCount represents a query to select the - // count of shared secrets for an org and repo in the database. - // - //nolint:gosec // ignore false positive - SelectSharedSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ?; -` - - // SelectOrgSecret represents a query to select a - // secret for an org and name in the database. - // - //nolint:gosec // ignore false positive - SelectOrgSecret = ` -SELECT * -FROM secrets -WHERE type = 'org' -AND org = ? -AND name = ? -LIMIT 1; -` - - // SelectRepoSecret represents a query to select a - // secret for an org, repo and name in the database. - // - //nolint:gosec // ignore false positive - SelectRepoSecret = ` -SELECT * -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ? -AND name = ? -LIMIT 1; -` - - // SelectSharedSecret represents a query to select a - // secret for an org, team and name in the database. - // - //nolint:gosec // ignore false positive - SelectSharedSecret = ` -SELECT * -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ? -AND name = ? -LIMIT 1; -` - - // DeleteSecret represents a query to - // remove a secret from the database. - // - //nolint:gosec // ignore false positive - DeleteSecret = ` -DELETE -FROM secrets -WHERE id = ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index a4199f316..7aa273a8f 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -14,6 +14,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" @@ -55,6 +56,8 @@ type ( pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService repo.RepoService + // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService + secret.SecretService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService @@ -167,6 +170,11 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the secret queries + _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -259,12 +267,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the secrets table - err = c.Postgres.Exec(ddl.CreateSecretTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableSecret, err) - } - // create the services table err = c.Postgres.Exec(ddl.CreateServiceTable).Error if err != nil { @@ -309,24 +311,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the secrets_type_org_repo index for the secrets table - err = c.Postgres.Exec(ddl.CreateSecretTypeOrgRepo).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %w", constants.TableSecret, err) - } - - // create the secrets_type_org_team index for the secrets table - err = c.Postgres.Exec(ddl.CreateSecretTypeOrgTeam).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %w", constants.TableSecret, err) - } - - // create the secrets_type_org index for the secrets table - err = c.Postgres.Exec(ddl.CreateSecretTypeOrg).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) - } - return nil } @@ -385,6 +369,19 @@ func createServices(c *client) error { return err } + // create the database agnostic secret service + // + // https://pkg.go.dev/github.com/go-vela/server/database/secret#New + c.SecretService, err = secret.New( + secret.WithClient(c.Postgres), + secret.WithEncryptionKey(c.config.EncryptionKey), + secret.WithLogger(c.Logger), + secret.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 97bb1c46c..6db511a83 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -15,6 +15,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" @@ -80,7 +81,6 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -89,9 +89,6 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -105,6 +102,11 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the secret queries + _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -172,7 +174,6 @@ func TestPostgres_createTables(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -217,9 +218,6 @@ func TestPostgres_createIndexes(t *testing.T) { _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateSecretTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool @@ -269,6 +267,11 @@ func TestPostgres_createServices(t *testing.T) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the secret queries + _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/postgres/secret.go b/database/postgres/secret.go deleted file mode 100644 index ee28853ca..000000000 --- a/database/postgres/secret.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetSecret gets a secret by type, org, name (repo or team) and secret name from the database. -func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "secret": secretName, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "secret": secretName, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("getting %s secret %s for %s/%s from the database", t, secretName, o, n) - - var err error - - // variable to store query results - s := new(database.Secret) - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - result := c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectOrgSecret, o, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - case constants.SecretRepo: - result := c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectRepoSecret, o, n, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - case constants.SecretShared: - result := c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectSharedSecret, o, n, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - } - - if err != nil { - return nil, err - } - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = s.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt %s secret %s for %s/%s: %v", t, secretName, o, n, err) - - // return the unencrypted secret - return s.ToLibrary(), nil - } - - // return the decrypted secret - return s.ToLibrary(), nil -} - -// CreateSecret creates a new secret in the database. -// -//nolint:dupl // ignore similar code with update -func (c *client) CreateSecret(s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": s.GetOrg(), - "repo": s.GetRepo(), - "secret": s.GetName(), - "type": s.GetType(), - } - - // check if secret is a shared secret - if strings.EqualFold(s.GetType(), constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": s.GetOrg(), - "team": s.GetTeam(), - "secret": s.GetName(), - "type": s.GetType(), - } - } - - c.Logger.WithFields(fields).Tracef("creating %s secret %s in the database", s.GetType(), s.GetName()) - - // cast to database type - secret := database.SecretFromLibrary(s) - - // validate the necessary fields are populated - err := secret.Validate() - if err != nil { - return err - } - - // encrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt - err = secret.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableSecret). - Create(secret.Nullify()).Error -} - -// UpdateSecret updates a secret in the database. -// -//nolint:dupl // ignore similar code with create -func (c *client) UpdateSecret(s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": s.GetOrg(), - "repo": s.GetRepo(), - "secret": s.GetName(), - "type": s.GetType(), - } - - // check if secret is a shared secret - if strings.EqualFold(s.GetType(), constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": s.GetOrg(), - "team": s.GetTeam(), - "secret": s.GetName(), - "type": s.GetType(), - } - } - - c.Logger.WithFields(fields).Tracef("updating %s secret %s in the database", s.GetType(), s.GetName()) - - // cast to database type - secret := database.SecretFromLibrary(s) - - // validate the necessary fields are populated - err := secret.Validate() - if err != nil { - return err - } - - // encrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt - err = secret.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) - } - - // send query to the database - return c.Postgres. - Table(constants.TableSecret). - Save(secret.Nullify()).Error -} - -// DeleteSecret deletes a secret by unique ID from the database. -func (c *client) DeleteSecret(id int64) error { - c.Logger.Tracef("deleting secret %d from the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableSecret). - Exec(dml.DeleteSecret, id).Error -} diff --git a/database/postgres/secret_count.go b/database/postgres/secret_count.go deleted file mode 100644 index 3a5008d85..000000000 --- a/database/postgres/secret_count.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" -) - -// GetTypeSecretCount gets a count of secrets by type, -// owner, and name (repo or team) from the database. -func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("getting count of %s secrets for %s/%s from the database", t, o, n) - - var err error - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectOrgSecretsCount, o). - Pluck("count", &s).Error - case constants.SecretRepo: - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectRepoSecretsCount, o, n). - Pluck("count", &s).Error - case constants.SecretShared: - if n == "*" { - // GitHub teams are not case-sensitive, the DB is lowercase everything for matching - var lowerTeams []string - for _, t := range teams { - lowerTeams = append(lowerTeams, strings.ToLower(t)) - } - - err = c.Postgres. - Table(constants.TableSecret). - Select("count(*)"). - Where("type = 'shared' AND org = ?", o). - Where("LOWER(team) IN (?)", lowerTeams). - Pluck("count", &s).Error - } else { - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.SelectSharedSecretsCount, o, n). - Pluck("count", &s).Error - } - } - - return s, err -} diff --git a/database/postgres/secret_count_test.go b/database/postgres/secret_count_test.go deleted file mode 100644 index d75a4f5e1..000000000 --- a/database/postgres/secret_count_test.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetTypeSecretCount_Org(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("*") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("org") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("*") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("org") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectOrgSecretsCount, "foo").Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretCount("org", "foo", "*", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretCount_Repo(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepoSecretsCount, "foo", "bar").Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretCount("repo", "foo", "bar", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretCount_Shared(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectSharedSecretsCount, "foo", "bar").Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretCount("shared", "foo", "bar", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretCount_Shared_Wildcard(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bared") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"secrets\" WHERE (type = 'shared' AND org = $1) AND LOWER(team) IN ($2,$3)").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretCount("shared", "foo", "*", []string{"bar", "bared"}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/secret_list.go b/database/postgres/secret_list.go deleted file mode 100644 index d8806a3b8..000000000 --- a/database/postgres/secret_list.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" -) - -// GetSecretList gets a list of all secrets from the database. -func (c *client) GetSecretList() ([]*library.Secret, error) { - c.Logger.Tracef("listing secrets from the database") - - // variable to store query results - s := new([]database.Secret) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableSecret). - Raw(dml.ListSecrets). - Scan(s).Error - if err != nil { - return nil, err - } - - // variable we want to return - secrets := []*library.Secret{} - // iterate through all query results - for _, secret := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := secret - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - secrets = append(secrets, tmp.ToLibrary()) - } - - return secrets, nil -} - -// GetTypeSecretList gets a list of secrets by type, -// owner, and name (repo or team) from the database. -func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []string) ([]*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("listing %s secrets for %s/%s from the database", t, o, n) - - var err error - // variable to store query results - s := new([]database.Secret) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.ListOrgSecrets, o, perPage, offset). - Scan(s).Error - case constants.SecretRepo: - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.ListRepoSecrets, o, n, perPage, offset). - Scan(s).Error - case constants.SecretShared: - if n == "*" { - // GitHub teams are not case-sensitive, the DB is lowercase everything for matching - var lowerTeams []string - for _, t := range teams { - lowerTeams = append(lowerTeams, strings.ToLower(t)) - } - - err = c.Postgres. - Table(constants.TableSecret). - Where("type = 'shared' AND org = ?", o). - Where("LOWER(team) IN (?)", lowerTeams). - Order("id DESC"). - Limit(perPage). - Offset(offset). - Scan(s).Error - } else { - err = c.Postgres. - Table(constants.TableSecret). - Raw(dml.ListSharedSecrets, o, n, perPage, offset). - Scan(s).Error - } - } - - if err != nil { - return nil, err - } - - // variable we want to return - secrets := []*library.Secret{} - // iterate through all query results - for _, secret := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := secret - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - secrets = append(secrets, tmp.ToLibrary()) - } - - return secrets, nil -} diff --git a/database/postgres/secret_list_test.go b/database/postgres/secret_list_test.go deleted file mode 100644 index bbaf3dc5f..000000000 --- a/database/postgres/secret_list_test.go +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetSecretList(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListSecrets).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "repo", "foo", "bar", "", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2"). - AddRow(1, "repo", "foo", "bar", "", "foob", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetSecretList() - - if test.failure { - if err == nil { - t.Errorf("GetSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecretList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretList_Org(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("*") - _secretOne.SetName("baz") - _secretOne.SetValue("bar") - _secretOne.SetType("org") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("*") - _secretTwo.SetName("bar") - _secretTwo.SetValue("baz") - _secretTwo.SetType("org") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListOrgSecrets, "foo", 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "org", "foo", "*", "", "baz", "bar", "{}", "{}", false, 1, "user", 1, "user2"). - AddRow(1, "org", "foo", "*", "", "bar", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretList("org", "foo", "*", 1, 10, []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretList_Repo(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListRepoSecrets, "foo", "bar", 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "repo", "foo", "bar", "", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2"). - AddRow(1, "repo", "foo", "bar", "", "foob", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretList("repo", "foo", "bar", 1, 10, []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretList_Shared(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListSharedSecrets, "foo", "bar", 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "shared", "foo", "", "bar", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2"). - AddRow(1, "shared", "foo", "", "bar", "foob", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretList("shared", "foo", "bar", 1, 10, []string{"bar"}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetTypeSecretList_Shared_Wildcard(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(1) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bared") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "shared", "foo", "", "bar", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2"). - AddRow(1, "shared", "foo", "", "bared", "foob", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT * FROM \"secrets\" WHERE (type = 'shared' AND org = $1) AND LOWER(team) IN ($2,$3) ORDER BY id DESC LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetTypeSecretList("shared", "foo", "*", 1, 10, []string{"bar", "bared"}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/secret_test.go b/database/postgres/secret_test.go deleted file mode 100644 index 6b513af45..000000000 --- a/database/postgres/secret_test.go +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - "time" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetSecret_Org(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("*") - _secret.SetName("bar") - _secret.SetValue("baz") - _secret.SetType("org") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectOrgSecret, "foo", "bar").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "org", "foo", "*", "", "bar", "baz", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetSecret("org", "foo", "*", "bar") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetSecret_Repo(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepoSecret, "foo", "bar", "baz").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "repo", "foo", "bar", "", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetSecret("repo", "foo", "bar", "baz") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetSecret_Shared(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetTeam("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("shared") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectSharedSecret, "foo", "bar", "baz").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}, - ).AddRow(1, "shared", "foo", "", "bar", "baz", "foob", "{}", "{}", false, 1, "user", 1, "user2") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetSecret("shared", "foo", "bar", "baz") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateSecret(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "secrets" ("org","repo","team","name","value","type","images","events","allow_command","created_at","created_by","updated_at","updated_by","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). - WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", "{}", "{}", false, 1, "user", 1, "user2", 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateSecret(_secret) - - if test.failure { - if err == nil { - t.Errorf("CreateSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateSecret returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateSecret(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "secrets" SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 WHERE "id" = $14`). - WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", "{}", "{}", false, 1, "user", time.Now().UTC().Unix(), "user2", 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateSecret(_secret) - - if test.failure { - if err == nil { - t.Errorf("UpdateSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateSecret returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteSecret(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteSecret, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteSecret(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteSecret returned err: %v", err) - } - } -} - -// testSecret is a test helper function to create a -// library Secret type with all fields set to their -// zero values. -func testSecret() *library.Secret { - i64 := int64(0) - str := "" - arr := []string{} - booL := false - - return &library.Secret{ - ID: &i64, - Org: &str, - Repo: &str, - Team: &str, - Name: &str, - Value: &str, - Type: &str, - Images: &arr, - Events: &arr, - AllowCommand: &booL, - CreatedAt: &i64, - CreatedBy: &str, - UpdatedAt: &i64, - UpdatedBy: &str, - } -} diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go index e5b545c1f..5e739029c 100644 --- a/database/repo/get_org_test.go +++ b/database/repo/get_org_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-vela/types/library" ) -func TestRepo_Engine_GetRepoForName(t *testing.T) { +func TestRepo_Engine_GetRepoForOrg(t *testing.T) { // setup types _repo := testRepo() _repo.SetID(1) diff --git a/database/secret/count.go b/database/secret/count.go new file mode 100644 index 000000000..0926c875c --- /dev/null +++ b/database/secret/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" +) + +// CountSecrets gets the count of all secrets from the database. +func (e *engine) CountSecrets() (int64, error) { + e.logger.Tracef("getting count of all secrets from the database") + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Count(&s). + Error + + return s, err +} diff --git a/database/secret/count_org.go b/database/secret/count_org.go new file mode 100644 index 000000000..751389800 --- /dev/null +++ b/database/secret/count_org.go @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// CountSecretsForOrg gets the count of secrets by org name from the database. +func (e *engine) CountSecretsForOrg(org string, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "type": constants.SecretOrg, + }).Tracef("getting count of secrets for org %s from the database", org) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretOrg). + Where("org = ?", org). + Where(filters). + Count(&s). + Error + + return s, err +} diff --git a/database/secret/count_org_test.go b/database/secret/count_org_test.go new file mode 100644 index 000000000..45e109157 --- /dev/null +++ b/database/secret/count_org_test.go @@ -0,0 +1,109 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" +) + +func TestSecret_Engine_CountSecretsForOrg(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("*") + _secretOne.SetName("baz") + _secretOne.SetValue("bar") + _secretOne.SetType("org") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("bar") + _secretTwo.SetRepo("*") + _secretTwo.SetName("foo") + _secretTwo.SetValue("baz") + _secretTwo.SetType("org") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2`). + WithArgs(constants.SecretOrg, "foo").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSecretsForOrg("foo", filters) + + if test.failure { + if err == nil { + t.Errorf("CountSecretsForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSecretsForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSecretsForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/count_repo.go b/database/secret/count_repo.go new file mode 100644 index 000000000..58100ebc6 --- /dev/null +++ b/database/secret/count_repo.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountSecretsForRepo gets the count of secrets by org and repo name from the database. +func (e *engine) CountSecretsForRepo(r *library.Repo, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "type": constants.SecretRepo, + }).Tracef("getting count of secrets for repo %s from the database", r.GetFullName()) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretRepo). + Where("org = ?", r.GetOrg()). + Where("repo = ?", r.GetName()). + Where(filters). + Count(&s). + Error + + return s, err +} diff --git a/database/secret/count_repo_test.go b/database/secret/count_repo_test.go new file mode 100644 index 000000000..be2dc7a9c --- /dev/null +++ b/database/secret/count_repo_test.go @@ -0,0 +1,120 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/go-vela/types/constants" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSecret_Engine_CountSecretsForRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("bar") + _secretTwo.SetRepo("foo") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND repo = $3`). + WithArgs(constants.SecretRepo, "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSecretsForRepo(_repo, filters) + + if test.failure { + if err == nil { + t.Errorf("CountSecretsForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSecretsForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSecretsForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/count_team.go b/database/secret/count_team.go new file mode 100644 index 000000000..30c7a4255 --- /dev/null +++ b/database/secret/count_team.go @@ -0,0 +1,68 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "strings" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// CountSecretsForTeam gets the count of secrets by org and team name from the database. +func (e *engine) CountSecretsForTeam(org, team string, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "team": team, + "type": constants.SecretShared, + }).Tracef("getting count of secrets for team %s/%s from the database", org, team) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretShared). + Where("org = ?", org). + Where("team = ?", team). + Where(filters). + Count(&s). + Error + + return s, err +} + +// CountSecretsForTeams gets the count of secrets by teams within an org from the database. +func (e *engine) CountSecretsForTeams(org string, teams []string, filters map[string]interface{}) (int64, error) { + // lower case team names for not case-sensitive values from the SCM i.e. GitHub + // + // iterate through the list of teams provided + for index, team := range teams { + // ensure the team name is lower case + teams[index] = strings.ToLower(team) + } + + e.logger.WithFields(logrus.Fields{ + "org": org, + "teams": teams, + "type": constants.SecretShared, + }).Tracef("getting count of secrets for teams %s in org %s from the database", teams, org) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretShared). + Where("org = ?", org). + Where("LOWER(team) IN (?)", teams). + Where(filters). + Count(&s). + Error + + return s, err +} diff --git a/database/secret/count_team_test.go b/database/secret/count_team_test.go new file mode 100644 index 000000000..7b029d9e8 --- /dev/null +++ b/database/secret/count_team_test.go @@ -0,0 +1,216 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/go-vela/types/constants" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSecret_Engine_CountSecretsForTeam(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetTeam("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("bar") + _secretTwo.SetTeam("foo") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND team = $3`). + WithArgs(constants.SecretShared, "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSecretsForTeam("foo", "bar", filters) + + if test.failure { + if err == nil { + t.Errorf("CountSecretsForTeam for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSecretsForTeam for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSecretsForTeam for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +func TestSecret_Engine_CountSecretsForTeams(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetTeam("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("bar") + _secretTwo.SetTeam("foo") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND LOWER(team) IN ($3,$4)`). + WithArgs(constants.SecretShared, "foo", "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSecretsForTeams("foo", []string{"foo", "bar"}, filters) + + if test.failure { + if err == nil { + t.Errorf("CountSecretsForTeams for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSecretsForTeams for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSecretsForTeams for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/count_test.go b/database/secret/count_test.go new file mode 100644 index 000000000..b30dcdca2 --- /dev/null +++ b/database/secret/count_test.go @@ -0,0 +1,105 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSecret_Engine_CountSecrets(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("bar") + _secretTwo.SetRepo("foo") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSecrets() + + if test.failure { + if err == nil { + t.Errorf("CountSecrets for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSecrets for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSecrets for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/create.go b/database/secret/create.go new file mode 100644 index 000000000..e061c36a1 --- /dev/null +++ b/database/secret/create.go @@ -0,0 +1,68 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with update.go +package secret + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateSecret creates a new secret in the database. +func (e *engine) CreateSecret(s *library.Secret) error { + // handle the secret based off the type + switch s.GetType() { + case constants.SecretShared: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "team": s.GetTeam(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("creating secret %s/%s/%s/%s in the database", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName()) + default: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "repo": s.GetRepo(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("creating secret %s/%s/%s/%s in the database", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#SecretFromLibrary + secret := database.SecretFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Validate + err := secret.Validate() + if err != nil { + return err + } + + // encrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt + err = secret.Encrypt(e.config.EncryptionKey) + if err != nil { + switch s.GetType() { + case constants.SecretShared: + return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + default: + return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + } + } + + // send query to the database + return e.client. + Table(constants.TableSecret). + Create(secret.Nullify()). + Error +} diff --git a/database/secret/create_test.go b/database/secret/create_test.go new file mode 100644 index 000000000..1f6fbd3bd --- /dev/null +++ b/database/secret/create_test.go @@ -0,0 +1,145 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_CreateSecret(t *testing.T) { + // setup types + _secretRepo := testSecret() + _secretRepo.SetID(1) + _secretRepo.SetOrg("foo") + _secretRepo.SetRepo("bar") + _secretRepo.SetName("baz") + _secretRepo.SetValue("foob") + _secretRepo.SetType("repo") + _secretRepo.SetCreatedAt(1) + _secretRepo.SetCreatedBy("user") + _secretRepo.SetUpdatedAt(1) + _secretRepo.SetUpdatedBy("user2") + + _secretOrg := testSecret() + _secretOrg.SetID(2) + _secretOrg.SetOrg("foo") + _secretOrg.SetRepo("*") + _secretOrg.SetName("bar") + _secretOrg.SetValue("baz") + _secretOrg.SetType("org") + _secretOrg.SetCreatedAt(1) + _secretOrg.SetCreatedBy("user") + _secretOrg.SetUpdatedAt(1) + _secretOrg.SetUpdatedBy("user2") + + _secretShared := testSecret() + _secretShared.SetID(3) + _secretShared.SetOrg("foo") + _secretShared.SetTeam("bar") + _secretShared.SetName("baz") + _secretShared.SetValue("foob") + _secretShared.SetType("shared") + _secretShared.SetCreatedAt(1) + _secretShared.SetCreatedBy("user") + _secretShared.SetUpdatedAt(1) + _secretShared.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the repo secrets query + _mock.ExpectQuery(`INSERT INTO "secrets" +("org","repo","team","name","value","type","images","events","allow_command","created_at","created_by","updated_at","updated_by","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). + WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", nil, nil, false, 1, "user", 1, "user2", 1). + WillReturnRows(_rows) + + // ensure the mock expects the org secrets query + _mock.ExpectQuery(`INSERT INTO "secrets" +("org","repo","team","name","value","type","images","events","allow_command","created_at","created_by","updated_at","updated_by","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). + WithArgs("foo", "*", nil, "bar", AnyArgument{}, "org", nil, nil, false, 1, "user", 1, "user2", 2). + WillReturnRows(_rows) + + // ensure the mock expects the shared secrets query + _mock.ExpectQuery(`INSERT INTO "secrets" +("org","repo","team","name","value","type","images","events","allow_command","created_at","created_by","updated_at","updated_by","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). + WithArgs("foo", nil, "bar", "baz", AnyArgument{}, "shared", nil, nil, false, 1, "user", 1, "user2", 3). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + secret *library.Secret + }{ + { + failure: false, + name: "postgres with repo", + database: _postgres, + secret: _secretRepo, + }, + { + failure: false, + name: "postgres with org", + database: _postgres, + secret: _secretOrg, + }, + { + failure: false, + name: "postgres with shared", + database: _postgres, + secret: _secretShared, + }, + { + failure: false, + name: "sqlite3 with repo", + database: _sqlite, + secret: _secretRepo, + }, + { + failure: false, + name: "sqlite3 with org", + database: _sqlite, + secret: _secretOrg, + }, + { + failure: false, + name: "sqlite3 with shared", + database: _sqlite, + secret: _secretShared, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateSecret(test.secret) + + if test.failure { + if err == nil { + t.Errorf("CreateSecret for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateSecret for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/secret/delete.go b/database/secret/delete.go new file mode 100644 index 000000000..a9207bbd9 --- /dev/null +++ b/database/secret/delete.go @@ -0,0 +1,46 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteSecret deletes an existing secret from the database. +func (e *engine) DeleteSecret(s *library.Secret) error { + // handle the secret based off the type + // + //nolint:dupl // ignore similar code with update.go + switch s.GetType() { + case constants.SecretShared: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "team": s.GetTeam(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("deleting secret %s/%s/%s/%s from the database", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName()) + default: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "repo": s.GetRepo(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("deleting secret %s/%s/%s/%s from the database", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#SecretFromLibrary + secret := database.SecretFromLibrary(s) + + // send query to the database + return e.client. + Table(constants.TableSecret). + Delete(secret). + Error +} diff --git a/database/secret/delete_test.go b/database/secret/delete_test.go new file mode 100644 index 000000000..c44202544 --- /dev/null +++ b/database/secret/delete_test.go @@ -0,0 +1,151 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_DeleteSecret(t *testing.T) { + // setup types + _secretRepo := testSecret() + _secretRepo.SetID(1) + _secretRepo.SetOrg("foo") + _secretRepo.SetRepo("bar") + _secretRepo.SetName("baz") + _secretRepo.SetValue("foob") + _secretRepo.SetType("repo") + _secretRepo.SetCreatedAt(1) + _secretRepo.SetCreatedBy("user") + _secretRepo.SetUpdatedAt(1) + _secretRepo.SetUpdatedBy("user2") + + _secretOrg := testSecret() + _secretOrg.SetID(2) + _secretOrg.SetOrg("foo") + _secretOrg.SetRepo("*") + _secretOrg.SetName("bar") + _secretOrg.SetValue("baz") + _secretOrg.SetType("org") + _secretOrg.SetCreatedAt(1) + _secretOrg.SetCreatedBy("user") + _secretOrg.SetUpdatedAt(1) + _secretOrg.SetUpdatedBy("user2") + + _secretShared := testSecret() + _secretShared.SetID(3) + _secretShared.SetOrg("foo") + _secretShared.SetTeam("bar") + _secretShared.SetName("baz") + _secretShared.SetValue("foob") + _secretShared.SetType("shared") + _secretShared.SetCreatedAt(1) + _secretShared.SetCreatedBy("user") + _secretShared.SetUpdatedAt(1) + _secretShared.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the repo query + _mock.ExpectExec(`DELETE FROM "secrets" WHERE "secrets"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the org query + _mock.ExpectExec(`DELETE FROM "secrets" WHERE "secrets"."id" = $1`). + WithArgs(2). + WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the shared query + _mock.ExpectExec(`DELETE FROM "secrets" WHERE "secrets"."id" = $1`). + WithArgs(3). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretRepo) + if err != nil { + t.Errorf("unable to create test repo secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretOrg) + if err != nil { + t.Errorf("unable to create test org secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretShared) + if err != nil { + t.Errorf("unable to create test shared secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + secret *library.Secret + }{ + { + failure: false, + name: "postgres with repo", + database: _postgres, + secret: _secretRepo, + }, + { + failure: false, + name: "postgres with org", + database: _postgres, + secret: _secretOrg, + }, + { + failure: false, + name: "postgres with shared", + database: _postgres, + secret: _secretShared, + }, + { + failure: false, + name: "sqlite3 with repo", + database: _sqlite, + secret: _secretRepo, + }, + { + failure: false, + name: "sqlite3 with org", + database: _sqlite, + secret: _secretOrg, + }, + { + failure: false, + name: "sqlite3 with shared", + database: _sqlite, + secret: _secretShared, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteSecret(test.secret) + + if test.failure { + if err == nil { + t.Errorf("DeleteSecret for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteSecret for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/secret/get.go b/database/secret/get.go new file mode 100644 index 000000000..67579c000 --- /dev/null +++ b/database/secret/get.go @@ -0,0 +1,52 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetSecret gets a secret by ID from the database. +func (e *engine) GetSecret(id int64) (*library.Secret, error) { + e.logger.Tracef("getting secret %d from the database", id) + + // variable to store query results + s := new(database.Secret) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("id = ?", id). + Take(s). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = s.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", id, err) + + // return the unencrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil + } + + // return the decrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/secret/get_org.go b/database/secret/get_org.go new file mode 100644 index 000000000..f7f3e9adc --- /dev/null +++ b/database/secret/get_org.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetSecretForOrg gets a secret by org name from the database. +func (e *engine) GetSecretForOrg(org, name string) (*library.Secret, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "secret": name, + "type": constants.SecretOrg, + }).Tracef("getting org secret %s/%s from the database", org, name) + + // variable to store query results + s := new(database.Secret) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretOrg). + Where("org = ?", org). + Where("name = ?", name). + Take(s). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = s.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt org secret %s/%s: %v", org, name, err) + + // return the unencrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil + } + + // return the decrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/secret/get_org_test.go b/database/secret/get_org_test.go new file mode 100644 index 000000000..107c2d804 --- /dev/null +++ b/database/secret/get_org_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_GetSecretForOrg(t *testing.T) { + // setup types + _secret := testSecret() + _secret.SetID(1) + _secret.SetOrg("foo") + _secret.SetRepo("*") + _secret.SetName("baz") + _secret.SetValue("bar") + _secret.SetType("org") + _secret.SetCreatedAt(1) + _secret.SetCreatedBy("user") + _secret.SetUpdatedAt(1) + _secret.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(1, "org", "foo", "*", "", "baz", "bar", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND name = $3 LIMIT 1`). + WithArgs(constants.SecretOrg, "foo", "baz").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secret) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _secret, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _secret, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetSecretForOrg("foo", "baz") + + if test.failure { + if err == nil { + t.Errorf("GetSecretForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetSecretForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetSecretForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/get_repo.go b/database/secret/get_repo.go new file mode 100644 index 000000000..6d7ca9dd9 --- /dev/null +++ b/database/secret/get_repo.go @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetSecretForRepo gets a secret by org and repo name from the database. +func (e *engine) GetSecretForRepo(name string, r *library.Repo) (*library.Secret, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "secret": name, + "type": constants.SecretRepo, + }).Tracef("getting repo secret %s/%s from the database", r.GetFullName(), name) + + // variable to store query results + s := new(database.Secret) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretRepo). + Where("org = ?", r.GetOrg()). + Where("repo = ?", r.GetName()). + Where("name = ?", name). + Take(s). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = s.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt repo secret %s/%s: %v", r.GetFullName(), name, err) + + // return the unencrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil + } + + // return the decrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/secret/get_repo_test.go b/database/secret/get_repo_test.go new file mode 100644 index 000000000..98b9f1da6 --- /dev/null +++ b/database/secret/get_repo_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_GetSecretForRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _secret := testSecret() + _secret.SetID(1) + _secret.SetOrg("foo") + _secret.SetRepo("bar") + _secret.SetName("baz") + _secret.SetValue("foob") + _secret.SetType("repo") + _secret.SetCreatedAt(1) + _secret.SetCreatedBy("user") + _secret.SetUpdatedAt(1) + _secret.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(1, "repo", "foo", "bar", "", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND repo = $3 AND name = $4 LIMIT 1`). + WithArgs(constants.SecretRepo, "foo", "bar", "baz").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secret) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _secret, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _secret, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetSecretForRepo("baz", _repo) + + if test.failure { + if err == nil { + t.Errorf("GetSecretForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetSecretForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetSecretForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/get_team.go b/database/secret/get_team.go new file mode 100644 index 000000000..306923ee1 --- /dev/null +++ b/database/secret/get_team.go @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetSecretForTeam gets a secret by org and team name from the database. +func (e *engine) GetSecretForTeam(org, team, name string) (*library.Secret, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "team": team, + "secret": name, + "type": constants.SecretShared, + }).Tracef("getting shared secret %s/%s/%s from the database", org, team, name) + + // variable to store query results + s := new(database.Secret) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretShared). + Where("org = ?", org). + Where("team = ?", team). + Where("name = ?", name). + Take(s). + Error + if err != nil { + return nil, err + } + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = s.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt shared secret %s/%s/%s: %v", org, team, name, err) + + // return the unencrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil + } + + // return the decrypted secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/secret/get_team_test.go b/database/secret/get_team_test.go new file mode 100644 index 000000000..8705a4e96 --- /dev/null +++ b/database/secret/get_team_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_GetSecretForTeam(t *testing.T) { + // setup types + _secret := testSecret() + _secret.SetID(1) + _secret.SetOrg("foo") + _secret.SetTeam("bar") + _secret.SetName("baz") + _secret.SetValue("foob") + _secret.SetType("shared") + _secret.SetCreatedAt(1) + _secret.SetCreatedBy("user") + _secret.SetUpdatedAt(1) + _secret.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(1, "shared", "foo", "", "bar", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND team = $3 AND name = $4 LIMIT 1`). + WithArgs(constants.SecretShared, "foo", "bar", "baz").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secret) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _secret, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _secret, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetSecretForTeam("foo", "bar", "baz") + + if test.failure { + if err == nil { + t.Errorf("GetSecretForTeam for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetSecretForTeam for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetSecretForTeam for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/get_test.go b/database/secret/get_test.go new file mode 100644 index 000000000..c4499c0fc --- /dev/null +++ b/database/secret/get_test.go @@ -0,0 +1,91 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_GetSecret(t *testing.T) { + // setup types + _secret := testSecret() + _secret.SetID(1) + _secret.SetOrg("foo") + _secret.SetRepo("bar") + _secret.SetName("baz") + _secret.SetValue("foob") + _secret.SetType("repo") + _secret.SetCreatedAt(1) + _secret.SetCreatedBy("user") + _secret.SetUpdatedAt(1) + _secret.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(1, "repo", "foo", "bar", "", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secret) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _secret, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _secret, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetSecret(1) + + if test.failure { + if err == nil { + t.Errorf("GetSecret for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetSecret for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetSecret for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/index.go b/database/secret/index.go new file mode 100644 index 000000000..7b6a2047a --- /dev/null +++ b/database/secret/index.go @@ -0,0 +1,52 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +const ( + // CreateTypeOrgRepo represents a query to create an + // index on the secrets table for the type, org and repo columns. + CreateTypeOrgRepo = ` +CREATE INDEX +IF NOT EXISTS +secrets_type_org_repo +ON secrets (type, org, repo); +` + // CreateTypeOrgTeam represents a query to create an + // index on the secrets table for the type, org and team columns. + CreateTypeOrgTeam = ` +CREATE INDEX +IF NOT EXISTS +secrets_type_org_team +ON secrets (type, org, team); +` + // CreateTypeOrg represents a query to create an + // index on the secrets table for the type, and org columns. + CreateTypeOrg = ` +CREATE INDEX +IF NOT EXISTS +secrets_type_org +ON secrets (type, org); +` +) + +// CreateSecretIndexes creates the indexes for the secrets table in the database. +func (e *engine) CreateSecretIndexes() error { + e.logger.Tracef("creating indexes for secrets table in the database") + + // create the type, org and repo columns index for the secrets table + err := e.client.Exec(CreateTypeOrgRepo).Error + if err != nil { + return err + } + + // create the type, org and team columns index for the secrets table + err = e.client.Exec(CreateTypeOrgTeam).Error + if err != nil { + return err + } + + // create the type and org columns index for the secrets table + return e.client.Exec(CreateTypeOrg).Error +} diff --git a/database/secret/index_test.go b/database/secret/index_test.go new file mode 100644 index 000000000..67a64d09d --- /dev/null +++ b/database/secret/index_test.go @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSecret_Engine_CreateSecretIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateSecretIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateSecretIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateSecretIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/secret/list.go b/database/secret/list.go new file mode 100644 index 000000000..fd01dc295 --- /dev/null +++ b/database/secret/list.go @@ -0,0 +1,67 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListSecrets gets a list of all secrets from the database. +func (e *engine) ListSecrets() ([]*library.Secret, error) { + e.logger.Trace("listing all secrets from the database") + + // variables to store query results and return value + count := int64(0) + s := new([]database.Secret) + secrets := []*library.Secret{} + + // count the results + count, err := e.CountSecrets() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return secrets, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSecret). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, secret := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + secrets = append(secrets, tmp.ToLibrary()) + } + + return secrets, nil +} diff --git a/database/secret/list_org.go b/database/secret/list_org.go new file mode 100644 index 000000000..27078a0f3 --- /dev/null +++ b/database/secret/list_org.go @@ -0,0 +1,82 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListSecretsForOrg gets a list of secrets by org name from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListSecretsForOrg(org string, filters map[string]interface{}, page, perPage int) ([]*library.Secret, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "type": constants.SecretOrg, + }).Tracef("listing secrets for org %s from the database", org) + + // variables to store query results and return values + count := int64(0) + s := new([]database.Secret) + secrets := []*library.Secret{} + + // count the results + count, err := e.CountSecretsForOrg(org, filters) + if err != nil { + return secrets, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return secrets, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretOrg). + Where("org = ?", org). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, secret := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + secrets = append(secrets, tmp.ToLibrary()) + } + + return secrets, count, nil +} diff --git a/database/secret/list_org_test.go b/database/secret/list_org_test.go new file mode 100644 index 000000000..dbf6695a4 --- /dev/null +++ b/database/secret/list_org_test.go @@ -0,0 +1,120 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_ListSecretsForOrg(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("*") + _secretOne.SetName("baz") + _secretOne.SetValue("bar") + _secretOne.SetType("org") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("foo") + _secretTwo.SetRepo("*") + _secretTwo.SetName("bar") + _secretTwo.SetValue("baz") + _secretTwo.SetType("org") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2`). + WithArgs(constants.SecretOrg, "foo").WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(2, "org", "foo", "*", "", "bar", "baz", nil, nil, false, 1, "user", 1, "user2"). + AddRow(1, "org", "foo", "*", "", "baz", "bar", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 ORDER BY id DESC LIMIT 10`). + WithArgs(constants.SecretOrg, "foo").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + { + failure: false, + name: "sqlite", + database: _sqlite, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListSecretsForOrg("foo", filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListSecretsForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSecretsForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSecretsForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/list_repo.go b/database/secret/list_repo.go new file mode 100644 index 000000000..c89ba1500 --- /dev/null +++ b/database/secret/list_repo.go @@ -0,0 +1,84 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListSecretsForRepo gets a list of secrets by org name from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListSecretsForRepo(r *library.Repo, filters map[string]interface{}, page, perPage int) ([]*library.Secret, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "type": constants.SecretRepo, + }).Tracef("listing secrets for repo %s from the database", r.GetFullName()) + + // variables to store query results and return values + count := int64(0) + s := new([]database.Secret) + secrets := []*library.Secret{} + + // count the results + count, err := e.CountSecretsForRepo(r, filters) + if err != nil { + return secrets, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return secrets, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretRepo). + Where("org = ?", r.GetOrg()). + Where("repo = ?", r.GetName()). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, secret := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + secrets = append(secrets, tmp.ToLibrary()) + } + + return secrets, count, nil +} diff --git a/database/secret/list_repo_test.go b/database/secret/list_repo_test.go new file mode 100644 index 000000000..10f389f8a --- /dev/null +++ b/database/secret/list_repo_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/go-vela/types/constants" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_ListSecretsForRepo(t *testing.T) { + // setup types + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("foo") + _secretTwo.SetRepo("bar") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND repo = $3`). + WithArgs(constants.SecretRepo, "foo", "bar").WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(2, "repo", "foo", "bar", "", "foob", "baz", nil, nil, false, 1, "user", 1, "user2"). + AddRow(1, "repo", "foo", "bar", "", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND repo = $3 ORDER BY id DESC LIMIT 10`). + WithArgs(constants.SecretRepo, "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + { + failure: false, + name: "sqlite", + database: _sqlite, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListSecretsForRepo(_repo, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListSecretsForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSecretsForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSecretsForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/list_team.go b/database/secret/list_team.go new file mode 100644 index 000000000..0897fe949 --- /dev/null +++ b/database/secret/list_team.go @@ -0,0 +1,162 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "strings" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListSecretsForTeam gets a list of secrets by org and team name from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListSecretsForTeam(org, team string, filters map[string]interface{}, page, perPage int) ([]*library.Secret, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + "team": team, + "type": constants.SecretShared, + }).Tracef("listing secrets for team %s/%s from the database", org, team) + + // variables to store query results and return values + count := int64(0) + s := new([]database.Secret) + secrets := []*library.Secret{} + + // count the results + count, err := e.CountSecretsForTeam(org, team, filters) + if err != nil { + return secrets, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return secrets, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretShared). + Where("org = ?", org). + Where("team = ?", team). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, secret := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + secrets = append(secrets, tmp.ToLibrary()) + } + + return secrets, count, nil +} + +// ListSecretsForTeams gets a list of secrets by teams within an org from the database. +func (e *engine) ListSecretsForTeams(org string, teams []string, filters map[string]interface{}, page, perPage int) ([]*library.Secret, int64, error) { + // iterate through the list of teams provided + for index, team := range teams { + // ensure the team name is lower case + teams[index] = strings.ToLower(team) + } + + e.logger.WithFields(logrus.Fields{ + "org": org, + "teams": teams, + "type": constants.SecretShared, + }).Tracef("listing secrets for teams %s in org %s from the database", teams, org) + + // variables to store query results and return values + count := int64(0) + s := new([]database.Secret) + secrets := []*library.Secret{} + + // count the results + count, err := e.CountSecretsForTeams(org, teams, filters) + if err != nil { + return secrets, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return secrets, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSecret). + Where("type = ?", constants.SecretShared). + Where("org = ?", org). + Where("LOWER(team) IN (?)", teams). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, secret := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // decrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt + err = tmp.Decrypt(e.config.EncryptionKey) + if err != nil { + // TODO: remove backwards compatibility before 1.x.x release + // + // ensures that the change is backwards compatible + // by logging the error instead of returning it + // which allows us to fetch unencrypted secrets + e.logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) + } + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.ToLibrary + secrets = append(secrets, tmp.ToLibrary()) + } + + return secrets, count, nil +} diff --git a/database/secret/list_team_test.go b/database/secret/list_team_test.go new file mode 100644 index 000000000..39492f52a --- /dev/null +++ b/database/secret/list_team_test.go @@ -0,0 +1,227 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/go-vela/types/constants" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_ListSecretsForTeam(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetTeam("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("foo") + _secretTwo.SetTeam("bar") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND team = $3`). + WithArgs(constants.SecretShared, "foo", "bar").WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(2, "shared", "foo", "", "bar", "foob", "baz", nil, nil, false, 1, "user", 1, "user2"). + AddRow(1, "shared", "foo", "", "bar", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND team = $3 ORDER BY id DESC LIMIT 10`). + WithArgs(constants.SecretShared, "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + { + failure: false, + name: "sqlite", + database: _sqlite, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListSecretsForTeam("foo", "bar", filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListSecretsForTeam for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSecretsForTeam for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSecretsForTeam for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +func TestSecret_Engine_ListSecretsForTeams(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetTeam("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("shared") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("foo") + _secretTwo.SetTeam("bar") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("shared") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected name count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the name count query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets" WHERE type = $1 AND org = $2 AND LOWER(team) IN ($3,$4)`). + WithArgs(constants.SecretShared, "foo", "foo", "bar").WillReturnRows(_rows) + + // create expected name query result in mock + _rows = sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(2, "shared", "foo", "", "bar", "foob", "baz", nil, nil, false, 1, "user", 1, "user2"). + AddRow(1, "shared", "foo", "", "bar", "baz", "foob", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT * FROM "secrets" WHERE type = $1 AND org = $2 AND LOWER(team) IN ($3,$4) ORDER BY id DESC LIMIT 10`). + WithArgs(constants.SecretShared, "foo", "foo", "bar").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + { + failure: false, + name: "sqlite", + database: _sqlite, + want: []*library.Secret{_secretTwo, _secretOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListSecretsForTeams("foo", []string{"foo", "bar"}, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListSecretsForTeams for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSecretsForTeams for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSecretsForTeams for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/list_test.go b/database/secret/list_test.go new file mode 100644 index 000000000..b962925ed --- /dev/null +++ b/database/secret/list_test.go @@ -0,0 +1,115 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_ListSecrets(t *testing.T) { + // setup types + _secretOne := testSecret() + _secretOne.SetID(1) + _secretOne.SetOrg("foo") + _secretOne.SetRepo("bar") + _secretOne.SetName("baz") + _secretOne.SetValue("foob") + _secretOne.SetType("repo") + _secretOne.SetCreatedAt(1) + _secretOne.SetCreatedBy("user") + _secretOne.SetUpdatedAt(1) + _secretOne.SetUpdatedBy("user2") + + _secretTwo := testSecret() + _secretTwo.SetID(2) + _secretTwo.SetOrg("foo") + _secretTwo.SetRepo("bar") + _secretTwo.SetName("foob") + _secretTwo.SetValue("baz") + _secretTwo.SetType("repo") + _secretTwo.SetCreatedAt(1) + _secretTwo.SetCreatedBy("user") + _secretTwo.SetUpdatedAt(1) + _secretTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "secrets"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "type", "org", "repo", "team", "name", "value", "images", "events", "allow_command", "created_at", "created_by", "updated_at", "updated_by"}). + AddRow(1, "repo", "foo", "bar", "", "baz", "foob", nil, nil, false, 1, "user", 1, "user2"). + AddRow(2, "repo", "foo", "bar", "", "foob", "baz", nil, nil, false, 1, "user", 1, "user2") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "secrets"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretOne) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretTwo) + if err != nil { + t.Errorf("unable to create test secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Secret + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Secret{_secretOne, _secretTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Secret{_secretOne, _secretTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListSecrets() + + if test.failure { + if err == nil { + t.Errorf("ListSecrets for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSecrets for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSecrets for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/secret/opts.go b/database/secret/opts.go new file mode 100644 index 000000000..0e6e7935f --- /dev/null +++ b/database/secret/opts.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Secrets. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Secrets. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the secret engine + e.client = client + + return nil + } +} + +// WithEncryptionKey sets the encryption key in the database engine for Secrets. +func WithEncryptionKey(key string) EngineOpt { + return func(e *engine) error { + // set the encryption key in the secret engine + e.config.EncryptionKey = key + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Secrets. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the secret engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Secrets. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the secret engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/secret/opts_test.go b/database/secret/opts_test.go new file mode 100644 index 000000000..0e123abdb --- /dev/null +++ b/database/secret/opts_test.go @@ -0,0 +1,210 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestSecret_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestSecret_EngineOpt_WithEncryptionKey(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + key string + want string + }{ + { + failure: false, + name: "encryption key set", + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + }, + { + failure: false, + name: "encryption key not set", + key: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithEncryptionKey(test.key)(e) + + if test.failure { + if err == nil { + t.Errorf("WithEncryptionKey for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithEncryptionKey returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.EncryptionKey, test.want) { + t.Errorf("WithEncryptionKey is %v, want %v", e.config.EncryptionKey, test.want) + } + }) + } +} + +func TestSecret_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestSecret_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/secret/secret.go b/database/secret/secret.go new file mode 100644 index 000000000..9f19279f4 --- /dev/null +++ b/database/secret/secret.go @@ -0,0 +1,82 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the SecretService interface. + config struct { + // specifies the encryption key to use for the Secret engine + EncryptionKey string + // specifies to skip creating tables and indexes for the Secret engine + SkipCreation bool + } + + // engine represents the secret functionality that implements the SecretService interface. + engine struct { + // engine configuration settings used in secret functions + config *config + + // gorm.io/gorm database client used in secret functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in secret functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with secrets in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Secret engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating secret database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of secrets table and indexes in the database") + + return e, nil + } + + // create the secrets table + err := e.CreateSecretTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableSecret, err) + } + + // create the indexes for the secrets table + err = e.CreateSecretIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableSecret, err) + } + + return e, nil +} diff --git a/database/secret/secret_test.go b/database/secret/secret_test.go new file mode 100644 index 000000000..228567344 --- /dev/null +++ b/database/secret/secret_test.go @@ -0,0 +1,240 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestSecret_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithEncryptionKey(test.key), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres secret engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite secret engine: %v", err) + } + + return _engine +} + +// testRepo is a test helper function to create a library +// Repo type with all fields set to their zero values. +func testRepo() *library.Repo { + return &library.Repo{ + ID: new(int64), + UserID: 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), + AllowPull: new(bool), + AllowPush: new(bool), + AllowDeploy: new(bool), + AllowTag: new(bool), + AllowComment: new(bool), + } +} + +// testSecret is a test helper function to create a library +// Secret type with all fields set to their zero values. +func testSecret() *library.Secret { + return &library.Secret{ + ID: new(int64), + Org: new(string), + Repo: new(string), + Team: new(string), + Name: new(string), + Value: new(string), + Type: new(string), + Images: new([]string), + Events: new([]string), + AllowCommand: new(bool), + CreatedAt: new(int64), + CreatedBy: new(string), + UpdatedAt: new(int64), + UpdatedBy: 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. +// +// 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 +} diff --git a/database/secret/service.go b/database/secret/service.go new file mode 100644 index 000000000..7637a91b8 --- /dev/null +++ b/database/secret/service.go @@ -0,0 +1,63 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "github.com/go-vela/types/library" +) + +// SecretService represents the Vela interface for secret +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type SecretService interface { + // Secret Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateSecretIndexes defines a function that creates the indexes for the secrets table. + CreateSecretIndexes() error + // CreateSecretTable defines a function that creates the secrets table. + CreateSecretTable(string) error + + // Secret Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountSecrets defines a function that gets the count of all secrets. + CountSecrets() (int64, error) + // CountSecretsForOrg defines a function that gets the count of secrets by org name. + CountSecretsForOrg(string, map[string]interface{}) (int64, error) + // CountSecretsForRepo defines a function that gets the count of secrets by org and repo name. + CountSecretsForRepo(*library.Repo, map[string]interface{}) (int64, error) + // CountSecretsForTeam defines a function that gets the count of secrets by org and team name. + CountSecretsForTeam(string, string, map[string]interface{}) (int64, error) + // CountSecretsForTeams defines a function that gets the count of secrets by teams within an org. + CountSecretsForTeams(string, []string, map[string]interface{}) (int64, error) + // CreateSecret defines a function that creates a new secret. + CreateSecret(*library.Secret) error + // DeleteSecret defines a function that deletes an existing secret. + DeleteSecret(*library.Secret) error + // GetSecret defines a function that gets a secret by ID. + GetSecret(int64) (*library.Secret, error) + // GetSecretForOrg defines a function that gets a secret by org name. + GetSecretForOrg(string, string) (*library.Secret, error) + // GetSecretForRepo defines a function that gets a secret by org and repo name. + GetSecretForRepo(string, *library.Repo) (*library.Secret, error) + // GetSecretForTeam defines a function that gets a secret by org and team name. + GetSecretForTeam(string, string, string) (*library.Secret, error) + // ListSecrets defines a function that gets a list of all secrets. + ListSecrets() ([]*library.Secret, error) + // ListSecretsForOrg defines a function that gets a list of secrets by org name. + ListSecretsForOrg(string, map[string]interface{}, int, int) ([]*library.Secret, int64, error) + // ListSecretsForRepo defines a function that gets a list of secrets by org and repo name. + ListSecretsForRepo(*library.Repo, map[string]interface{}, int, int) ([]*library.Secret, int64, error) + // ListSecretsForTeam defines a function that gets a list of secrets by org and team name. + ListSecretsForTeam(string, string, map[string]interface{}, int, int) ([]*library.Secret, int64, error) + // ListSecretsForTeams defines a function that gets a list of secrets by teams within an org. + ListSecretsForTeams(string, []string, map[string]interface{}, int, int) ([]*library.Secret, int64, error) + // UpdateSecret defines a function that updates an existing secret. + UpdateSecret(*library.Secret) error +} diff --git a/database/secret/table.go b/database/secret/table.go new file mode 100644 index 000000000..b36b6c4e9 --- /dev/null +++ b/database/secret/table.go @@ -0,0 +1,74 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import "github.com/go-vela/types/constants" + +const ( + // CreatePostgresTable represents a query to create the Postgres secrets table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +secrets ( + id SERIAL PRIMARY KEY, + type VARCHAR(100), + org VARCHAR(250), + repo VARCHAR(250), + team VARCHAR(250), + name VARCHAR(250), + value BYTEA, + images VARCHAR(1000), + events VARCHAR(1000), + allow_command BOOLEAN, + created_at INTEGER, + created_by VARCHAR(250), + updated_at INTEGER, + updated_by VARCHAR(250), + UNIQUE(type, org, repo, name), + UNIQUE(type, org, team, name) +); +` + + // CreateSqliteTable represents a query to create the Sqlite secrets table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +secrets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + type TEXT, + org TEXT, + repo TEXT, + team TEXT, + name TEXT, + value TEXT, + images TEXT, + events TEXT, + allow_command BOOLEAN, + created_at INTEGER, + created_by TEXT, + updated_at INTEGER, + updated_by TEXT, + UNIQUE(type, org, repo, name), + UNIQUE(type, org, team, name) +); +` +) + +// CreateSecretTable creates the secrets table in the database. +func (e *engine) CreateSecretTable(driver string) error { + e.logger.Tracef("creating secrets table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the secrets table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the secrets table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/secret/table_test.go b/database/secret/table_test.go new file mode 100644 index 000000000..055d84fa6 --- /dev/null +++ b/database/secret/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSecret_Engine_CreateSecretTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateSecretTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateSecretTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateSecretTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/secret/update.go b/database/secret/update.go new file mode 100644 index 000000000..3f00efb09 --- /dev/null +++ b/database/secret/update.go @@ -0,0 +1,68 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create.go +package secret + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateSecret updates an existing secret in the database. +func (e *engine) UpdateSecret(s *library.Secret) error { + // handle the secret based off the type + switch s.GetType() { + case constants.SecretShared: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "team": s.GetTeam(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("updating secret %s/%s/%s/%s in the database", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName()) + default: + e.logger.WithFields(logrus.Fields{ + "org": s.GetOrg(), + "repo": s.GetRepo(), + "secret": s.GetName(), + "type": s.GetType(), + }).Tracef("updating secret %s/%s/%s/%s in the database", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName()) + } + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#SecretFromLibrary + secret := database.SecretFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Validate + err := secret.Validate() + if err != nil { + return err + } + + // encrypt the fields for the secret + // + // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt + err = secret.Encrypt(e.config.EncryptionKey) + if err != nil { + switch s.GetType() { + case constants.SecretShared: + return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + default: + return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + } + } + + // send query to the database + return e.client. + Table(constants.TableSecret). + Save(secret.Nullify()). + Error +} diff --git a/database/secret/update_test.go b/database/secret/update_test.go new file mode 100644 index 000000000..e719e220e --- /dev/null +++ b/database/secret/update_test.go @@ -0,0 +1,158 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSecret_Engine_UpdateSecret(t *testing.T) { + // setup types + _secretRepo := testSecret() + _secretRepo.SetID(1) + _secretRepo.SetOrg("foo") + _secretRepo.SetRepo("bar") + _secretRepo.SetName("baz") + _secretRepo.SetValue("foob") + _secretRepo.SetType("repo") + _secretRepo.SetCreatedAt(1) + _secretRepo.SetCreatedBy("user") + _secretRepo.SetUpdatedAt(1) + _secretRepo.SetUpdatedBy("user2") + + _secretOrg := testSecret() + _secretOrg.SetID(2) + _secretOrg.SetOrg("foo") + _secretOrg.SetRepo("*") + _secretOrg.SetName("bar") + _secretOrg.SetValue("baz") + _secretOrg.SetType("org") + _secretOrg.SetCreatedAt(1) + _secretOrg.SetCreatedBy("user") + _secretOrg.SetUpdatedAt(1) + _secretOrg.SetUpdatedBy("user2") + + _secretShared := testSecret() + _secretShared.SetID(3) + _secretShared.SetOrg("foo") + _secretShared.SetTeam("bar") + _secretShared.SetName("baz") + _secretShared.SetValue("foob") + _secretShared.SetType("shared") + _secretShared.SetCreatedAt(1) + _secretShared.SetCreatedBy("user") + _secretShared.SetUpdatedAt(1) + _secretShared.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the repo query + _mock.ExpectExec(`UPDATE "secrets" +SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 +WHERE "id" = $14`). + WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the org query + _mock.ExpectExec(`UPDATE "secrets" +SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 +WHERE "id" = $14`). + WithArgs("foo", "*", nil, "bar", AnyArgument{}, "org", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 2). + WillReturnResult(sqlmock.NewResult(1, 1)) + + // ensure the mock expects the shared query + _mock.ExpectExec(`UPDATE "secrets" +SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 +WHERE "id" = $14`). + WithArgs("foo", nil, "bar", "baz", AnyArgument{}, "shared", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 3). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSecret(_secretRepo) + if err != nil { + t.Errorf("unable to create test repo secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretOrg) + if err != nil { + t.Errorf("unable to create test org secret for sqlite: %v", err) + } + + err = _sqlite.CreateSecret(_secretShared) + if err != nil { + t.Errorf("unable to create test shared secret for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + secret *library.Secret + }{ + { + failure: false, + name: "postgres with repo", + database: _postgres, + secret: _secretRepo, + }, + { + failure: false, + name: "postgres with org", + database: _postgres, + secret: _secretOrg, + }, + { + failure: false, + name: "postgres with shared", + database: _postgres, + secret: _secretShared, + }, + { + failure: false, + name: "sqlite3 with repo", + database: _sqlite, + secret: _secretRepo, + }, + { + failure: false, + name: "sqlite3 with org", + database: _sqlite, + secret: _secretOrg, + }, + { + failure: false, + name: "sqlite3 with shared", + database: _sqlite, + secret: _secretShared, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateSecret(test.secret) + + if test.failure { + if err == nil { + t.Errorf("UpdateSecret for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateSecret for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/service.go b/database/service.go index 33517b484..81d8ad960 100644 --- a/database/service.go +++ b/database/service.go @@ -9,6 +9,7 @@ import ( "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" @@ -90,29 +91,9 @@ type Service interface { // related to repos stored in the database. repo.RepoService - // Secret Database Interface Functions - - // GetSecret defines a function that gets a secret - // by type, org, name (repo or team) and secret name. - GetSecret(string, string, string, string) (*library.Secret, error) - // GetSecretList defines a function that - // gets a list of all secrets. - GetSecretList() ([]*library.Secret, error) - // GetTypeSecretList defines a function that gets a list - // of secrets by type, owner, and name (repo or team). - GetTypeSecretList(string, string, string, int, int, []string) ([]*library.Secret, error) - // GetTypeSecretCount defines a function that gets a count - // of secrets by type, owner, and name (repo or team). - GetTypeSecretCount(string, string, string, []string) (int64, error) - // CreateSecret defines a function that - // creates a new secret. - CreateSecret(*library.Secret) error - // UpdateSecret defines a function that - // updates a secret. - UpdateSecret(*library.Secret) error - // DeleteSecret defines a function that - // deletes a secret by unique ID. - DeleteSecret(int64) error + // SecretService provides the interface for functionality + // related to secrets stored in the database. + secret.SecretService // Step Database Interface Functions diff --git a/database/sqlite/ddl/secret.go b/database/sqlite/ddl/secret.go deleted file mode 100644 index a23bad110..000000000 --- a/database/sqlite/ddl/secret.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateSecretTable represents a query to - // create the secrets table for Vela. - CreateSecretTable = ` -CREATE TABLE -IF NOT EXISTS -secrets ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - type TEXT, - org TEXT, - repo TEXT, - team TEXT, - name TEXT, - value TEXT, - images TEXT, - events TEXT, - allow_command BOOLEAN, - created_at INTEGER, - created_by TEXT, - updated_at INTEGER, - updated_by TEXT, - UNIQUE(type, org, repo, name), - UNIQUE(type, org, team, name) -); -` - - // CreateSecretTypeOrgRepo represents a query to create an - // index on the secrets table for the type, org and repo columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrgRepo = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org_repo -ON secrets (type, org, repo); -` - - // CreateSecretTypeOrgTeam represents a query to create an - // index on the secrets table for the type, org and team columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrgTeam = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org_team -ON secrets (type, org, team); -` - - // CreateSecretTypeOrg represents a query to create an - // index on the secrets table for the type, and org columns. - // - //nolint:gosec // ignore false positive - CreateSecretTypeOrg = ` -CREATE INDEX -IF NOT EXISTS -secrets_type_org -ON secrets (type, org); -` -) diff --git a/database/sqlite/dml/secret.go b/database/sqlite/dml/secret.go deleted file mode 100644 index 28d7607bc..000000000 --- a/database/sqlite/dml/secret.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListSecrets represents a query to - // list all secrets in the database. - // - //nolint:gosec // ignore false positive - ListSecrets = ` -SELECT * -FROM secrets; -` - - // ListOrgSecrets represents a query to list all - // secrets for a type and org in the database. - // - //nolint:gosec // ignore false positive - ListOrgSecrets = ` -SELECT * -FROM secrets -WHERE type = 'org' -AND org = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // ListRepoSecrets represents a query to list all - // secrets for a type, org and repo in the database. - // - //nolint:gosec // ignore false positive - ListRepoSecrets = ` -SELECT * -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // ListSharedSecrets represents a query to list all - // secrets for a type, org and team in the database. - // - //nolint:gosec // ignore false positive - ListSharedSecrets = ` -SELECT * -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectOrgSecretsCount represents a query to select the - // count of org secrets for an org in the database. - // - //nolint:gosec // ignore false positive - SelectOrgSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'org' -AND org = ?; -` - - // SelectRepoSecretsCount represents a query to select the - // count of repo secrets for an org and repo in the database. - // - //nolint:gosec // ignore false positive - SelectRepoSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ?; -` - - // SelectSharedSecretsCount represents a query to select the - // count of shared secrets for an org and repo in the database. - // - //nolint:gosec // ignore false positive - SelectSharedSecretsCount = ` -SELECT count(*) as count -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ?; -` - - // SelectOrgSecret represents a query to select a - // secret for an org and name in the database. - // - //nolint:gosec // ignore false positive - SelectOrgSecret = ` -SELECT * -FROM secrets -WHERE type = 'org' -AND org = ? -AND name = ? -LIMIT 1; -` - - // SelectRepoSecret represents a query to select a - // secret for an org, repo and name in the database. - // - //nolint:gosec // ignore false positive - SelectRepoSecret = ` -SELECT * -FROM secrets -WHERE type = 'repo' -AND org = ? -AND repo = ? -AND name = ? -LIMIT 1; -` - - // SelectSharedSecret represents a query to select a - // secret for an org, team and name in the database. - // - //nolint:gosec // ignore false positive - SelectSharedSecret = ` -SELECT * -FROM secrets -WHERE type = 'shared' -AND org = ? -AND team = ? -AND name = ? -LIMIT 1; -` - - // DeleteSecret represents a query to - // remove a secret from the database. - // - //nolint:gosec // ignore false positive - DeleteSecret = ` -DELETE -FROM secrets -WHERE id = ?; -` -) diff --git a/database/sqlite/secret.go b/database/sqlite/secret.go deleted file mode 100644 index d4e25572a..000000000 --- a/database/sqlite/secret.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetSecret gets a secret by type, org, name (repo or team) and secret name from the database. -func (c *client) GetSecret(t, o, n, secretName string) (*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "secret": secretName, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "secret": secretName, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("getting %s secret %s for %s/%s from the database", t, secretName, o, n) - - var err error - - // variable to store query results - s := new(database.Secret) - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - result := c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectOrgSecret, o, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - case constants.SecretRepo: - result := c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectRepoSecret, o, n, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - case constants.SecretShared: - result := c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectSharedSecret, o, n, secretName). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - err = result.Error - } - - if err != nil { - return nil, err - } - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = s.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt %s secret %s for %s/%s: %v", t, secretName, o, n, err) - - // return the unencrypted secret - return s.ToLibrary(), nil - } - - // return the decrypted secret - return s.ToLibrary(), nil -} - -// CreateSecret creates a new secret in the database. -// -//nolint:dupl // ignore similar code with update -func (c *client) CreateSecret(s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": s.GetOrg(), - "repo": s.GetRepo(), - "secret": s.GetName(), - "type": s.GetType(), - } - - // check if secret is a shared secret - if strings.EqualFold(s.GetType(), constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": s.GetOrg(), - "team": s.GetTeam(), - "secret": s.GetName(), - "type": s.GetType(), - } - } - - c.Logger.WithFields(fields).Tracef("creating %s secret %s in the database", s.GetType(), s.GetName()) - - // cast to database type - secret := database.SecretFromLibrary(s) - - // validate the necessary fields are populated - err := secret.Validate() - if err != nil { - return err - } - - // encrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt - err = secret.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableSecret). - Create(secret.Nullify()).Error -} - -// UpdateSecret updates a secret in the database. -// -//nolint:dupl // ignore similar code with create -func (c *client) UpdateSecret(s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": s.GetOrg(), - "repo": s.GetRepo(), - "secret": s.GetName(), - "type": s.GetType(), - } - - // check if secret is a shared secret - if strings.EqualFold(s.GetType(), constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": s.GetOrg(), - "team": s.GetTeam(), - "secret": s.GetName(), - "type": s.GetType(), - } - } - - c.Logger.WithFields(fields).Tracef("updating %s secret %s in the database", s.GetType(), s.GetName()) - - // cast to database type - secret := database.SecretFromLibrary(s) - - // validate the necessary fields are populated - err := secret.Validate() - if err != nil { - return err - } - - // encrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Encrypt - err = secret.Encrypt(c.config.EncryptionKey) - if err != nil { - return fmt.Errorf("unable to encrypt secret %s: %w", s.GetName(), err) - } - - // send query to the database - return c.Sqlite. - Table(constants.TableSecret). - Save(secret.Nullify()).Error -} - -// DeleteSecret deletes a secret by unique ID from the database. -func (c *client) DeleteSecret(id int64) error { - c.Logger.Tracef("Deleting secret %d from the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableSecret). - Exec(dml.DeleteSecret, id).Error -} diff --git a/database/sqlite/secret_count.go b/database/sqlite/secret_count.go deleted file mode 100644 index cca5fb6b8..000000000 --- a/database/sqlite/secret_count.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" -) - -// GetTypeSecretCount gets a count of secrets by type, -// owner, and name (repo or team) from the database. -func (c *client) GetTypeSecretCount(t, o, n string, teams []string) (int64, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("getting count of %s secrets for %s/%s from the database", t, o, n) - - var err error - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectOrgSecretsCount, o). - Pluck("count", &s).Error - case constants.SecretRepo: - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectRepoSecretsCount, o, n). - Pluck("count", &s).Error - case constants.SecretShared: - if n == "*" { - // GitHub teams are not case-sensitive, the DB is lowercase everything for matching - var lowerTeams []string - for _, t := range teams { - lowerTeams = append(lowerTeams, strings.ToLower(t)) - } - - err = c.Sqlite. - Table(constants.TableSecret). - Select("count(*)"). - Where("type = 'shared' AND org = ?", o). - Where("LOWER(team) IN (?)", lowerTeams). - Pluck("count", &s).Error - } else { - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.SelectSharedSecretsCount, o, n). - Pluck("count", &s).Error - } - } - - return s, err -} diff --git a/database/sqlite/secret_count_test.go b/database/sqlite/secret_count_test.go deleted file mode 100644 index 56039d5d8..000000000 --- a/database/sqlite/secret_count_test.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the secret table - err = _database.Sqlite.Exec(ddl.CreateSecretTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableSecret, err) - } -} - -func TestSqlite_Client_GetTypeSecretCount_Org(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("*") - _secretOne.SetName("baz") - _secretOne.SetValue("bar") - _secretOne.SetType("org") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("*") - _secretTwo.SetName("bar") - _secretTwo.SetValue("baz") - _secretTwo.SetType("org") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secrets in the database - err := _database.CreateSecret(_secretOne) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.CreateSecret(_secretTwo) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - got, err := _database.GetTypeSecretCount("org", "foo", "*", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretCount_Repo(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secrets in the database - err := _database.CreateSecret(_secretOne) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.CreateSecret(_secretTwo) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - got, err := _database.GetTypeSecretCount("repo", "foo", "bar", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretCount_Shared(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secrets in the database - err := _database.CreateSecret(_secretOne) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.CreateSecret(_secretTwo) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - got, err := _database.GetTypeSecretCount("shared", "foo", "bar", []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretCount_Shared_Wildcard(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetCreatedBy("user") - _secretOne.SetUpdatedAt(1) - _secretOne.SetUpdatedBy("user2") - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bared") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetCreatedBy("user") - _secretTwo.SetUpdatedAt(1) - _secretTwo.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secrets in the database - err := _database.CreateSecret(_secretOne) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.CreateSecret(_secretTwo) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - got, err := _database.GetTypeSecretCount("shared", "foo", "*", []string{"bar", "bared"}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/secret_list.go b/database/sqlite/secret_list.go deleted file mode 100644 index 7fdfb6e1e..000000000 --- a/database/sqlite/secret_list.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "strings" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" -) - -// GetSecretList gets a list of all secrets from the database. -func (c *client) GetSecretList() ([]*library.Secret, error) { - c.Logger.Tracef("listing secrets from the database") - - // variable to store query results - s := new([]database.Secret) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableSecret). - Raw(dml.ListSecrets). - Scan(s).Error - if err != nil { - return nil, err - } - - // variable we want to return - secrets := []*library.Secret{} - // iterate through all query results - for _, secret := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := secret - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - secrets = append(secrets, tmp.ToLibrary()) - } - - return secrets, nil -} - -// GetTypeSecretList gets a list of secrets by type, -// owner, and name (repo or team) from the database. -func (c *client) GetTypeSecretList(t, o, n string, page, perPage int, teams []string) ([]*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": o, - "repo": n, - "type": t, - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": o, - "team": n, - "type": t, - } - } - - c.Logger.WithFields(fields).Tracef("listing %s secrets for %s/%s from the database", t, o, n) - - var err error - - // variable to store query results - s := new([]database.Secret) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - switch t { - case constants.SecretOrg: - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.ListOrgSecrets, o, perPage, offset). - Scan(s).Error - case constants.SecretRepo: - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.ListRepoSecrets, o, n, perPage, offset). - Scan(s).Error - case constants.SecretShared: - if n == "*" { - // GitHub teams are not case-sensitive, the DB is lowercase everything for matching - var lowerTeams []string - for _, t := range teams { - lowerTeams = append(lowerTeams, strings.ToLower(t)) - } - - err = c.Sqlite. - Table(constants.TableSecret). - Where("type = 'shared' AND org = ?", o). - Where("LOWER(team) IN (?)", lowerTeams). - Order("id DESC"). - Limit(perPage). - Offset(offset). - Scan(s).Error - } else { - err = c.Sqlite. - Table(constants.TableSecret). - Raw(dml.ListSharedSecrets, o, n, perPage, offset). - Scan(s).Error - } - } - - if err != nil { - return nil, err - } - - // variable we want to return - secrets := []*library.Secret{} - // iterate through all query results - for _, secret := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := secret - - // decrypt the value for the secret - // - // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Decrypt - err = tmp.Decrypt(c.config.EncryptionKey) - if err != nil { - // ensures that the change is backwards compatible - // by logging the error instead of returning it - // which allows us to fetch unencrypted secrets - c.Logger.Errorf("unable to decrypt secret %d: %v", tmp.ID.Int64, err) - } - - // convert query result to library type - secrets = append(secrets, tmp.ToLibrary()) - } - - return secrets, nil -} diff --git a/database/sqlite/secret_list_test.go b/database/sqlite/secret_list_test.go deleted file mode 100644 index a4bb354ee..000000000 --- a/database/sqlite/secret_list_test.go +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the secret table - err = _database.Sqlite.Exec(ddl.CreateSecretTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableSecret, err) - } -} - -func TestSqlite_Client_GetSecretList(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - _secretOne.SetCreatedAt(1) - _secretOne.SetUpdatedAt(1) - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetUpdatedAt(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretOne, _secretTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - for _, secret := range test.want { - // create the secret in the database - err := _database.CreateSecret(secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetSecretList() - - if test.failure { - if err == nil { - t.Errorf("GetSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecretList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretList_Org(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("*") - _secretOne.SetName("baz") - _secretOne.SetValue("bar") - _secretOne.SetType("org") - _secretOne.SetCreatedAt(1) - _secretOne.SetUpdatedAt(1) - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("*") - _secretTwo.SetName("bar") - _secretTwo.SetValue("baz") - _secretTwo.SetType("org") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetUpdatedAt(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretTwo, _secretOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - for _, secret := range test.want { - // create the secret in the database - err := _database.CreateSecret(secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetTypeSecretList("org", "foo", "*", 1, 10, []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretList_Repo(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetRepo("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("repo") - _secretOne.SetCreatedAt(1) - _secretOne.SetUpdatedAt(1) - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetRepo("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("repo") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetUpdatedAt(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretTwo, _secretOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - for _, secret := range test.want { - // create the secret in the database - err := _database.CreateSecret(secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetTypeSecretList("repo", "foo", "bar", 1, 10, []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretList_Shared(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetUpdatedAt(1) - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bar") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetUpdatedAt(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretTwo, _secretOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - for _, secret := range test.want { - // create the secret in the database - err := _database.CreateSecret(secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetTypeSecretList("shared", "foo", "bar", 1, 10, []string{}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetTypeSecretList_Shared_wildcard(t *testing.T) { - // setup types - _secretOne := testSecret() - _secretOne.SetID(1) - _secretOne.SetOrg("foo") - _secretOne.SetTeam("bar") - _secretOne.SetName("baz") - _secretOne.SetValue("foob") - _secretOne.SetType("shared") - _secretOne.SetCreatedAt(1) - _secretOne.SetUpdatedAt(1) - - _secretTwo := testSecret() - _secretTwo.SetID(2) - _secretTwo.SetOrg("foo") - _secretTwo.SetTeam("bared") - _secretTwo.SetName("foob") - _secretTwo.SetValue("baz") - _secretTwo.SetType("shared") - _secretTwo.SetCreatedAt(1) - _secretTwo.SetUpdatedAt(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Secret - }{ - { - failure: false, - want: []*library.Secret{_secretTwo, _secretOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - for _, secret := range test.want { - // create the secret in the database - err := _database.CreateSecret(secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetTypeSecretList("shared", "foo", "*", 1, 10, []string{"bar", "bared"}) - - if test.failure { - if err == nil { - t.Errorf("GetTypeSecretList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetTypeSecretList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetTypeSecretList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/secret_test.go b/database/sqlite/secret_test.go deleted file mode 100644 index 74dacd850..000000000 --- a/database/sqlite/secret_test.go +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetSecret_Org(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("*") - _secret.SetName("bar") - _secret.SetValue("baz") - _secret.SetType("org") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the secret in the database - err := _database.CreateSecret(test.want) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetSecret("org", "foo", "*", "bar") - - // cleanup the secrets table - _ = _database.Sqlite.Exec("DELETE FROM secrets;") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetSecret_Repo(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the secret in the database - err := _database.CreateSecret(test.want) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetSecret("repo", "foo", "bar", "baz") - - // cleanup the secrets table - _ = _database.Sqlite.Exec("DELETE FROM secrets;") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetSecret_Shared(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetTeam("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("shared") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Secret - }{ - { - failure: false, - want: _secret, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the secret in the database - err := _database.CreateSecret(test.want) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - } - - got, err := _database.GetSecret("shared", "foo", "bar", "baz") - - // cleanup the secrets table - _ = _database.Sqlite.Exec("DELETE FROM secrets;") - - if test.failure { - if err == nil { - t.Errorf("GetSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetSecret returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetSecret is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateSecret(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - err := _database.CreateSecret(_secret) - - if test.failure { - if err == nil { - t.Errorf("CreateSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateSecret returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateSecret(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secret in the database - err := _database.CreateSecret(_secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.UpdateSecret(_secret) - - if test.failure { - if err == nil { - t.Errorf("UpdateSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateSecret returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteSecret(t *testing.T) { - // setup types - _secret := testSecret() - _secret.SetID(1) - _secret.SetOrg("foo") - _secret.SetRepo("bar") - _secret.SetName("baz") - _secret.SetValue("foob") - _secret.SetType("repo") - _secret.SetCreatedAt(1) - _secret.SetCreatedBy("user") - _secret.SetUpdatedAt(1) - _secret.SetUpdatedBy("user2") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the secrets table - defer _database.Sqlite.Exec("delete from secrets;") - - // create the secret in the database - err := _database.CreateSecret(_secret) - if err != nil { - t.Errorf("unable to create test secret: %v", err) - } - - err = _database.DeleteSecret(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteSecret should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteSecret returned err: %v", err) - } - } -} - -// testSecret is a test helper function to create a -// library Secret type with all fields set to their -// zero values. -func testSecret() *library.Secret { - i64 := int64(0) - str := "" - booL := false - - var arr []string - - return &library.Secret{ - ID: &i64, - Org: &str, - Repo: &str, - Team: &str, - Name: &str, - Value: &str, - Type: &str, - Images: &arr, - Events: &arr, - AllowCommand: &booL, - CreatedAt: &i64, - CreatedBy: &str, - UpdatedAt: &i64, - UpdatedBy: &str, - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 5018e8548..87645f323 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -12,6 +12,7 @@ import ( "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" @@ -54,6 +55,8 @@ type ( pipeline.PipelineService // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService repo.RepoService + // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService + secret.SecretService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService @@ -239,12 +242,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the secrets table - err = c.Sqlite.Exec(ddl.CreateSecretTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableSecret, err) - } - // create the services table err = c.Sqlite.Exec(ddl.CreateServiceTable).Error if err != nil { @@ -289,24 +286,6 @@ func createIndexes(c *client) error { return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) } - // create the secrets_type_org_repo index for the secrets table - err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgRepo).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org_repo index for the %s table: %w", constants.TableSecret, err) - } - - // create the secrets_type_org_team index for the secrets table - err = c.Sqlite.Exec(ddl.CreateSecretTypeOrgTeam).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org_team index for the %s table: %w", constants.TableSecret, err) - } - - // create the secrets_type_org index for the secrets table - err = c.Sqlite.Exec(ddl.CreateSecretTypeOrg).Error - if err != nil { - return fmt.Errorf("unable to create secrets_type_org index for the %s table: %w", constants.TableSecret, err) - } - return nil } @@ -365,6 +344,19 @@ func createServices(c *client) error { return err } + // create the database agnostic secret service + // + // https://pkg.go.dev/github.com/go-vela/server/database/secret#New + c.SecretService, err = secret.New( + secret.WithClient(c.Sqlite), + secret.WithEncryptionKey(c.config.EncryptionKey), + secret.WithLogger(c.Logger), + secret.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/secret/native/count.go b/secret/native/count.go index d534cb268..2460d998a 100644 --- a/secret/native/count.go +++ b/secret/native/count.go @@ -5,38 +5,62 @@ package native import ( - "strings" + "fmt" "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // Count counts a list of secrets. func (c *client) Count(sType, org, name string, teams []string) (int64, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "type": sType, - } + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "type": sType, + }).Tracef("counting native %s secrets for %s", sType, org) - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ + // capture the count of org secrets from the native service + return c.Database.CountSecretsForOrg(org, nil) + case constants.SecretRepo: + c.Logger.WithFields(logrus.Fields{ "org": org, - "team": name, + "repo": name, "type": sType, + }).Tracef("counting native %s secrets for %s/%s", sType, org, name) + + // create the repo with the information available + r := new(library.Repo) + r.SetOrg(org) + r.SetName(name) + r.SetFullName(fmt.Sprintf("%s/%s", org, name)) + + // capture the count of repo secrets from the native service + return c.Database.CountSecretsForRepo(r, nil) + case constants.SecretShared: + // check if we should capture secrets for multiple teams + if name == "*" { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "teams": teams, + "type": sType, + }).Tracef("counting native %s secrets for teams %s in org %s", sType, teams, org) + + // capture the count of shared secrets for multiple teams from the native service + return c.Database.CountSecretsForTeams(org, teams, nil) } - } - c.Logger.WithFields(fields).Tracef("counting native %s secrets for %s/%s", sType, org, name) + c.Logger.WithFields(logrus.Fields{ + "org": org, + "team": name, + "type": sType, + }).Tracef("counting native %s secrets for %s/%s", sType, org, name) - // capture the count of secrets from the native service - s, err := c.Database.GetTypeSecretCount(sType, org, name, teams) - if err != nil { - return 0, err + // capture the count of shared secrets from the native service + return c.Database.CountSecretsForTeam(org, name, nil) + default: + return 0, fmt.Errorf("invalid secret type: %s", sType) } - - return s, nil } diff --git a/secret/native/create.go b/secret/native/create.go index 5c2cdfe7d..6b6c90512 100644 --- a/secret/native/create.go +++ b/secret/native/create.go @@ -6,46 +6,46 @@ package native import ( "fmt" - "strings" - - "github.com/sirupsen/logrus" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" ) // Create creates a new secret. func (c *client) Create(sType, org, name string, s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "secret": s.GetName(), - "type": sType, - } - - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ "org": org, - "team": name, "secret": s.GetName(), "type": sType, - } - } + }).Tracef("creating native %s secret %s for %s", sType, s.GetName(), org) - c.Logger.WithFields(fields).Tracef("creating native %s secret %s for %s/%s", sType, s.GetName(), org, name) - - // create the secret for the native service - switch sType { - case constants.SecretOrg: - fallthrough + // create the org secret in the native service + return c.Database.CreateSecret(s) case constants.SecretRepo: - fallthrough + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + "secret": s.GetName(), + "type": sType, + }).Tracef("creating native %s secret %s for %s/%s", sType, s.GetName(), org, name) + + // create the repo secret in the native service + return c.Database.CreateSecret(s) case constants.SecretShared: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "secret": s.GetName(), + "team": name, + "type": sType, + }).Tracef("creating native %s secret %s for %s/%s", sType, s.GetName(), org, name) + + // create the shared secret in the native service return c.Database.CreateSecret(s) default: - return fmt.Errorf("invalid secret type: %v", sType) + return fmt.Errorf("invalid secret type: %s", sType) } } diff --git a/secret/native/delete.go b/secret/native/delete.go index 380e4bf65..c414296ca 100644 --- a/secret/native/delete.go +++ b/secret/native/delete.go @@ -5,7 +5,7 @@ package native import ( - "strings" + "fmt" "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" @@ -13,33 +13,44 @@ import ( // Delete deletes a secret. func (c *client) Delete(sType, org, name, path string) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "secret": path, - "type": sType, + // capture the secret from the native service + s, err := c.Get(sType, org, name, path) + if err != nil { + return err } - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ "org": org, - "team": name, "secret": path, "type": sType, - } - } + }).Tracef("deleting native %s secret %s for %s", sType, path, org) - c.Logger.WithFields(fields).Tracef("deleting native %s secret %s for %s/%s", sType, path, org, name) + // delete the org secret from the native service + return c.Database.DeleteSecret(s) + case constants.SecretRepo: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + "secret": path, + "type": sType, + }).Tracef("deleting native %s secret %s for %s/%s", sType, path, org, name) - // capture the secret from the native service - s, err := c.Database.GetSecret(sType, org, name, path) - if err != nil { - return err - } + // delete the repo secret from the native service + return c.Database.DeleteSecret(s) + case constants.SecretShared: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "secret": path, + "team": name, + "type": sType, + }).Tracef("deleting native %s secret %s for %s/%s", sType, path, org, name) - // delete the secret from the native service - return c.Database.DeleteSecret(s.GetID()) + // delete the shared secret from the native service + return c.Database.DeleteSecret(s) + default: + return fmt.Errorf("invalid secret type: %s", sType) + } } diff --git a/secret/native/get.go b/secret/native/get.go index 087679a0d..9ed322355 100644 --- a/secret/native/get.go +++ b/secret/native/get.go @@ -5,7 +5,7 @@ package native import ( - "strings" + "fmt" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -14,32 +14,44 @@ import ( // Get captures a secret. func (c *client) Get(sType, org, name, path string) (*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "secret": path, - "type": sType, - } - - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ "org": org, - "team": name, "secret": path, "type": sType, - } - } + }).Tracef("getting native %s secret %s for %s", sType, path, org) - c.Logger.WithFields(fields).Tracef("getting native %s secret %s for %s/%s", sType, path, org, name) + // capture the org secret from the native service + return c.Database.GetSecretForOrg(org, path) + case constants.SecretRepo: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + "secret": path, + "type": sType, + }).Tracef("getting native %s secret %s for %s/%s", sType, path, org, name) + + // create the repo with the information available + r := new(library.Repo) + r.SetOrg(org) + r.SetName(name) + r.SetFullName(fmt.Sprintf("%s/%s", org, name)) + + // capture the repo secret from the native service + return c.Database.GetSecretForRepo(path, r) + case constants.SecretShared: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "secret": path, + "team": name, + "type": sType, + }).Tracef("getting native %s secret %s for %s/%s", sType, path, org, name) - // capture the secret from the native service - s, err := c.Database.GetSecret(sType, org, name, path) - if err != nil { - return nil, err + // capture the shared secret from the native service + return c.Database.GetSecretForTeam(org, name, path) + default: + return nil, fmt.Errorf("invalid secret type: %s", sType) } - - return s, nil } diff --git a/secret/native/list.go b/secret/native/list.go index 3b92f9462..0bd9ab303 100644 --- a/secret/native/list.go +++ b/secret/native/list.go @@ -5,7 +5,7 @@ package native import ( - "strings" + "fmt" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -14,30 +14,73 @@ import ( // List captures a list of secrets. func (c *client) List(sType, org, name string, page, perPage int, teams []string) ([]*library.Secret, error) { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "type": sType, - } + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "type": sType, + }).Tracef("listing native %s secrets for %s", sType, org) + + // capture the list of org secrets from the native service + secrets, _, err := c.Database.ListSecretsForOrg(org, nil, page, perPage) + if err != nil { + return nil, err + } - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ + return secrets, nil + case constants.SecretRepo: + c.Logger.WithFields(logrus.Fields{ "org": org, - "team": name, + "repo": name, "type": sType, + }).Tracef("listing native %s secrets for %s/%s", sType, org, name) + + // create the repo with the information available + r := new(library.Repo) + r.SetOrg(org) + r.SetName(name) + r.SetFullName(fmt.Sprintf("%s/%s", org, name)) + + // capture the list of repo secrets from the native service + secrets, _, err := c.Database.ListSecretsForRepo(r, nil, page, perPage) + if err != nil { + return nil, err } - } - c.Logger.WithFields(fields).Tracef("listing native %s secrets for %s/%s", sType, org, name) + return secrets, nil + case constants.SecretShared: + // check if we should capture secrets for multiple teams + if name == "*" { + c.Logger.WithFields(logrus.Fields{ + "org": org, + "teams": teams, + "type": sType, + }).Tracef("listing native %s secrets for teams %s in org %s", sType, teams, org) - // capture the list of secrets from the native service - s, err := c.Database.GetTypeSecretList(sType, org, name, page, perPage, teams) - if err != nil { - return nil, err - } + // capture the list of shared secrets for multiple teams from the native service + secrets, _, err := c.Database.ListSecretsForTeams(org, teams, nil, page, perPage) + if err != nil { + return nil, err + } - return s, nil + return secrets, nil + } + + c.Logger.WithFields(logrus.Fields{ + "org": org, + "team": name, + "type": sType, + }).Tracef("listing native %s secrets for %s/%s", sType, org, name) + + // capture the list of shared secrets from the native service + secrets, _, err := c.Database.ListSecretsForTeam(org, name, nil, page, perPage) + if err != nil { + return nil, err + } + + return secrets, nil + default: + return nil, fmt.Errorf("invalid secret type: %s", sType) + } } diff --git a/secret/native/update.go b/secret/native/update.go index 04f136800..ceda7e842 100644 --- a/secret/native/update.go +++ b/secret/native/update.go @@ -5,7 +5,7 @@ package native import ( - "strings" + "fmt" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -14,58 +14,70 @@ import ( // Update updates an existing secret. func (c *client) Update(sType, org, name string, s *library.Secret) error { - // create log fields from secret metadata - fields := logrus.Fields{ - "org": org, - "repo": name, - "secret": s.GetName(), - "type": sType, - } - - // check if secret is a shared secret - if strings.EqualFold(sType, constants.SecretShared) { - // update log fields from secret metadata - fields = logrus.Fields{ - "org": org, - "team": name, - "secret": s.GetName(), - "type": sType, - } - } - - c.Logger.WithFields(fields).Tracef("updating native %s secret %s for %s/%s", sType, s.GetName(), org, name) - // capture the secret from the native service - sec, err := c.Database.GetSecret(sType, org, name, s.GetName()) + secret, err := c.Get(sType, org, name, s.GetName()) if err != nil { return err } // update the events if set if len(s.GetEvents()) > 0 { - sec.SetEvents(s.GetEvents()) + secret.SetEvents(s.GetEvents()) } // update the images if set if s.Images != nil { - sec.SetImages(s.GetImages()) + secret.SetImages(s.GetImages()) } // update the value if set if len(s.GetValue()) > 0 { - sec.SetValue(s.GetValue()) + secret.SetValue(s.GetValue()) } // update allow_command if set if s.AllowCommand != nil { - sec.SetAllowCommand(s.GetAllowCommand()) + secret.SetAllowCommand(s.GetAllowCommand()) } // update updated_at if set - sec.SetUpdatedAt(s.GetUpdatedAt()) + secret.SetUpdatedAt(s.GetUpdatedAt()) // update updated_by if set - sec.SetUpdatedBy(s.GetUpdatedBy()) + secret.SetUpdatedBy(s.GetUpdatedBy()) - return c.Database.UpdateSecret(sec) + // handle the secret based off the type + switch sType { + case constants.SecretOrg: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "secret": s.GetName(), + "type": sType, + }).Tracef("updating native %s secret %s for %s", sType, s.GetName(), org) + + // update the org secret in the native service + return c.Database.UpdateSecret(secret) + case constants.SecretRepo: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "repo": name, + "secret": s.GetName(), + "type": sType, + }).Tracef("updating native %s secret %s for %s/%s", sType, s.GetName(), org, name) + + // update the repo secret in the native service + return c.Database.UpdateSecret(secret) + case constants.SecretShared: + c.Logger.WithFields(logrus.Fields{ + "org": org, + "team": name, + "secret": s.GetName(), + "type": sType, + }).Tracef("updating native %s secret %s for %s/%s", sType, s.GetName(), org, name) + + // update the shared secret in the native service + return c.Database.UpdateSecret(secret) + default: + return fmt.Errorf("invalid secret type: %s", sType) + } } From 931e938a5f889a36e6a4ac0d990397cab9a1666e Mon Sep 17 00:00:00 2001 From: David May <49894298+wass3rw3rk@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:02:59 -0500 Subject: [PATCH 196/298] fix(jwt): set issued_at to nil prior to validating claims (#814) --- internal/token/parse.go | 4 ++++ internal/token/parse_test.go | 6 +++--- router/middleware/claims/claims_test.go | 10 +++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/internal/token/parse.go b/internal/token/parse.go index dc9b002d3..4cae4e986 100644 --- a/internal/token/parse.go +++ b/internal/token/parse.go @@ -34,6 +34,10 @@ func (tm *Manager) ParseToken(token string) (*Claims, error) { claims = t.Claims.(*Claims) name := claims.Subject + // according to JWT, the iat field is optional for security purposes and is purely informational. + // setting it to nil avoids any worries of race conditions. + claims.IssuedAt = nil + // check if subject has a value in claims; // we can save a db lookup attempt if len(name) == 0 { diff --git a/internal/token/parse_test.go b/internal/token/parse_test.go index 9ee9ce453..6c9076515 100644 --- a/internal/token/parse_test.go +++ b/internal/token/parse_test.go @@ -51,7 +51,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.UserAccessTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: u.GetName(), - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), }, }, @@ -69,7 +69,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.UserRefreshTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: u.GetName(), - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 30)), }, }, @@ -89,7 +89,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.WorkerBuildTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "worker", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 90)), }, }, diff --git a/router/middleware/claims/claims_test.go b/router/middleware/claims/claims_test.go index 914c5882e..8447ff009 100644 --- a/router/middleware/claims/claims_test.go +++ b/router/middleware/claims/claims_test.go @@ -33,7 +33,7 @@ func TestClaims_Retrieve(t *testing.T) { IsActive: true, RegisteredClaims: jwt.RegisteredClaims{ Subject: "octocat", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 1)), }, } @@ -90,7 +90,7 @@ func TestClaims_Establish(t *testing.T) { IsActive: true, RegisteredClaims: jwt.RegisteredClaims{ Subject: "foo", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), }, }, @@ -110,7 +110,7 @@ func TestClaims_Establish(t *testing.T) { Repo: "foo/bar", RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 35)), }, }, @@ -130,7 +130,7 @@ func TestClaims_Establish(t *testing.T) { TokenType: constants.WorkerAuthTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerAuthTokenDuration)), }, }, @@ -148,7 +148,7 @@ func TestClaims_Establish(t *testing.T) { TokenType: constants.WorkerRegisterTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: jwt.NewNumericDate(now), + IssuedAt: nil, ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerRegisterTokenDuration)), }, }, From 4a275f635b216022078d25674869d0d6c1d2607a Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:03:43 -0600 Subject: [PATCH 197/298] feat(templates): allow for compile-time rulesets for template steps (#720) Co-authored-by: Jacob Floyd --- compiler/engine.go | 4 ++-- compiler/native/compile.go | 8 +++---- compiler/native/expand.go | 23 +++++++++++++++++--- compiler/native/expand_test.go | 38 ++++++++++++++++++++++++++++++---- 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/compiler/engine.go b/compiler/engine.go index 9addf7a79..f2ff2a33e 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -71,10 +71,10 @@ type Engine interface { // ExpandStages defines a function that injects the template // for each templated step in every stage in a yaml configuration. - ExpandStages(*yaml.Build, map[string]*yaml.Template) (*yaml.Build, error) + ExpandStages(*yaml.Build, map[string]*yaml.Template, *pipeline.RuleData) (*yaml.Build, error) // ExpandSteps defines a function that injects the template // for each templated step in a yaml configuration. - ExpandSteps(*yaml.Build, map[string]*yaml.Template) (*yaml.Build, error) + ExpandSteps(*yaml.Build, map[string]*yaml.Template, *pipeline.RuleData) (*yaml.Build, error) // Init Compiler Interface Functions diff --git a/compiler/native/compile.go b/compiler/native/compile.go index 4b80e3365..a36ddc113 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -155,7 +155,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp switch { case len(p.Stages) > 0: // inject the templates into the steps - p, err = c.ExpandStages(p, templates) + p, err = c.ExpandStages(p, templates, nil) if err != nil { return nil, _pipeline, err } @@ -169,7 +169,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp } case len(p.Steps) > 0: // inject the templates into the steps - p, err = c.ExpandSteps(p, templates) + p, err = c.ExpandSteps(p, templates, nil) if err != nil { return nil, _pipeline, err } @@ -307,7 +307,7 @@ func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls } // inject the templates into the steps - p, err = c.ExpandSteps(p, tmpls) + p, err = c.ExpandSteps(p, tmpls, r) if err != nil { return nil, _pipeline, err } @@ -404,7 +404,7 @@ func (c *client) compileStages(p *yaml.Build, _pipeline *library.Pipeline, tmpls } // inject the templates into the stages - p, err = c.ExpandStages(p, tmpls) + p, err = c.ExpandStages(p, tmpls, r) if err != nil { return nil, _pipeline, err } diff --git a/compiler/native/expand.go b/compiler/native/expand.go index e17d03161..4256de7e8 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/go-vela/types/constants" + "github.com/go-vela/types/pipeline" "github.com/go-vela/server/compiler/registry" "github.com/go-vela/server/compiler/template/native" @@ -22,7 +23,7 @@ import ( // ExpandStages injects the template for each // templated step in every stage in a yaml configuration. -func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (*yaml.Build, error) { +func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*yaml.Build, error) { if len(tmpls) == 0 { return s, nil } @@ -30,7 +31,7 @@ func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (* // iterate through all stages for _, stage := range s.Stages { // inject the templates into the steps for the stage - p, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls) + p, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls, r) if err != nil { return nil, err } @@ -46,7 +47,7 @@ func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template) (* // ExpandSteps injects the template for each // templated step in a yaml configuration. -func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (*yaml.Build, error) { +func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*yaml.Build, error) { if len(tmpls) == 0 { return s, nil } @@ -75,6 +76,22 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template) (*y return s, fmt.Errorf("missing template source for template %s in pipeline for step %s", step.Template.Name, step.Name) } + // if ruledata is nil (CompileLite), continue with expansion + if r != nil { + // form a one-step pipeline to prep for purge check + check := &yaml.StepSlice{step} + pipeline := &pipeline.Build{ + Steps: *check.ToPipeline(), + } + + pipeline = pipeline.Purge(r) + + // if step purged, do not proceed with expansion + if len(pipeline.Steps) == 0 { + continue + } + } + // Create some default global environment inject vars // these are used below to overwrite to an empty // map if they should not be injected into a container diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index ae3fc32b7..a8c232a71 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" "github.com/go-vela/types/raw" "github.com/go-vela/types/yaml" "github.com/google/go-cmp/cmp" @@ -145,7 +146,7 @@ func TestNative_ExpandStages(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - build, err := compiler.ExpandStages(&yaml.Build{Stages: stages, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + build, err := compiler.ExpandStages(&yaml.Build{Stages: stages, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, new(pipeline.RuleData)) if err != nil { t.Errorf("ExpandStages returned err: %v", err) } @@ -321,7 +322,7 @@ func TestNative_ExpandSteps(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData)) if err != nil { t.Errorf("ExpandSteps_Type%s returned err: %v", test.name, err) } @@ -385,6 +386,11 @@ func TestNative_ExpandStepsMulti(t *testing.T) { Source: "github.example.com/bar/foo/maven.yml", Type: "github", }, + "npm": { + Name: "npm", + Source: "github.example.com/foo/bar/gradle.yml", + Type: "github", + }, } steps := yaml.StepSlice{ @@ -409,6 +415,27 @@ func TestNative_ExpandStepsMulti(t *testing.T) { "pull_policy": "pull: true", }, }, + Ruleset: yaml.Ruleset{ + If: yaml.Rules{ + Branch: []string{"main"}, + }, + }, + }, + &yaml.Step{ + Name: "sample", + Template: yaml.StepTemplate{ + Name: "npm", + Variables: map[string]interface{}{ + "image": "openjdk:latest", + "environment": "{ GRADLE_USER_HOME: .gradle, GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=1 -Dorg.gradle.parallel=false }", + "pull_policy": "pull: true", + }, + }, + Ruleset: yaml.Ruleset{ + If: yaml.Rules{ + Branch: []string{"dev"}, + }, + }, }, } @@ -557,7 +584,10 @@ func TestNative_ExpandStepsMulti(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + ruledata := new(pipeline.RuleData) + ruledata.Branch = "main" + + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, ruledata) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } @@ -644,7 +674,7 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, new(pipeline.RuleData)) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } From 116ea3b1a078a9cc2a6d8990bdb35d660eb15a96 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 13 Apr 2023 14:20:23 -0600 Subject: [PATCH 198/298] fix(metrics/spec): add queued_build_count to spec (#815) --- api/metrics.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/metrics.go b/api/metrics.go index cf059d324..14a277be6 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -121,6 +121,11 @@ var ( // type: boolean // default: false // - in: query +// name: queued_build_count +// description: Indicates a request for queued build count +// type: boolean +// default: false +// - in: query // name: failure_build_count // description: Indicates a request for failure build count // type: boolean From 05371c1b760d5a4485013f992095deb1fe48b0dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 10:13:47 -0500 Subject: [PATCH 199/298] fix(deps): update go.starlark.net digest to 4b1e35f (#778) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 01e869534..b7e3765ea 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 github.com/urfave/cli/v2 v2.24.4 - go.starlark.net v0.0.0-20230228032650-dded03209ead + go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 golang.org/x/oauth2 v0.5.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 diff --git a/go.sum b/go.sum index 9b8e2d8a7..cdb1e7d1e 100644 --- a/go.sum +++ b/go.sum @@ -446,8 +446,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.starlark.net v0.0.0-20230228032650-dded03209ead h1:qZOFk6/3JiKg5gjRTf4lShf/N0K3acJ95Bg70LsgnHI= -go.starlark.net v0.0.0-20230228032650-dded03209ead/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg= +go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From f37d973383d18546ea3b3f662980272a7284f56c Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 17 Apr 2023 10:38:39 -0500 Subject: [PATCH 200/298] refactor(database): move step logic into separate package (#810) * feat(database): add step engine * chore(database): remove old step logic * chore: updates for database step engine --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- api/build.go | 2 +- api/metrics.go | 4 +- api/step.go | 22 +-- database/postgres/ddl/step.go | 33 ---- database/postgres/dml/step.go | 67 ------- database/postgres/postgres.go | 23 ++- database/postgres/postgres_test.go | 7 +- database/postgres/step.go | 94 ---------- database/postgres/step_count.go | 90 --------- database/postgres/step_count_test.go | 194 ------------------- database/postgres/step_list.go | 71 ------- database/postgres/step_list_test.go | 168 ----------------- database/postgres/step_test.go | 268 --------------------------- database/service.go | 35 +--- database/sqlite/ddl/step.go | 33 ---- database/sqlite/dml/step.go | 67 ------- database/sqlite/sqlite.go | 21 ++- database/sqlite/step.go | 94 ---------- database/sqlite/step_count.go | 90 --------- database/sqlite/step_count_test.go | 198 -------------------- database/sqlite/step_list.go | 71 ------- database/sqlite/step_list_test.go | 174 ----------------- database/sqlite/step_test.go | 267 -------------------------- database/step/count.go | 25 +++ database/step/count_build.go | 31 ++++ database/step/count_build_test.go | 104 +++++++++++ database/step/count_test.go | 97 ++++++++++ database/step/create.go | 38 ++++ database/step/create_test.go | 75 ++++++++ database/step/delete.go | 30 +++ database/step/delete_test.go | 75 ++++++++ database/step/get.go | 34 ++++ database/step/get_build.go | 39 ++++ database/step/get_build_test.go | 92 +++++++++ database/step/get_test.go | 87 +++++++++ database/step/list.go | 54 ++++++ database/step/list_build.go | 65 +++++++ database/step/list_build_test.go | 114 ++++++++++++ database/step/list_image.go | 44 +++++ database/step/list_image_test.go | 97 ++++++++++ database/step/list_status.go | 50 +++++ database/step/list_status_test.go | 114 ++++++++++++ database/step/list_test.go | 107 +++++++++++ database/step/opts.go | 44 +++++ database/step/opts_test.go | 161 ++++++++++++++++ database/step/service.go | 49 +++++ database/step/step.go | 74 ++++++++ database/step/step_test.go | 225 ++++++++++++++++++++++ database/step/table.go | 78 ++++++++ database/step/table_test.go | 59 ++++++ database/step/update.go | 38 ++++ database/step/update_test.go | 77 ++++++++ router/middleware/step/step.go | 2 +- 53 files changed, 2228 insertions(+), 2044 deletions(-) delete mode 100644 database/postgres/ddl/step.go delete mode 100644 database/postgres/dml/step.go delete mode 100644 database/postgres/step.go delete mode 100644 database/postgres/step_count.go delete mode 100644 database/postgres/step_count_test.go delete mode 100644 database/postgres/step_list.go delete mode 100644 database/postgres/step_list_test.go delete mode 100644 database/postgres/step_test.go delete mode 100644 database/sqlite/ddl/step.go delete mode 100644 database/sqlite/dml/step.go delete mode 100644 database/sqlite/step.go delete mode 100644 database/sqlite/step_count.go delete mode 100644 database/sqlite/step_count_test.go delete mode 100644 database/sqlite/step_list.go delete mode 100644 database/sqlite/step_list_test.go delete mode 100644 database/sqlite/step_test.go create mode 100644 database/step/count.go create mode 100644 database/step/count_build.go create mode 100644 database/step/count_build_test.go create mode 100644 database/step/count_test.go create mode 100644 database/step/create.go create mode 100644 database/step/create_test.go create mode 100644 database/step/delete.go create mode 100644 database/step/delete_test.go create mode 100644 database/step/get.go create mode 100644 database/step/get_build.go create mode 100644 database/step/get_build_test.go create mode 100644 database/step/get_test.go create mode 100644 database/step/list.go create mode 100644 database/step/list_build.go create mode 100644 database/step/list_build_test.go create mode 100644 database/step/list_image.go create mode 100644 database/step/list_image_test.go create mode 100644 database/step/list_status.go create mode 100644 database/step/list_status_test.go create mode 100644 database/step/list_test.go create mode 100644 database/step/opts.go create mode 100644 database/step/opts_test.go create mode 100644 database/step/service.go create mode 100644 database/step/step.go create mode 100644 database/step/step_test.go create mode 100644 database/step/table.go create mode 100644 database/step/table_test.go create mode 100644 database/step/update.go create mode 100644 database/step/update_test.go diff --git a/api/build.go b/api/build.go index 523825a26..94cb83d30 100644 --- a/api/build.go +++ b/api/build.go @@ -1837,7 +1837,7 @@ func CancelBuild(c *gin.Context) { for page > 0 { // retrieve build steps (per page) from the database - stepsPart, err := database.FromContext(c).GetBuildStepList(b, page, perPage) + stepsPart, _, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) if err != nil { retErr := fmt.Errorf("unable to retrieve steps for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/api/metrics.go b/api/metrics.go index 14a277be6..4bdeb044e 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -324,7 +324,7 @@ func recordGauges(c *gin.Context) { // step_image_count if q.StepImageCount { // send API call to capture the total number of step images - stepImageMap, err := database.FromContext(c).GetStepImageCount() + stepImageMap, err := database.FromContext(c).ListStepImageCount() if err != nil { logrus.Errorf("unable to get count of all step images: %v", err) } @@ -337,7 +337,7 @@ func recordGauges(c *gin.Context) { // step_status_count if q.StepStatusCount { // send API call to capture the total number of step statuses - stepStatusMap, err := database.FromContext(c).GetStepStatusCount() + stepStatusMap, err := database.FromContext(c).ListStepStatusCount() if err != nil { logrus.Errorf("unable to get count of all step statuses: %v", err) } diff --git a/api/step.go b/api/step.go index ba7ec6119..465ce89f0 100644 --- a/api/step.go +++ b/api/step.go @@ -127,7 +127,7 @@ func CreateStep(c *gin.Context) { } // send API call to capture the created step - s, _ := database.FromContext(c).GetStep(input.GetNumber(), b) + s, _ := database.FromContext(c).GetStepForBuild(b, input.GetNumber()) c.JSON(http.StatusCreated, s) } @@ -235,18 +235,8 @@ func GetSteps(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) - // send API call to capture the total number of steps for the build - t, err := database.FromContext(c).GetBuildStepCount(b) - if err != nil { - retErr := fmt.Errorf("unable to get steps count for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // send API call to capture the list of steps for the build - s, err := database.FromContext(c).GetBuildStepList(b, page, perPage) + s, t, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get steps for build %s: %w", entry, err) @@ -464,7 +454,7 @@ func UpdateStep(c *gin.Context) { } // send API call to capture the updated step - s, _ = database.FromContext(c).GetStep(s.GetNumber(), b) + s, _ = database.FromContext(c).GetStepForBuild(b, s.GetNumber()) c.JSON(http.StatusOK, s) } @@ -535,7 +525,7 @@ func DeleteStep(c *gin.Context) { }).Infof("deleting step %s", entry) // send API call to remove the step - err := database.FromContext(c).DeleteStep(s.GetID()) + err := database.FromContext(c).DeleteStep(s) if err != nil { retErr := fmt.Errorf("unable to delete step %s: %w", entry, err) @@ -576,7 +566,7 @@ func planSteps(database database.Service, p *pipeline.Build, b *library.Build) ( } // send API call to capture the created step - s, err = database.GetStep(s.GetNumber(), b) + s, err = database.GetStepForBuild(b, s.GetNumber()) if err != nil { return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) } @@ -625,7 +615,7 @@ func planSteps(database database.Service, p *pipeline.Build, b *library.Build) ( } // send API call to capture the created step - s, err = database.GetStep(s.GetNumber(), b) + s, err = database.GetStepForBuild(b, s.GetNumber()) if err != nil { return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) } diff --git a/database/postgres/ddl/step.go b/database/postgres/ddl/step.go deleted file mode 100644 index 8e5540e95..000000000 --- a/database/postgres/ddl/step.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateStepTable represents a query to - // create the steps table for Vela. - CreateStepTable = ` -CREATE TABLE -IF NOT EXISTS -steps ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - name VARCHAR(250), - image VARCHAR(500), - stage VARCHAR(250), - status VARCHAR(250), - error VARCHAR(500), - exit_code INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - host VARCHAR(250), - runtime VARCHAR(250), - distribution VARCHAR(250), - UNIQUE(build_id, number) -); -` -) diff --git a/database/postgres/dml/step.go b/database/postgres/dml/step.go deleted file mode 100644 index 7aa82b29a..000000000 --- a/database/postgres/dml/step.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListSteps represents a query to - // list all steps in the database. - ListSteps = ` -SELECT * -FROM steps; -` - - // ListBuildSteps represents a query to list - // all steps for a build_id in the database. - ListBuildSteps = ` -SELECT * -FROM steps -WHERE build_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectBuildStepsCount represents a query to select - // the count of steps for a build_id in the database. - SelectBuildStepsCount = ` -SELECT count(*) as count -FROM steps -WHERE build_id = ? -` - - // SelectStepImagesCount represents a query to select - // the count of an images appearances in the database. - SelectStepImagesCount = ` -SELECT image, count(image) as count -FROM steps -GROUP BY image; -` - - // SelectStepStatusesCount represents a query to select - // the count of a statuses appearances in the database. - SelectStepStatusesCount = ` -SELECT status, count(status) as count -FROM steps -GROUP BY status; -` - - // SelectBuildStep represents a query to select a - // step for a build_id and number in the database. - SelectBuildStep = ` -SELECT * -FROM steps -WHERE build_id = ? -AND number = ? -LIMIT 1; -` - - // DeleteStep represents a query to - // remove a step from the database. - DeleteStep = ` -DELETE -FROM steps -WHERE id = ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 7aa273a8f..c96883b59 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -15,6 +15,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/secret" + "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" @@ -58,6 +59,8 @@ type ( repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService secret.SecretService + // https://pkg.go.dev/github.com/go-vela/server/database/step#StepService + step.StepService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService @@ -175,6 +178,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the step queries + _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -273,12 +278,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) } - // create the steps table - err = c.Postgres.Exec(ddl.CreateStepTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) - } - return nil } @@ -382,6 +381,18 @@ func createServices(c *client) error { return err } + // create the database agnostic step service + // + // https://pkg.go.dev/github.com/go-vela/server/database/repo#New + c.StepService, err = step.New( + step.WithClient(c.Postgres), + step.WithLogger(c.Logger), + step.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 6db511a83..03c49a7d6 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -16,6 +16,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/secret" + "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" @@ -82,7 +83,6 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the index queries _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -107,6 +107,8 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the step queries + _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -175,7 +177,6 @@ func TestPostgres_createTables(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateStepTable).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool @@ -272,6 +273,8 @@ func TestPostgres_createServices(t *testing.T) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the step queries + _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/postgres/step.go b/database/postgres/step.go deleted file mode 100644 index 5f7ecd50e..000000000 --- a/database/postgres/step.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetStep gets a step by number and build ID from the database. -func (c *client) GetStep(number int, b *library.Build) (*library.Step, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "step": number, - }).Tracef("getting step %d for build %d from the database", number, b.GetNumber()) - - // variable to store query results - s := new(database.Step) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableStep). - Raw(dml.SelectBuildStep, b.GetID(), number). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return s.ToLibrary(), result.Error -} - -// CreateStep creates a new step in the database. -func (c *client) CreateStep(s *library.Step) error { - c.Logger.WithFields(logrus.Fields{ - "step": s.GetNumber(), - }).Tracef("creating step %s in the database", s.GetName()) - - // cast to database type - step := database.StepFromLibrary(s) - - // validate the necessary fields are populated - err := step.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableStep). - Create(step).Error -} - -// UpdateStep updates a step in the database. -func (c *client) UpdateStep(s *library.Step) error { - c.Logger.WithFields(logrus.Fields{ - "step": s.GetNumber(), - }).Tracef("updating step %s in the database", s.GetName()) - - // cast to database type - step := database.StepFromLibrary(s) - - // validate the necessary fields are populated - err := step.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableStep). - Save(step).Error -} - -// DeleteStep deletes a step by unique ID from the database. -func (c *client) DeleteStep(id int64) error { - c.Logger.Tracef("deleting step %d from the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableStep). - Exec(dml.DeleteStep, id).Error -} diff --git a/database/postgres/step_count.go b/database/postgres/step_count.go deleted file mode 100644 index 64fe6952b..000000000 --- a/database/postgres/step_count.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildStepCount gets a count of all steps by build ID from the database. -func (c *client) GetBuildStepCount(b *library.Build) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("getting count of steps for build %d from the database", b.GetNumber()) - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableStep). - Raw(dml.SelectBuildStepsCount, b.GetID()). - Pluck("count", &s).Error - - return s, err -} - -// GetStepImageCount gets a count of all step images -// and the count of their occurrence in the database. -func (c *client) GetStepImageCount() (map[string]float64, error) { - c.Logger.Tracef("getting count of all images for steps from the database") - - type imageCount struct { - Image string - Count int - } - - // variable to store query results - images := new([]imageCount) - counts := make(map[string]float64) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableStep). - Raw(dml.SelectStepImagesCount). - Scan(images).Error - - for _, image := range *images { - counts[image.Image] = float64(image.Count) - } - - return counts, err -} - -// GetStepStatusCount gets a list of all step statuses -// and the count of their occurrence in the database. -func (c *client) GetStepStatusCount() (map[string]float64, error) { - c.Logger.Trace("getting count of all statuses for steps from the database") - - type statusCount struct { - Status string - Count int - } - - // variable to store query results - s := new([]statusCount) - counts := map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - } - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableStep). - Raw(dml.SelectStepStatusesCount). - Scan(s).Error - - for _, status := range *s { - counts[status.Status] = float64(status.Count) - } - - return counts, err -} diff --git a/database/postgres/step_count_test.go b/database/postgres/step_count_test.go deleted file mode 100644 index e065ade38..000000000 --- a/database/postgres/step_count_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuildStepCount(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildStepsCount, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildStepCount(_build) - - if test.failure { - if err == nil { - t.Errorf("GetBuildStepCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildStepCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildStepCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetStepImageCount(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectStepImagesCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"image", "count"}).AddRow("foo", 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{"foo": 0}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepImageCount() - - if test.failure { - if err == nil { - t.Errorf("GetStepImageCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepImageCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepImageCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetStepStatusCount(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectStepStatusesCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"status", "count"}). - AddRow("failure", 0). - AddRow("killed", 0). - AddRow("pending", 0). - AddRow("running", 0). - AddRow("success", 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - }, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepStatusCount() - - if test.failure { - if err == nil { - t.Errorf("GetStepStatusCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepStatusCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepStatusCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/step_list.go b/database/postgres/step_list.go deleted file mode 100644 index 8e678f382..000000000 --- a/database/postgres/step_list.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetStepList gets a list of all steps from the database. -func (c *client) GetStepList() ([]*library.Step, error) { - c.Logger.Trace("listing steps from the database") - - // variable to store query results - s := new([]database.Step) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableStep). - Raw(dml.ListSteps). - Scan(s).Error - - // variable we want to return - steps := []*library.Step{} - // iterate through all query results - for _, step := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := step - - // convert query result to library type - steps = append(steps, tmp.ToLibrary()) - } - - return steps, err -} - -// GetBuildStepList gets a list of steps by build ID from the database. -func (c *client) GetBuildStepList(b *library.Build, page, perPage int) ([]*library.Step, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("listing steps for build %d from the database", b.GetNumber()) - - // variable to store query results - s := new([]database.Step) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableStep). - Raw(dml.ListBuildSteps, b.GetID(), perPage, offset). - Scan(s).Error - - // variable we want to return - steps := []*library.Step{} - // iterate through all query results - for _, step := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := step - - // convert query result to library type - steps = append(steps, tmp.ToLibrary()) - } - - return steps, err -} diff --git a/database/postgres/step_list_test.go b/database/postgres/step_list_test.go deleted file mode 100644 index f5985690f..000000000 --- a/database/postgres/step_list_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetStepList(t *testing.T) { - // setup types - _stepOne := testStep() - _stepOne.SetID(1) - _stepOne.SetRepoID(1) - _stepOne.SetBuildID(1) - _stepOne.SetNumber(1) - _stepOne.SetName("foo") - _stepOne.SetImage("bar") - - _stepTwo := testStep() - _stepTwo.SetID(2) - _stepTwo.SetRepoID(1) - _stepTwo.SetBuildID(1) - _stepTwo.SetNumber(1) - _stepTwo.SetName("bar") - _stepTwo.SetImage("foo") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListSteps).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). - AddRow(2, 1, 1, 1, "bar", "foo", "", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Step - }{ - { - failure: false, - want: []*library.Step{_stepOne, _stepTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepList() - - if test.failure { - if err == nil { - t.Errorf("GetStepList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetBuildStepList(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _stepOne := testStep() - _stepOne.SetID(1) - _stepOne.SetRepoID(1) - _stepOne.SetBuildID(1) - _stepOne.SetNumber(1) - _stepOne.SetName("foo") - _stepOne.SetImage("bar") - - _stepTwo := testStep() - _stepTwo.SetID(2) - _stepTwo.SetRepoID(1) - _stepTwo.SetBuildID(1) - _stepTwo.SetNumber(1) - _stepTwo.SetName("bar") - _stepTwo.SetImage("foo") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListBuildSteps, 1, 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). - AddRow(2, 1, 1, 1, "bar", "foo", "", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Step - }{ - { - failure: false, - want: []*library.Step{_stepOne, _stepTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildStepList(_build, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetBuildStepList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildStepList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildStepList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/step_test.go b/database/postgres/step_test.go deleted file mode 100644 index 1b0e79388..000000000 --- a/database/postgres/step_test.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetStep(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildStep, 1, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Step - }{ - { - failure: false, - want: _step, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStep(1, _build) - - if test.failure { - if err == nil { - t.Errorf("GetStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStep returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStep is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateStep(t *testing.T) { - // setup types - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "steps" ("build_id","repo_id","number","name","image","stage","status","error","exit_code","created","started","finished","host","runtime","distribution","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`). - WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateStep(_step) - - if test.failure { - if err == nil { - t.Errorf("CreateStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateStep returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateStep(t *testing.T) { - // setup types - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "steps" SET "build_id"=$1,"repo_id"=$2,"number"=$3,"name"=$4,"image"=$5,"stage"=$6,"status"=$7,"error"=$8,"exit_code"=$9,"created"=$10,"started"=$11,"finished"=$12,"host"=$13,"runtime"=$14,"distribution"=$15 WHERE "id" = $16`). - WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateStep(_step) - - if test.failure { - if err == nil { - t.Errorf("UpdateStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateStep returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteStep(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteStep, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteStep(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteStep returned err: %v", err) - } - } -} - -// testStep is a test helper function to create a -// library Step type with all fields set to their -// zero values. -func testStep() *library.Step { - i64 := int64(0) - i := 0 - str := "" - - return &library.Step{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - Number: &i, - Name: &str, - Image: &str, - Stage: &str, - Status: &str, - Error: &str, - ExitCode: &i, - Created: &i64, - Started: &i64, - Finished: &i64, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/service.go b/database/service.go index 81d8ad960..306c77720 100644 --- a/database/service.go +++ b/database/service.go @@ -10,6 +10,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/secret" + "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" @@ -95,37 +96,9 @@ type Service interface { // related to secrets stored in the database. secret.SecretService - // Step Database Interface Functions - - // GetStep defines a function that - // gets a step by number and build ID. - GetStep(int, *library.Build) (*library.Step, error) - // GetStepList defines a function that - // gets a list of all steps. - GetStepList() ([]*library.Step, error) - // GetBuildStepList defines a function that - // gets a list of steps by build ID. - GetBuildStepList(*library.Build, int, int) ([]*library.Step, error) - // GetBuildStepCount defines a function that - // gets the count of steps by build ID. - GetBuildStepCount(*library.Build) (int64, error) - // GetStepImageCount defines a function that - // gets a list of all step images and the - // count of their occurrence. - GetStepImageCount() (map[string]float64, error) - // GetStepStatusCount defines a function that - // gets a list of all step statuses and the - // count of their occurrence. - GetStepStatusCount() (map[string]float64, error) - // CreateStep defines a function that - // creates a new step. - CreateStep(*library.Step) error - // UpdateStep defines a function that - // updates a step. - UpdateStep(*library.Step) error - // DeleteStep defines a function that - // deletes a step by unique ID. - DeleteStep(int64) error + // StepService provides the interface for functionality + // related to steps stored in the database. + step.StepService // Service Database Interface Functions diff --git a/database/sqlite/ddl/step.go b/database/sqlite/ddl/step.go deleted file mode 100644 index 7809dcc3f..000000000 --- a/database/sqlite/ddl/step.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateStepTable represents a query to - // create the steps table for Vela. - CreateStepTable = ` -CREATE TABLE -IF NOT EXISTS -steps ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - name TEXT, - image TEXT, - stage TEXT, - status TEXT, - error TEXT, - exit_code INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - host TEXT, - runtime TEXT, - distribution TEXT, - UNIQUE(build_id, number) -); -` -) diff --git a/database/sqlite/dml/step.go b/database/sqlite/dml/step.go deleted file mode 100644 index 862ea2a67..000000000 --- a/database/sqlite/dml/step.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListSteps represents a query to - // list all steps in the database. - ListSteps = ` -SELECT * -FROM steps; -` - - // ListBuildSteps represents a query to list - // all steps for a build_id in the database. - ListBuildSteps = ` -SELECT * -FROM steps -WHERE build_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectBuildStepsCount represents a query to select - // the count of steps for a build_id in the database. - SelectBuildStepsCount = ` -SELECT count(*) as count -FROM steps -WHERE build_id = ? -` - - // SelectStepImagesCount represents a query to select - // the count of an images appearances in the database. - SelectStepImagesCount = ` -SELECT image, count(image) as count -FROM steps -GROUP BY image; -` - - // SelectStepStatusesCount represents a query to select - // the count of step status' appearances in the database. - SelectStepStatusesCount = ` -SELECT status, count(status) as count -FROM steps -GROUP BY status; -` - - // SelectBuildStep represents a query to select a - // step for a build_id and number in the database. - SelectBuildStep = ` -SELECT * -FROM steps -WHERE build_id = ? -AND number = ? -LIMIT 1; -` - - // DeleteStep represents a query to - // remove a step from the database. - DeleteStep = ` -DELETE -FROM steps -WHERE id = ?; -` -) diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 87645f323..abc382a37 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -14,6 +14,7 @@ import ( "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/sqlite/ddl" + "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" @@ -57,6 +58,8 @@ type ( repo.RepoService // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService secret.SecretService + // https://pkg.go.dev/github.com/go-vela/server/database/step#StepService + step.StepService // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService user.UserService // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService @@ -248,12 +251,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) } - // create the steps table - err = c.Sqlite.Exec(ddl.CreateStepTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) - } - return nil } @@ -357,6 +354,18 @@ func createServices(c *client) error { return err } + // create the database agnostic step service + // + // https://pkg.go.dev/github.com/go-vela/server/database/step#New + c.StepService, err = step.New( + step.WithClient(c.Sqlite), + step.WithLogger(c.Logger), + step.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic user service // // https://pkg.go.dev/github.com/go-vela/server/database/user#New diff --git a/database/sqlite/step.go b/database/sqlite/step.go deleted file mode 100644 index f055b2ebe..000000000 --- a/database/sqlite/step.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetStep gets a step by number and build ID from the database. -func (c *client) GetStep(number int, b *library.Build) (*library.Step, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "step": number, - }).Tracef("getting step %d for build %d from the database", number, b.GetNumber()) - - // variable to store query results - s := new(database.Step) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableStep). - Raw(dml.SelectBuildStep, b.GetID(), number). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return s.ToLibrary(), result.Error -} - -// CreateStep creates a new step in the database. -func (c *client) CreateStep(s *library.Step) error { - c.Logger.WithFields(logrus.Fields{ - "step": s.GetNumber(), - }).Tracef("creating step %s in the database", s.GetName()) - - // cast to database type - step := database.StepFromLibrary(s) - - // validate the necessary fields are populated - err := step.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableStep). - Create(step).Error -} - -// UpdateStep updates a step in the database. -func (c *client) UpdateStep(s *library.Step) error { - c.Logger.WithFields(logrus.Fields{ - "step": s.GetNumber(), - }).Tracef("updating step %s in the database", s.GetName()) - - // cast to database type - step := database.StepFromLibrary(s) - - // validate the necessary fields are populated - err := step.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableStep). - Save(step).Error -} - -// DeleteStep deletes a step by unique ID from the database. -func (c *client) DeleteStep(id int64) error { - c.Logger.Tracef("deleting step %d from the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableStep). - Exec(dml.DeleteStep, id).Error -} diff --git a/database/sqlite/step_count.go b/database/sqlite/step_count.go deleted file mode 100644 index 1d7e45c87..000000000 --- a/database/sqlite/step_count.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildStepCount gets a count of all steps by build ID from the database. -func (c *client) GetBuildStepCount(b *library.Build) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("getting count of steps for build %d from the database", b.GetNumber()) - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableStep). - Raw(dml.SelectBuildStepsCount, b.GetID()). - Pluck("count", &s).Error - - return s, err -} - -// GetStepImageCount gets a count of all step images -// and the count of their occurrence in the database. -func (c *client) GetStepImageCount() (map[string]float64, error) { - c.Logger.Tracef("getting count of all images for steps from the database") - - type imageCount struct { - Image string - Count int - } - - // variable to store query results - images := new([]imageCount) - counts := make(map[string]float64) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableStep). - Raw(dml.SelectStepImagesCount). - Scan(images).Error - - for _, image := range *images { - counts[image.Image] = float64(image.Count) - } - - return counts, err -} - -// GetStepStatusCount gets a list of all step statuses -// and the count of their occurrence in the database. -func (c *client) GetStepStatusCount() (map[string]float64, error) { - c.Logger.Trace("getting count of all statuses for steps from the database") - - type statusCount struct { - Status string - Count int - } - - // variable to store query results - s := new([]statusCount) - counts := map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - } - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableStep). - Raw(dml.SelectStepStatusesCount). - Scan(s).Error - - for _, status := range *s { - counts[status.Status] = float64(status.Count) - } - - return counts, err -} diff --git a/database/sqlite/step_count_test.go b/database/sqlite/step_count_test.go deleted file mode 100644 index 83bf7138a..000000000 --- a/database/sqlite/step_count_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the step table - err = _database.Sqlite.Exec(ddl.CreateStepTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableStep, err) - } -} - -func TestSqlite_Client_GetBuildStepCount(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _stepOne := testStep() - _stepOne.SetID(1) - _stepOne.SetRepoID(1) - _stepOne.SetBuildID(1) - _stepOne.SetNumber(1) - _stepOne.SetName("foo") - _stepOne.SetImage("bar") - - _stepTwo := testStep() - _stepTwo.SetID(2) - _stepTwo.SetRepoID(1) - _stepTwo.SetBuildID(1) - _stepTwo.SetNumber(2) - _stepTwo.SetName("bar") - _stepTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - // create the steps in the database - err := _database.CreateStep(_stepOne) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - - err = _database.CreateStep(_stepTwo) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - - got, err := _database.GetBuildStepCount(_build) - - if test.failure { - if err == nil { - t.Errorf("GetBuildStepCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildStepCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildStepCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetStepImageCount(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepImageCount() - - if test.failure { - if err == nil { - t.Errorf("GetStepImageCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepImageCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepImageCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetStepStatusCount(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - }, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetStepStatusCount() - - if test.failure { - if err == nil { - t.Errorf("GetStepStatusCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepStatusCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepStatusCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/step_list.go b/database/sqlite/step_list.go deleted file mode 100644 index 4c82fa858..000000000 --- a/database/sqlite/step_list.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetStepList gets a list of all steps from the database. -func (c *client) GetStepList() ([]*library.Step, error) { - c.Logger.Trace("listing steps from the database") - - // variable to store query results - s := new([]database.Step) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableStep). - Raw(dml.ListSteps). - Scan(s).Error - - // variable we want to return - steps := []*library.Step{} - // iterate through all query results - for _, step := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := step - - // convert query result to library type - steps = append(steps, tmp.ToLibrary()) - } - - return steps, err -} - -// GetBuildStepList gets a list of steps by build ID from the database. -func (c *client) GetBuildStepList(b *library.Build, page, perPage int) ([]*library.Step, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("listing steps for build %d from the database", b.GetNumber()) - - // variable to store query results - s := new([]database.Step) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableStep). - Raw(dml.ListBuildSteps, b.GetID(), perPage, offset). - Scan(s).Error - - // variable we want to return - steps := []*library.Step{} - // iterate through all query results - for _, step := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := step - - // convert query result to library type - steps = append(steps, tmp.ToLibrary()) - } - - return steps, err -} diff --git a/database/sqlite/step_list_test.go b/database/sqlite/step_list_test.go deleted file mode 100644 index 75956b54f..000000000 --- a/database/sqlite/step_list_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the step table - err = _database.Sqlite.Exec(ddl.CreateStepTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableStep, err) - } -} - -func TestSqlite_Client_GetStepList(t *testing.T) { - // setup types - _stepOne := testStep() - _stepOne.SetID(1) - _stepOne.SetRepoID(1) - _stepOne.SetBuildID(1) - _stepOne.SetNumber(1) - _stepOne.SetName("foo") - _stepOne.SetImage("bar") - - _stepTwo := testStep() - _stepTwo.SetID(2) - _stepTwo.SetRepoID(1) - _stepTwo.SetBuildID(1) - _stepTwo.SetNumber(2) - _stepTwo.SetName("bar") - _stepTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Step - }{ - { - failure: false, - want: []*library.Step{_stepOne, _stepTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - for _, step := range test.want { - // create the step in the database - err := _database.CreateStep(step) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - } - - got, err := _database.GetStepList() - - if test.failure { - if err == nil { - t.Errorf("GetStepList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStepList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStepList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetBuildStepList(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _stepOne := testStep() - _stepOne.SetID(1) - _stepOne.SetRepoID(1) - _stepOne.SetBuildID(1) - _stepOne.SetNumber(1) - _stepOne.SetName("foo") - _stepOne.SetImage("bar") - - _stepTwo := testStep() - _stepTwo.SetID(2) - _stepTwo.SetRepoID(1) - _stepTwo.SetBuildID(1) - _stepTwo.SetNumber(2) - _stepTwo.SetName("bar") - _stepTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Step - }{ - { - failure: false, - want: []*library.Step{_stepTwo, _stepOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - for _, step := range test.want { - // create the step in the database - err := _database.CreateStep(step) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - } - - got, err := _database.GetBuildStepList(_build, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetBuildStepList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildStepList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildStepList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/step_test.go b/database/sqlite/step_test.go deleted file mode 100644 index 7c7b91500..000000000 --- a/database/sqlite/step_test.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetStep(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Step - }{ - { - failure: false, - want: _step, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the step in the database - err := _database.CreateStep(test.want) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - } - - got, err := _database.GetStep(1, _build) - - // cleanup the steps table - _ = _database.Sqlite.Exec("DELETE FROM steps;") - - if test.failure { - if err == nil { - t.Errorf("GetStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetStep returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetStep is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateStep(t *testing.T) { - // setup types - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - err := _database.CreateStep(_step) - - if test.failure { - if err == nil { - t.Errorf("CreateStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateStep returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateStep(t *testing.T) { - // setup types - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - // create the step in the database - err := _database.CreateStep(_step) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - - err = _database.UpdateStep(_step) - - if test.failure { - if err == nil { - t.Errorf("UpdateStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateStep returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteStep(t *testing.T) { - // setup types - _step := testStep() - _step.SetID(1) - _step.SetRepoID(1) - _step.SetBuildID(1) - _step.SetNumber(1) - _step.SetName("foo") - _step.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the steps table - defer _database.Sqlite.Exec("delete from steps;") - - // create the step in the database - err := _database.CreateStep(_step) - if err != nil { - t.Errorf("unable to create test step: %v", err) - } - - err = _database.DeleteStep(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteStep should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteStep returned err: %v", err) - } - } -} - -// testStep is a test helper function to create a -// library Step type with all fields set to their -// zero values. -func testStep() *library.Step { - i64 := int64(0) - i := 0 - str := "" - - return &library.Step{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - Number: &i, - Name: &str, - Image: &str, - Stage: &str, - Status: &str, - Error: &str, - ExitCode: &i, - Created: &i64, - Started: &i64, - Finished: &i64, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/step/count.go b/database/step/count.go new file mode 100644 index 000000000..6f8a665b4 --- /dev/null +++ b/database/step/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" +) + +// CountSteps gets the count of all steps from the database. +func (e *engine) CountSteps() (int64, error) { + e.logger.Tracef("getting count of all steps from the database") + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Count(&s). + Error + + return s, err +} diff --git a/database/step/count_build.go b/database/step/count_build.go new file mode 100644 index 000000000..448e04d7d --- /dev/null +++ b/database/step/count_build.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountStepsForBuild gets the count of steps by build ID from the database. +func (e *engine) CountStepsForBuild(b *library.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()) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Where("build_id = ?", b.GetID()). + Where(filters). + Count(&s). + Error + + return s, err +} diff --git a/database/step/count_build_test.go b/database/step/count_build_test.go new file mode 100644 index 000000000..401e1d6b3 --- /dev/null +++ b/database/step/count_build_test.go @@ -0,0 +1,104 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_CountStepsForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(2) + _stepTwo.SetNumber(1) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "steps" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountStepsForBuild(_build, filters) + + if test.failure { + if err == nil { + t.Errorf("CountStepsForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountStepsForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountStepsForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/count_test.go b/database/step/count_test.go new file mode 100644 index 000000000..eff1fec8c --- /dev/null +++ b/database/step/count_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_CountSteps(t *testing.T) { + // setup types + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(2) + _stepTwo.SetNumber(1) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "steps"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSteps() + + if test.failure { + if err == nil { + t.Errorf("CountSteps for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSteps for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSteps for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/create.go b/database/step/create.go new file mode 100644 index 000000000..03ec3a953 --- /dev/null +++ b/database/step/create.go @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateStep creates a new step in the database. +func (e *engine) CreateStep(s *library.Step) error { + e.logger.WithFields(logrus.Fields{ + "step": s.GetNumber(), + }).Tracef("creating step %s in the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#StepFromLibrary + step := database.StepFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.Validate + err := step.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableStep). + Create(step). + Error +} diff --git a/database/step/create_test.go b/database/step/create_test.go new file mode 100644 index 000000000..1f7b3e1b8 --- /dev/null +++ b/database/step/create_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_CreateStep(t *testing.T) { + // setup types + _step := testStep() + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + _step.SetName("foo") + _step.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "steps" +("build_id","repo_id","number","name","image","stage","status","error","exit_code","created","started","finished","host","runtime","distribution","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`). + WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateStep(_step) + + if test.failure { + if err == nil { + t.Errorf("CreateStep for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateStep for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/step/delete.go b/database/step/delete.go new file mode 100644 index 000000000..d5107dea8 --- /dev/null +++ b/database/step/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteStep deletes an existing step from the database. +func (e *engine) DeleteStep(s *library.Step) error { + e.logger.WithFields(logrus.Fields{ + "step": s.GetNumber(), + }).Tracef("deleting step %s from the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#StepFromLibrary + step := database.StepFromLibrary(s) + + // send query to the database + return e.client. + Table(constants.TableStep). + Delete(step). + Error +} diff --git a/database/step/delete_test.go b/database/step/delete_test.go new file mode 100644 index 000000000..c3b35ee8a --- /dev/null +++ b/database/step/delete_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_DeleteStep(t *testing.T) { + // setup types + _step := testStep() + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + _step.SetName("foo") + _step.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "steps" WHERE "steps"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_step) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteStep(_step) + + if test.failure { + if err == nil { + t.Errorf("DeleteStep for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteStep for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/step/get.go b/database/step/get.go new file mode 100644 index 000000000..1b07d1f6a --- /dev/null +++ b/database/step/get.go @@ -0,0 +1,34 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetStep gets a step by ID from the database. +func (e *engine) GetStep(id int64) (*library.Step, error) { + e.logger.Tracef("getting step %d from the database", id) + + // variable to store query results + s := new(database.Step) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Where("id = ?", id). + Take(s). + Error + if err != nil { + return nil, err + } + + // return the step + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/step/get_build.go b/database/step/get_build.go new file mode 100644 index 000000000..49aed7551 --- /dev/null +++ b/database/step/get_build.go @@ -0,0 +1,39 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetStepForBuild gets a step by number and build ID from the database. +func (e *engine) GetStepForBuild(b *library.Build, number int) (*library.Step, error) { + e.logger.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "step": number, + }).Tracef("getting step %d from the database", number) + + // variable to store query results + s := new(database.Step) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Where("build_id = ?", b.GetID()). + Where("number = ?", number). + Take(s). + Error + if err != nil { + return nil, err + } + + // return the step + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/step/get_build_test.go b/database/step/get_build_test.go new file mode 100644 index 000000000..ce4bfff37 --- /dev/null +++ b/database/step/get_build_test.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestStep_Engine_GetStepForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _step := testStep() + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + _step.SetName("foo") + _step.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "steps" WHERE build_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_step) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Step + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _step, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _step, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetStepForBuild(_build, 1) + + if test.failure { + if err == nil { + t.Errorf("GetStepForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetStepForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetStepForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/get_test.go b/database/step/get_test.go new file mode 100644 index 000000000..382fa0b7c --- /dev/null +++ b/database/step/get_test.go @@ -0,0 +1,87 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestStep_Engine_GetStep(t *testing.T) { + // setup types + _step := testStep() + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + _step.SetName("foo") + _step.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "steps" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_step) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Step + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _step, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _step, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetStep(1) + + if test.failure { + if err == nil { + t.Errorf("GetStep for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetStep for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetStep for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/list.go b/database/step/list.go new file mode 100644 index 000000000..3c7fedbc9 --- /dev/null +++ b/database/step/list.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListSteps gets a list of all steps from the database. +func (e *engine) ListSteps() ([]*library.Step, error) { + e.logger.Trace("listing all steps from the database") + + // variables to store query results and return value + count := int64(0) + w := new([]database.Step) + steps := []*library.Step{} + + // count the results + count, err := e.CountSteps() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return steps, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableStep). + Find(&w). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, step := range *w { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := step + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.ToLibrary + steps = append(steps, tmp.ToLibrary()) + } + + return steps, nil +} diff --git a/database/step/list_build.go b/database/step/list_build.go new file mode 100644 index 000000000..f338b1374 --- /dev/null +++ b/database/step/list_build.go @@ -0,0 +1,65 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListStepsForBuild gets a list of all steps from the database. +func (e *engine) ListStepsForBuild(b *library.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()) + + // variables to store query results and return value + count := int64(0) + s := new([]database.Step) + steps := []*library.Step{} + + // count the results + count, err := e.CountStepsForBuild(b, filters) + if err != nil { + return steps, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return steps, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableStep). + Where("build_id = ?", b.GetID()). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, step := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := step + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.ToLibrary + steps = append(steps, tmp.ToLibrary()) + } + + return steps, count, nil +} diff --git a/database/step/list_build_test.go b/database/step/list_build_test.go new file mode 100644 index 000000000..c79100eae --- /dev/null +++ b/database/step/list_build_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestStep_Engine_ListStepsForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(1) + _stepTwo.SetNumber(2) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "steps" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(2, 1, 1, 2, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "steps" WHERE build_id = $1 ORDER BY id DESC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Step + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Step{_stepTwo, _stepOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Step{_stepTwo, _stepOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListStepsForBuild(_build, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListStepsForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListStepsForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListStepsForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/list_image.go b/database/step/list_image.go new file mode 100644 index 000000000..cd02af894 --- /dev/null +++ b/database/step/list_image.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "database/sql" + + "github.com/go-vela/types/constants" +) + +// ListStepImageCount gets a list of all step images and the count of their occurrence from the database. +func (e *engine) ListStepImageCount() (map[string]float64, error) { + e.logger.Tracef("getting count of all images for steps from the database") + + // variables to store query results and return value + s := []struct { + Image sql.NullString + Count sql.NullInt32 + }{} + images := make(map[string]float64) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Select("image", " count(image) as count"). + Group("image"). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, value := range s { + // check if the image returned is not empty + if value.Image.Valid { + images[value.Image.String] = float64(value.Count.Int32) + } + } + + return images, nil +} diff --git a/database/step/list_image_test.go b/database/step/list_image_test.go new file mode 100644 index 000000000..574545493 --- /dev/null +++ b/database/step/list_image_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_ListStepImageCount(t *testing.T) { + // setup types + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(1) + _stepTwo.SetNumber(2) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"image", "count"}).AddRow("bar", 2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT "image", count(image) as count FROM "steps" GROUP BY "image"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want map[string]float64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: map[string]float64{"bar": 2}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: map[string]float64{"bar": 2}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListStepImageCount() + + if test.failure { + if err == nil { + t.Errorf("ListStepImageCount for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListStepImageCount for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListStepImageCount for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/list_status.go b/database/step/list_status.go new file mode 100644 index 000000000..9b54e3b7f --- /dev/null +++ b/database/step/list_status.go @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "database/sql" + + "github.com/go-vela/types/constants" +) + +// ListStepStatusCount gets a list of all step statuses and the count of their occurrence from the database. +func (e *engine) ListStepStatusCount() (map[string]float64, error) { + e.logger.Tracef("getting count of all statuses for steps from the database") + + // variables to store query results and return value + s := []struct { + Status sql.NullString + Count sql.NullInt32 + }{} + statuses := map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + } + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableStep). + Select("status", " count(status) as count"). + Group("status"). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, value := range s { + // check if the status returned is not empty + if value.Status.Valid { + statuses[value.Status.String] = float64(value.Count.Int32) + } + } + + return statuses, nil +} diff --git a/database/step/list_status_test.go b/database/step/list_status_test.go new file mode 100644 index 000000000..57f500650 --- /dev/null +++ b/database/step/list_status_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_ListStepStatusCount(t *testing.T) { + // setup types + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(1) + _stepTwo.SetNumber(2) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"status", "count"}). + AddRow("pending", 0). + AddRow("failure", 0). + AddRow("killed", 0). + AddRow("running", 0). + AddRow("success", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT "status", count(status) as count FROM "steps" GROUP BY "status"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want map[string]float64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + }, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListStepStatusCount() + + if test.failure { + if err == nil { + t.Errorf("ListStepStatusCount for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListStepStatusCount for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListStepStatusCount for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/list_test.go b/database/step/list_test.go new file mode 100644 index 000000000..cb1c05cb2 --- /dev/null +++ b/database/step/list_test.go @@ -0,0 +1,107 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestStep_Engine_ListSteps(t *testing.T) { + // setup types + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(2) + _stepTwo.SetNumber(1) + _stepTwo.SetName("bar") + _stepTwo.SetImage("foo") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "steps"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). + AddRow(2, 1, 2, 1, "bar", "foo", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "steps"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Step + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Step{_stepOne, _stepTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Step{_stepOne, _stepTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListSteps() + + if test.failure { + if err == nil { + t.Errorf("ListSteps for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSteps for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSteps for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/opts.go b/database/step/opts.go new file mode 100644 index 000000000..80db4689c --- /dev/null +++ b/database/step/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Steps. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Steps. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the step engine + e.client = client + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Steps. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the step engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Steps. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the step engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/step/opts_test.go b/database/step/opts_test.go new file mode 100644 index 000000000..4ea1d64c0 --- /dev/null +++ b/database/step/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestStep_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestStep_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestStep_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/step/service.go b/database/step/service.go new file mode 100644 index 000000000..4007e537a --- /dev/null +++ b/database/step/service.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/library" +) + +// StepService represents the Vela interface for step +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type StepService interface { + // Step Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateStepTable defines a function that creates the steps table. + CreateStepTable(string) error + + // Step Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountSteps defines a function that gets the count of all steps. + CountSteps() (int64, error) + // CountStepsForBuild defines a function that gets the count of steps by build ID. + CountStepsForBuild(*library.Build, map[string]interface{}) (int64, error) + // CreateStep defines a function that creates a new step. + CreateStep(*library.Step) error + // DeleteStep defines a function that deletes an existing step. + DeleteStep(*library.Step) error + // GetStep defines a function that gets a step by ID. + GetStep(int64) (*library.Step, error) + // GetStepForBuild defines a function that gets a step by number and build ID. + GetStepForBuild(*library.Build, int) (*library.Step, error) + // ListSteps defines a function that gets a list of all steps. + ListSteps() ([]*library.Step, error) + // ListStepsForBuild defines a function that gets a list of steps by build ID. + ListStepsForBuild(*library.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() (map[string]float64, error) + // ListStepStatusCount defines a function that gets a list of all step statuses and the count of their occurrence. + ListStepStatusCount() (map[string]float64, error) + // UpdateStep defines a function that updates an existing step. + UpdateStep(*library.Step) error +} diff --git a/database/step/step.go b/database/step/step.go new file mode 100644 index 000000000..94017b04c --- /dev/null +++ b/database/step/step.go @@ -0,0 +1,74 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the StepService interface. + config struct { + // specifies to skip creating tables and indexes for the Step engine + SkipCreation bool + } + + // engine represents the step functionality that implements the StepService interface. + engine struct { + // engine configuration settings used in step functions + config *config + + // gorm.io/gorm database client used in step functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in step functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with steps in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Step engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating step database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of steps table in the database") + + return e, nil + } + + // create the steps table + err := e.CreateStepTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableStep, err) + } + + return e, nil +} diff --git a/database/step/step_test.go b/database/step/step_test.go new file mode 100644 index 000000000..26edfa5e1 --- /dev/null +++ b/database/step/step_test.go @@ -0,0 +1,225 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestStep_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres step engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite step engine: %v", err) + } + + 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), + } +} diff --git a/database/step/table.go b/database/step/table.go new file mode 100644 index 000000000..ffd44c6c6 --- /dev/null +++ b/database/step/table.go @@ -0,0 +1,78 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres steps table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +steps ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + name VARCHAR(250), + image VARCHAR(500), + stage VARCHAR(250), + status VARCHAR(250), + error VARCHAR(500), + exit_code INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + host VARCHAR(250), + runtime VARCHAR(250), + distribution VARCHAR(250), + UNIQUE(build_id, number) +); +` + + // CreateSqliteTable represents a query to create the Sqlite steps table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +steps ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + name TEXT, + image TEXT, + stage TEXT, + status TEXT, + error TEXT, + exit_code INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + host TEXT, + runtime TEXT, + distribution TEXT, + UNIQUE(build_id, number) +); +` +) + +// CreateStepTable creates the steps table in the database. +func (e *engine) CreateStepTable(driver string) error { + e.logger.Tracef("creating steps table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the steps table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the steps table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/step/table_test.go b/database/step/table_test.go new file mode 100644 index 000000000..08900c753 --- /dev/null +++ b/database/step/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_CreateStepTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateStepTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateStepTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateStepTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/step/update.go b/database/step/update.go new file mode 100644 index 000000000..87f8d2aa9 --- /dev/null +++ b/database/step/update.go @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateStep updates an existing step in the database. +func (e *engine) UpdateStep(s *library.Step) error { + e.logger.WithFields(logrus.Fields{ + "step": s.GetNumber(), + }).Tracef("updating step %s in the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#StepFromLibrary + step := database.StepFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Step.Validate + err := step.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableStep). + Save(step). + Error +} diff --git a/database/step/update_test.go b/database/step/update_test.go new file mode 100644 index 000000000..c2a10a113 --- /dev/null +++ b/database/step/update_test.go @@ -0,0 +1,77 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_UpdateStep(t *testing.T) { + // setup types + _step := testStep() + _step.SetID(1) + _step.SetRepoID(1) + _step.SetBuildID(1) + _step.SetNumber(1) + _step.SetName("foo") + _step.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "steps" +SET "build_id"=$1,"repo_id"=$2,"number"=$3,"name"=$4,"image"=$5,"stage"=$6,"status"=$7,"error"=$8,"exit_code"=$9,"created"=$10,"started"=$11,"finished"=$12,"host"=$13,"runtime"=$14,"distribution"=$15 +WHERE "id" = $16`). + WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_step) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateStep(_step) + + if test.failure { + if err == nil { + t.Errorf("UpdateStep for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateStep for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/router/middleware/step/step.go b/router/middleware/step/step.go index 7dbd2d6c5..27d517efe 100644 --- a/router/middleware/step/step.go +++ b/router/middleware/step/step.go @@ -75,7 +75,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading step %s/%d/%d", r.GetFullName(), b.GetNumber(), number) - s, err := database.FromContext(c).GetStep(number, b) + s, err := database.FromContext(c).GetStepForBuild(b, number) if err != nil { retErr := fmt.Errorf("unable to read step %s/%d/%d: %w", r.GetFullName(), b.GetNumber(), number, err) util.HandleError(c, http.StatusNotFound, retErr) From 676edd65e0cc89a0b1a75616f23f6a55de317393 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 17 Apr 2023 10:11:28 -0600 Subject: [PATCH 201/298] enhance(repo)!: add topics field to build env and repo (#807) * enhance(repo): add topics field to build env and repo * update types, trust in nil checks * update swagger * update scm tests * webhook refactoring * fix some hook logic * Update api/webhook.go Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> * address feedback * correct name for second repo db get * change log repo var --------- Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/webhook.go | 345 ++++++++++-------- compiler/native/environment_test.go | 37 +- database/repo/create_test.go | 6 +- database/repo/get_org_test.go | 5 +- database/repo/get_test.go | 5 +- database/repo/list_org_test.go | 14 +- database/repo/list_test.go | 8 +- database/repo/list_user_test.go | 14 +- database/repo/table.go | 2 + database/repo/update_test.go | 6 +- go.mod | 2 +- go.sum | 4 +- router/middleware/repo/repo_test.go | 1 + scm/github/repo.go | 1 + scm/github/repo_test.go | 2 + .../testdata/hooks/repository_edited.json | 6 +- scm/github/webhook.go | 6 + scm/github/webhook_test.go | 9 + 18 files changed, 281 insertions(+), 192 deletions(-) diff --git a/api/webhook.go b/api/webhook.go index 56794fe57..4c657425e 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "net/http" + "reflect" "strings" "time" @@ -134,18 +135,27 @@ func PostWebhook(c *gin.Context) { logrus.Debugf("hook generated from SCM: %v", h) logrus.Debugf("repo generated from SCM: %v", r) - if b != nil { - logrus.Debugf(`build author: %s, - build branch: %s, - build commit: %s, - build ref: %s`, - b.GetAuthor(), b.GetBranch(), b.GetCommit(), b.GetRef()) + // if event is repository event, handle separately and return + if strings.EqualFold(h.GetEvent(), constants.EventRepository) { + r, err = handleRepositoryEvent(c, m, h, r) + if err != nil { + util.HandleError(c, http.StatusInternalServerError, err) + return + } + + // if there were actual changes to the repo, return the repo object + if r.GetID() != 0 { + c.JSON(http.StatusOK, r) + return + } + + c.JSON(http.StatusOK, "handled repository event, no build to process") + + return } // check if build was parsed from webhook. - // build will be nil on repository events, but - // for renaming, we want to continue. - if b == nil && h.GetEvent() != constants.EventRepository { + if b == nil { // typically, this should only happen on a webhook // "ping" which gets sent when the webhook is created c.JSON(http.StatusOK, "no build to process") @@ -153,6 +163,12 @@ func PostWebhook(c *gin.Context) { return } + logrus.Debugf(`build author: %s, + build branch: %s, + build commit: %s, + build ref: %s`, + b.GetAuthor(), b.GetBranch(), b.GetCommit(), b.GetRef()) + // check if repo was parsed from webhook if r == nil { retErr := fmt.Errorf("%s: failed to parse repo from webhook", baseErr) @@ -169,71 +185,8 @@ func PostWebhook(c *gin.Context) { } }() - if h.GetEvent() == constants.EventRepository { - switch h.GetEventAction() { - // if action is rename, go through rename routine - case constants.ActionRenamed: - err = renameRepository(h, r, c, m) - if err != nil { - util.HandleError(c, http.StatusBadRequest, err) - h.SetStatus(constants.StatusFailure) - h.SetError(err.Error()) - } - - c.JSON(http.StatusOK, fmt.Sprintf("no build to process, repository renamed from %s to %s", r.GetPreviousName(), r.GetFullName())) - - return - // if action is archived, unarchived, or edited, perform edits to relevant repo fields - case "archived", "unarchived", constants.ActionEdited: - // send call to get repository from database - dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) - if err != nil { - retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) - util.HandleError(c, http.StatusBadRequest, retErr) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return - } - - var retMsg string - // the only edits to a repo that impact Vela are to these two fields - if !strings.EqualFold(dbRepo.GetBranch(), r.GetBranch()) { - retMsg = fmt.Sprintf("no build to process, repository default branch changed from %s to %s", dbRepo.GetBranch(), r.GetBranch()) - dbRepo.SetBranch(r.GetBranch()) - } - - if dbRepo.GetActive() != r.GetActive() { - retMsg = fmt.Sprintf("no build to process, repository changed active status from %t to %t", dbRepo.GetActive(), r.GetActive()) - dbRepo.SetActive(r.GetActive()) - } - - // update repo object in the database after applying edits - err = database.FromContext(c).UpdateRepo(dbRepo) - if err != nil { - retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) - util.HandleError(c, http.StatusInternalServerError, retErr) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return - } - - c.JSON(http.StatusOK, retMsg) - - return - // all other repo event actions are skippable - default: - c.JSON(http.StatusOK, "no build to process") - - return - } - } - // send API call to capture parsed repo from webhook - r, err = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + repo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -245,13 +198,23 @@ func PostWebhook(c *gin.Context) { } // set the RepoID fields - b.SetRepoID(r.GetID()) - h.SetRepoID(r.GetID()) + b.SetRepoID(repo.GetID()) + h.SetRepoID(repo.GetID()) + + // update repo fields with any changes (necessary for repos enabled before repository event handling) + // TODO: eventually remove this in favor of some sync scripting? + if len(r.GetTopics()) != 0 { + repo.SetTopics(r.GetTopics()) + } + + if !strings.EqualFold(repo.GetBranch(), r.GetBranch()) { + repo.SetBranch(r.GetBranch()) + } // send API call to capture the last hook for the repo - lastHook, err := database.FromContext(c).LastHookForRepo(r) + lastHook, err := database.FromContext(c).LastHookForRepo(repo) if err != nil { - retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) + retErr := fmt.Errorf("unable to get last hook for repo %s: %w", repo.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -270,7 +233,7 @@ func PostWebhook(c *gin.Context) { // send API call to create the webhook err = database.FromContext(c).CreateHook(h) if err != nil { - retErr := fmt.Errorf("unable to create webhook %s/%d: %w", r.GetFullName(), h.GetNumber(), err) + retErr := fmt.Errorf("unable to create webhook %s/%d: %w", repo.GetFullName(), h.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -280,11 +243,11 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the created webhook - h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) + h, _ = database.FromContext(c).GetHookForRepo(repo, h.GetNumber()) // verify the webhook from the source control provider if c.Value("webhookvalidation").(bool) { - err = scm.FromContext(c).VerifyWebhook(dupRequest, r) + err = scm.FromContext(c).VerifyWebhook(dupRequest, repo) if err != nil { retErr := fmt.Errorf("unable to verify webhook: %w", err) util.HandleError(c, http.StatusUnauthorized, retErr) @@ -297,8 +260,8 @@ func PostWebhook(c *gin.Context) { } // check if the repo is active - if !r.GetActive() { - retErr := fmt.Errorf("%s: %s is not an active repo", baseErr, r.GetFullName()) + if !repo.GetActive() { + retErr := fmt.Errorf("%s: %s is not an active repo", baseErr, repo.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -308,12 +271,12 @@ func PostWebhook(c *gin.Context) { } // verify the build has a valid event and the repo allows that event type - if (b.GetEvent() == constants.EventPush && !r.GetAllowPush()) || - (b.GetEvent() == constants.EventPull && !r.GetAllowPull()) || - (b.GetEvent() == constants.EventComment && !r.GetAllowComment()) || - (b.GetEvent() == constants.EventTag && !r.GetAllowTag()) || - (b.GetEvent() == constants.EventDeploy && !r.GetAllowDeploy()) { - retErr := fmt.Errorf("%s: %s does not have %s events enabled", baseErr, r.GetFullName(), b.GetEvent()) + if (b.GetEvent() == constants.EventPush && !repo.GetAllowPush()) || + (b.GetEvent() == constants.EventPull && !repo.GetAllowPull()) || + (b.GetEvent() == constants.EventComment && !repo.GetAllowComment()) || + (b.GetEvent() == constants.EventTag && !repo.GetAllowTag()) || + (b.GetEvent() == constants.EventDeploy && !repo.GetAllowDeploy()) { + retErr := fmt.Errorf("%s: %s does not have %s events enabled", baseErr, repo.GetFullName(), b.GetEvent()) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -323,8 +286,8 @@ func PostWebhook(c *gin.Context) { } // check if the repo has a valid owner - if r.GetUserID() == 0 { - retErr := fmt.Errorf("%s: %s has no valid owner", baseErr, r.GetFullName()) + if repo.GetUserID() == 0 { + retErr := fmt.Errorf("%s: %s has no valid owner", baseErr, repo.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -334,11 +297,11 @@ func PostWebhook(c *gin.Context) { } // send API call to capture repo owner - logrus.Debugf("capturing owner of repository %s", r.GetFullName()) + logrus.Debugf("capturing owner of repository %s", repo.GetFullName()) - u, err := database.FromContext(c).GetUser(r.GetUserID()) + u, err := database.FromContext(c).GetUser(repo.GetUserID()) if err != nil { - retErr := fmt.Errorf("%s: failed to get owner for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get owner for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -353,9 +316,9 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).GetRepoBuildCount(r, filters) + builds, err := database.FromContext(c).GetRepoBuildCount(repo, filters) if err != nil { - retErr := fmt.Errorf("%s: unable to get count of builds for repo %s", baseErr, r.GetFullName()) + retErr := fmt.Errorf("%s: unable to get count of builds for repo %s", baseErr, repo.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -364,11 +327,11 @@ func PostWebhook(c *gin.Context) { return } - logrus.Debugf("currently %d builds running on repo %s", builds, r.GetFullName()) + logrus.Debugf("currently %d builds running on repo %s", builds, repo.GetFullName()) // check if the number of pending and running builds exceeds the limit for the repo - if builds >= r.GetBuildLimit() { - retErr := fmt.Errorf("%s: repo %s has exceeded the concurrent build limit of %d", baseErr, r.GetFullName(), r.GetBuildLimit()) + if builds >= repo.GetBuildLimit() { + retErr := fmt.Errorf("%s: repo %s has exceeded the concurrent build limit of %d", baseErr, repo.GetFullName(), repo.GetBuildLimit()) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -378,8 +341,8 @@ func PostWebhook(c *gin.Context) { } // update fields in build object - logrus.Debugf("updating build number to %d", r.GetCounter()) - b.SetNumber(r.GetCounter()) + logrus.Debugf("updating build number to %d", repo.GetCounter()) + b.SetNumber(repo.GetCounter()) logrus.Debugf("updating parent number to %d", b.GetNumber()) b.SetParent(b.GetNumber()) @@ -389,9 +352,9 @@ func PostWebhook(c *gin.Context) { // if this is a comment on a pull_request event if strings.EqualFold(b.GetEvent(), constants.EventComment) && webhook.PRNumber > 0 { - commit, branch, baseref, headref, err := scm.FromContext(c).GetPullRequest(u, r, webhook.PRNumber) + commit, branch, baseref, headref, err := scm.FromContext(c).GetPullRequest(u, repo, webhook.PRNumber) if err != nil { - retErr := fmt.Errorf("%s: failed to get pull request info for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get pull request info for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -412,9 +375,9 @@ func PostWebhook(c *gin.Context) { if !strings.EqualFold(b.GetEvent(), constants.EventComment) && !strings.EqualFold(b.GetEvent(), constants.EventPull) { // send API call to capture list of files changed for the commit - files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) + files, err = scm.FromContext(c).Changeset(u, repo, b.GetCommit()) if err != nil { - retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -427,9 +390,9 @@ func PostWebhook(c *gin.Context) { // check if the build event is a pull_request if strings.EqualFold(b.GetEvent(), constants.EventPull) && webhook.PRNumber > 0 { // send API call to capture list of files changed for the pull request - files, err = scm.FromContext(c).ChangesetPR(u, r, webhook.PRNumber) + files, err = scm.FromContext(c).ChangesetPR(u, repo, webhook.PRNumber) if err != nil { - retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to get changeset for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -449,7 +412,7 @@ func PostWebhook(c *gin.Context) { // variable to control number of times to retry processing pipeline retryLimit = 3 // variable to store the pipeline type for the repository - pipelineType = r.GetPipelineType() + pipelineType = repo.GetPipelineType() ) // implement a loop to process asynchronous operations with a retry limit @@ -466,12 +429,12 @@ func PostWebhook(c *gin.Context) { } // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), repo) if err != nil { // assume the pipeline doesn't exist in the database yet // send API call to capture the pipeline configuration file - config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) + config, err = scm.FromContext(c).ConfigBackoff(u, repo, b.GetCommit()) if err != nil { - retErr := fmt.Errorf("%s: unable to get pipeline configuration for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: unable to get pipeline configuration for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusNotFound, retErr) @@ -484,8 +447,8 @@ func PostWebhook(c *gin.Context) { config = pipeline.GetData() } - // send API call to capture repo for the counter - r, err = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + // send API call to capture repo for the counter (grabbing repo again to ensure counter is correct) + repo, err = database.FromContext(c).GetRepoForOrg(repo.GetOrg(), repo.GetName()) if err != nil { retErr := fmt.Errorf("%s: unable to get repo %s: %w", baseErr, r.GetFullName(), err) @@ -506,7 +469,7 @@ func PostWebhook(c *gin.Context) { } // set the parent equal to the current repo counter - b.SetParent(r.GetCounter()) + b.SetParent(repo.GetCounter()) // check if the parent is set to 0 if b.GetParent() == 0 { @@ -515,14 +478,14 @@ func PostWebhook(c *gin.Context) { } // update the build numbers based off repo counter - inc := r.GetCounter() + 1 - r.SetCounter(inc) + inc := repo.GetCounter() + 1 + repo.SetCounter(inc) b.SetNumber(inc) // populate the build link if a web address is provided if len(m.Vela.WebAddress) > 0 { b.SetLink( - fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), b.GetNumber()), + fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, repo.GetFullName(), b.GetNumber()), ) } @@ -533,7 +496,7 @@ func PostWebhook(c *gin.Context) { // the repo pipeline type to match what was defined for the existing pipeline // before compiling. After we're done compiling, we reset the pipeline type. if len(pipeline.GetType()) > 0 { - r.SetPipelineType(pipeline.GetType()) + repo.SetPipelineType(pipeline.GetType()) } var compiled *library.Pipeline @@ -544,12 +507,12 @@ func PostWebhook(c *gin.Context) { WithComment(webhook.Comment). WithFiles(files). WithMetadata(m). - WithRepo(r). + WithRepo(repo). WithUser(u). Compile(config) if err != nil { // format the error message with extra information - err = fmt.Errorf("unable to compile pipeline configuration for %s: %w", r.GetFullName(), err) + err = fmt.Errorf("unable to compile pipeline configuration for %s: %w", repo.GetFullName(), err) // log the error for traceability logrus.Error(err.Error()) @@ -569,7 +532,7 @@ func PostWebhook(c *gin.Context) { // existing pipelines in the system for that repo. To account for this, we update // the repo pipeline type to match what was defined for the existing pipeline // before compiling. After we're done compiling, we reset the pipeline type. - r.SetPipelineType(pipelineType) + repo.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found skip := skipEmptyBuild(p) @@ -578,9 +541,9 @@ func PostWebhook(c *gin.Context) { b.SetStatus(constants.StatusSkipped) // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) + err = scm.FromContext(c).Status(u, b, repo.GetOrg(), repo.GetName()) if err != nil { - logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err) + logrus.Errorf("unable to set commit status for %s/%d: %v", repo.GetFullName(), b.GetNumber(), err) } c.JSON(http.StatusOK, skip) @@ -591,14 +554,14 @@ func PostWebhook(c *gin.Context) { // check if the pipeline did not already exist in the database if pipeline == nil { pipeline = compiled - pipeline.SetRepoID(r.GetID()) + pipeline.SetRepoID(repo.GetID()) pipeline.SetCommit(b.GetCommit()) pipeline.SetRef(b.GetRef()) // send API call to create the pipeline err = database.FromContext(c).CreatePipeline(pipeline) if err != nil { - retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, repo.GetFullName(), err) // check if the retry limit has been exceeded if i < retryLimit-1 { @@ -617,10 +580,10 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), repo) if err != nil { //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("%s: failed to get new pipeline %s/%s: %w", baseErr, r.GetFullName(), pipeline.GetCommit(), err) + retErr := fmt.Errorf("%s: failed to get new pipeline %s/%s: %w", baseErr, repo.GetFullName(), pipeline.GetCommit(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -639,7 +602,7 @@ func PostWebhook(c *gin.Context) { // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = planBuild(database.FromContext(c), p, b, r) + err = planBuild(database.FromContext(c), p, b, repo) if err != nil { retErr := fmt.Errorf("%s: %w", baseErr, err) @@ -669,9 +632,9 @@ func PostWebhook(c *gin.Context) { } // end of retry loop // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(r) + err = database.FromContext(c).UpdateRepo(repo) if err != nil { - retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -682,7 +645,7 @@ func PostWebhook(c *gin.Context) { // return error if pipeline didn't get populated if p == nil { - retErr := fmt.Errorf("%s: failed to set pipeline for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to set pipeline for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -693,7 +656,7 @@ func PostWebhook(c *gin.Context) { // return error if build didn't get populated if b == nil { - retErr := fmt.Errorf("%s: failed to set build for %s: %w", baseErr, r.GetFullName(), err) + retErr := fmt.Errorf("%s: failed to set build for %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -703,9 +666,9 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the triggered build - b, err = database.FromContext(c).GetBuild(b.GetNumber(), r) + b, err = database.FromContext(c).GetBuild(b.GetNumber(), repo) if err != nil { - retErr := fmt.Errorf("%s: failed to get new build %s/%d: %w", baseErr, r.GetFullName(), b.GetNumber(), err) + retErr := fmt.Errorf("%s: failed to get new build %s/%d: %w", baseErr, repo.GetFullName(), b.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) h.SetStatus(constants.StatusFailure) @@ -720,9 +683,9 @@ func PostWebhook(c *gin.Context) { c.JSON(http.StatusOK, b) // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) + err = scm.FromContext(c).Status(u, b, repo.GetOrg(), repo.GetName()) if err != nil { - logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err) + logrus.Errorf("unable to set commit status for %s/%d: %v", repo.GetFullName(), b.GetNumber(), err) } // publish the build to the queue @@ -731,7 +694,7 @@ func PostWebhook(c *gin.Context) { database.FromContext(c), p, b, - r, + repo, u, ) } @@ -792,11 +755,99 @@ func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, } } +func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r *library.Repo) (*library.Repo, error) { + logrus.Debugf("webhook is repository event, making necessary updates to repo %s", r.GetFullName()) + + defer func() { + // send API call to update the webhook + err := database.FromContext(c).CreateHook(h) + if err != nil { + logrus.Errorf("unable to create webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err) + } + }() + + switch h.GetEventAction() { + // if action is rename, go through rename routine + case constants.ActionRenamed: + r, err := renameRepository(h, r, c, m) + if err != nil { + h.SetStatus(constants.StatusFailure) + h.SetError(err.Error()) + + return nil, err + } + + return r, nil + // if action is archived, unarchived, or edited, perform edits to relevant repo fields + case "archived", "unarchived", constants.ActionEdited: + logrus.Debugf("repository action %s for %s", h.GetEventAction(), r.GetFullName()) + // send call to get repository from database + dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + if err != nil { + retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return nil, retErr + } + + // send API call to capture the last hook for the repo + lastHook, err := database.FromContext(c).LastHookForRepo(dbRepo) + if err != nil { + retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return nil, retErr + } + + // set the Number field + if lastHook != nil { + h.SetNumber( + lastHook.GetNumber() + 1, + ) + } + + h.SetRepoID(dbRepo.GetID()) + + // the only edits to a repo that impact Vela are to these three fields + if !strings.EqualFold(dbRepo.GetBranch(), r.GetBranch()) { + dbRepo.SetBranch(r.GetBranch()) + } + + if dbRepo.GetActive() != r.GetActive() { + dbRepo.SetActive(r.GetActive()) + } + + if !reflect.DeepEqual(dbRepo.GetTopics(), r.GetTopics()) { + dbRepo.SetTopics(r.GetTopics()) + } + + // update repo object in the database after applying edits + err = database.FromContext(c).UpdateRepo(dbRepo) + if err != nil { + retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return nil, err + } + + return dbRepo, nil + // all other repo event actions are skippable + default: + return r, nil + } +} + // renameRepository is a helper function that takes the old name of the repo, // queries the database for the repo that matches that name and org, and updates // that repo to its new name in order to preserve it. It also updates the secrets // associated with that repo. -func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) error { +func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) (*library.Repo, error) { logrus.Debugf("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) // get the old name of the repo previousName := r.GetPreviousName() @@ -809,7 +860,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) - return retErr + return nil, retErr } // update the repo name information @@ -828,7 +879,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) - return retErr + return nil, retErr } // update hook object which will be added to DB upon reaching deferred function in PostWebhook @@ -843,7 +894,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types h.SetStatus(constants.StatusFailure) h.SetError(retErr.Error()) - return retErr + return nil, retErr } // set the Number field @@ -856,7 +907,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types // get total number of secrets associated with repository t, err := database.FromContext(c).CountSecretsForRepo(dbR, map[string]interface{}{}) if err != nil { - return fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) } secrets := []*library.Secret{} @@ -865,7 +916,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types for repoSecrets := int64(0); repoSecrets < t; repoSecrets += 100 { s, _, err := database.FromContext(c).ListSecretsForRepo(dbR, map[string]interface{}{}, page, 100) if err != nil { - return fmt.Errorf("unable to get secret list for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to get secret list for repo %s/%s: %w", r.GetOrg(), previousName, err) } secrets = append(secrets, s...) @@ -879,14 +930,14 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types err = database.FromContext(c).UpdateSecret(secret) if err != nil { - return fmt.Errorf("unable to update secret for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to update secret for repo %s/%s: %w", r.GetOrg(), previousName, err) } } // get total number of builds associated with repository t, err = database.FromContext(c).GetRepoBuildCount(dbR, nil) if err != nil { - return fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) + return nil, fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) } builds := []*library.Build{} @@ -895,7 +946,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types for build := int64(0); build < t; build += 100 { b, _, err := database.FromContext(c).GetRepoBuildList(dbR, nil, time.Now().Unix(), 0, page, 100) if err != nil { - return fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err) + return nil, fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err) } builds = append(builds, b...) @@ -911,9 +962,9 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types err = database.FromContext(c).UpdateBuild(build) if err != nil { - return fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err) + return nil, fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err) } } - return nil + return dbR, nil } diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index c61cb0984..cba5e9242 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -185,6 +185,7 @@ func TestNative_EnvironmentSteps(t *testing.T) { "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "", + "VELA_REPO_TOPICS": "", "VELA_REPO_BUILD_LIMIT": "0", "VELA_REPO_CLONE": "", "VELA_REPO_FULL_NAME": "", @@ -333,6 +334,7 @@ func TestNative_EnvironmentServices(t *testing.T) { "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "", + "VELA_REPO_TOPICS": "", "VELA_REPO_BUILD_LIMIT": "0", "VELA_REPO_CLONE": "", "VELA_REPO_FULL_NAME": "", @@ -493,6 +495,7 @@ func TestNative_EnvironmentSecrets(t *testing.T) { "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "", + "VELA_REPO_TOPICS": "", "VELA_REPO_BUILD_LIMIT": "0", "VELA_REPO_CLONE": "", "VELA_REPO_FULL_NAME": "", @@ -541,6 +544,7 @@ func TestNative_environment(t *testing.T) { num64 := int64(num) str := "foo" workspace := "/vela/src/foo/foo/foo" + topics := []string{"cloud", "security"} // push push := "push" // tag @@ -567,36 +571,36 @@ func TestNative_environment(t *testing.T) { 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}, m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + r: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "foo", "VELA_REPO_TOPICS": "cloud,security", "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_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 { 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}, m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + r: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "foo", "VELA_REPO_TOPICS": "cloud,security", "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_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 { 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}, m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + r: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "foo", "VELA_REPO_TOPICS": "cloud,security", "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_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 { 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}, m: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - r: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + r: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, u: &library.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, - want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + want: 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "VELA_REPO_BRANCH": "foo", "VELA_REPO_TOPICS": "cloud,security", "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_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"}, }, } @@ -653,6 +657,7 @@ func Test_client_EnvironmentBuild(t *testing.T) { num := 1 num64 := int64(num) str := "foo" + topics := []string{"cloud", "security"} //workspace := "/vela/src/foo/foo/foo" // push push := "push" @@ -682,29 +687,29 @@ func Test_client_EnvironmentBuild(t *testing.T) { {"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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + repo: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + repo: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + repo: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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}, metadata: &types.Metadata{Database: &types.Database{Driver: str, Host: str}, Queue: &types.Queue{Channel: str, Driver: str, Host: str}, Source: &types.Source{Driver: str, Host: str}, Vela: &types.Vela{Address: str, WebAddress: str}}, - repo: &library.Repo{ID: &num64, UserID: &num64, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, + repo: &library.Repo{ID: &num64, UserID: &num64, 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, AllowPull: &booL, AllowPush: &booL, AllowDeploy: &booL, AllowTag: &booL, AllowComment: &booL}, user: &library.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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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_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"}, + }, 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": "deployment", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TARGET": "production", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_COMMENT": "false", "REPOSITORY_ALLOW_DEPLOY": "false", "REPOSITORY_ALLOW_PULL": "false", "REPOSITORY_ALLOW_PUSH": "false", "REPOSITORY_ALLOW_TAG": "false", "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_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": "deployment", "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/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TARGET": "production", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DEPLOYMENT": "production", "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_COMMENT": "false", "VELA_REPO_ALLOW_DEPLOY": "false", "VELA_REPO_ALLOW_PULL": "false", "VELA_REPO_ALLOW_PUSH": "false", "VELA_REPO_ALLOW_TAG": "false", "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"}, }, } for _, tt := range tests { diff --git a/database/repo/create_test.go b/database/repo/create_test.go index e2ab70417..ac0a86ffa 100644 --- a/database/repo/create_test.go +++ b/database/repo/create_test.go @@ -31,9 +31,9 @@ func TestRepo_Engine_CreateRepo(t *testing.T) { // ensure the mock expects the query _mock.ExpectQuery(`INSERT INTO "repos" -("user_id","hash","org","name","full_name","link","clone","branch","build_limit","timeout","counter","visibility","private","trusted","active","allow_pull","allow_push","allow_deploy","allow_tag","allow_comment","pipeline_type","previous_name","id") -VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23) RETURNING "id"`). - WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). +("user_id","hash","org","name","full_name","link","clone","branch","topics","build_limit","timeout","counter","visibility","private","trusted","active","allow_pull","allow_push","allow_deploy","allow_tag","allow_comment","pipeline_type","previous_name","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24) RETURNING "id"`). + WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). WillReturnRows(_rows) _sqlite := testSqlite(t) diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go index 5e739029c..2f1dee125 100644 --- a/database/repo/get_org_test.go +++ b/database/repo/get_org_test.go @@ -23,14 +23,15 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { _repo.SetFullName("foo/bar") _repo.SetVisibility("public") _repo.SetPipelineType("yaml") + _repo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "repos" WHERE org = $1 AND name = $2 LIMIT 1`).WithArgs("foo", "bar").WillReturnRows(_rows) diff --git a/database/repo/get_test.go b/database/repo/get_test.go index d5fd926be..a1b7a8485 100644 --- a/database/repo/get_test.go +++ b/database/repo/get_test.go @@ -23,14 +23,15 @@ func TestRepo_Engine_GetRepo(t *testing.T) { _repo.SetFullName("foo/bar") _repo.SetVisibility("public") _repo.SetPipelineType("yaml") + _repo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", "") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "repos" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) diff --git a/database/repo/list_org_test.go b/database/repo/list_org_test.go index fdfa80779..b668aff97 100644 --- a/database/repo/list_org_test.go +++ b/database/repo/list_org_test.go @@ -38,6 +38,7 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") _repoOne.SetPipelineType("yaml") + _repoOne.SetTopics([]string{}) _repoTwo := testRepo() _repoTwo.SetID(2) @@ -48,6 +49,7 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _repoTwo.SetFullName("foo/baz") _repoTwo.SetVisibility("public") _repoTwo.SetPipelineType("yaml") + _repoTwo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -60,9 +62,9 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { // create expected name query result in mock _rows = sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). - AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) // ensure the mock expects the name query _mock.ExpectQuery(`SELECT * FROM "repos" WHERE org = $1 ORDER BY name LIMIT 10`).WithArgs("foo").WillReturnRows(_rows) @@ -75,9 +77,9 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { // create expected latest query result in mock _rows = sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). - AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) // ensure the mock expects the latest query _mock.ExpectQuery(`SELECT repos.* FROM "repos" LEFT JOIN (SELECT repos.id, MAX(builds.created) AS latest_build FROM "builds" INNER JOIN repos repos ON builds.repo_id = repos.id WHERE repos.org = $1 GROUP BY "repos"."id") t on repos.id = t.id ORDER BY latest_build DESC NULLS LAST LIMIT 10`).WithArgs("foo").WillReturnRows(_rows) diff --git a/database/repo/list_test.go b/database/repo/list_test.go index 86b9968fe..9e359c40f 100644 --- a/database/repo/list_test.go +++ b/database/repo/list_test.go @@ -23,6 +23,7 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") _repoOne.SetPipelineType("yaml") + _repoOne.SetTopics([]string{}) _repoTwo := testRepo() _repoTwo.SetID(2) @@ -33,6 +34,7 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _repoTwo.SetFullName("bar/foo") _repoTwo.SetVisibility("public") _repoTwo.SetPipelineType("yaml") + _repoTwo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -45,9 +47,9 @@ func TestRepo_Engine_ListRepos(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). - AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "repos"`).WillReturnRows(_rows) diff --git a/database/repo/list_user_test.go b/database/repo/list_user_test.go index 0e1cc8336..a65958c39 100644 --- a/database/repo/list_user_test.go +++ b/database/repo/list_user_test.go @@ -38,6 +38,7 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") _repoOne.SetPipelineType("yaml") + _repoOne.SetTopics([]string{}) _repoTwo := testRepo() _repoTwo.SetID(2) @@ -48,6 +49,7 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _repoTwo.SetFullName("bar/foo") _repoTwo.SetVisibility("public") _repoTwo.SetPipelineType("yaml") + _repoTwo.SetTopics([]string{}) _user := new(library.User) _user.SetID(1) @@ -65,9 +67,9 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { // create expected name query result in mock _rows = sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). - AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) // ensure the mock expects the name query _mock.ExpectQuery(`SELECT * FROM "repos" WHERE user_id = $1 ORDER BY name LIMIT 10`).WithArgs(1).WillReturnRows(_rows) @@ -80,9 +82,9 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { // create expected latest query result in mock _rows = sqlmock.NewRows( - []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). - AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). - AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_pull", "allow_push", "allow_deploy", "allow_tag", "allow_comment", "pipeline_type", "previous_name"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil). + AddRow(2, 1, "baz", "bar", "foo", "bar/foo", "", "", "", "{}", 0, 0, "public", false, false, false, false, false, false, false, false, "yaml", nil) // ensure the mock expects the latest query _mock.ExpectQuery(`SELECT repos.* FROM "repos" LEFT JOIN (SELECT repos.id, MAX(builds.created) AS latest_build FROM "builds" INNER JOIN repos repos ON builds.repo_id = repos.id WHERE repos.user_id = $1 GROUP BY "repos"."id") t on repos.id = t.id ORDER BY latest_build DESC NULLS LAST LIMIT 10`).WithArgs(1).WillReturnRows(_rows) diff --git a/database/repo/table.go b/database/repo/table.go index fc55a4a56..1df91afff 100644 --- a/database/repo/table.go +++ b/database/repo/table.go @@ -21,6 +21,7 @@ repos ( link VARCHAR(1000), clone VARCHAR(1000), branch VARCHAR(250), + topics VARCHAR(1020), build_limit INTEGER, timeout INTEGER, counter INTEGER, @@ -53,6 +54,7 @@ repos ( link TEXT, clone TEXT, branch TEXT, + topics TEXT, build_limit INTEGER, timeout INTEGER, counter INTEGER, diff --git a/database/repo/update_test.go b/database/repo/update_test.go index db29a91dd..35d4b74bb 100644 --- a/database/repo/update_test.go +++ b/database/repo/update_test.go @@ -28,9 +28,9 @@ func TestRepo_Engine_UpdateRepo(t *testing.T) { // ensure the mock expects the query _mock.ExpectExec(`UPDATE "repos" -SET "user_id"=$1,"hash"=$2,"org"=$3,"name"=$4,"full_name"=$5,"link"=$6,"clone"=$7,"branch"=$8,"build_limit"=$9,"timeout"=$10,"counter"=$11,"visibility"=$12,"private"=$13,"trusted"=$14,"active"=$15,"allow_pull"=$16,"allow_push"=$17,"allow_deploy"=$18,"allow_tag"=$19,"allow_comment"=$20,"pipeline_type"=$21,"previous_name"=$22 -WHERE "id" = $23`). - WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). +SET "user_id"=$1,"hash"=$2,"org"=$3,"name"=$4,"full_name"=$5,"link"=$6,"clone"=$7,"branch"=$8,"topics"=$9,"build_limit"=$10,"timeout"=$11,"counter"=$12,"visibility"=$13,"private"=$14,"trusted"=$15,"active"=$16,"allow_pull"=$17,"allow_push"=$18,"allow_deploy"=$19,"allow_tag"=$20,"allow_comment"=$21,"pipeline_type"=$22,"previous_name"=$23 +WHERE "id" = $24`). + WithArgs(1, AnyArgument{}, "foo", "bar", "foo/bar", nil, nil, nil, AnyArgument{}, AnyArgument{}, AnyArgument{}, AnyArgument{}, "public", false, false, false, false, false, false, false, false, "yaml", "oldName", 1). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) diff --git a/go.mod b/go.mod index b7e3765ea..3822e4315 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c + github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 diff --git a/go.sum b/go.sum index cdb1e7d1e..9b87a5147 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,8 @@ github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyh github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c h1:lnCL1knUGvgZQG4YBHSs/CZnxNBfqFUBlGhyq9LO9uk= -github.com/go-vela/types v0.18.2-0.20230321015315-6c723879639c/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 h1:fkxgJa0ispCsLsUHaEImsLPFUhFRrAQPoA3a1XlARxQ= +github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index eac2daeee..d812e1ba7 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -48,6 +48,7 @@ func TestRepo_Establish(t *testing.T) { want.SetLink("") want.SetClone("") want.SetBranch("") + want.SetTopics([]string{}) want.SetBuildLimit(0) want.SetTimeout(0) want.SetCounter(0) diff --git a/scm/github/repo.go b/scm/github/repo.go index de39ca07b..d7019359b 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -471,6 +471,7 @@ func toLibraryRepo(gr github.Repository) *library.Repo { Link: gr.HTMLURL, Clone: gr.CloneURL, Branch: gr.DefaultBranch, + Topics: &gr.Topics, Private: gr.Private, } } diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 6b56b6903..9c30ac5ab 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1026,6 +1026,7 @@ func TestGithub_GetRepo(t *testing.T) { want.SetClone("https://github.com/octocat/Hello-World.git") want.SetBranch("master") want.SetPrivate(false) + want.SetTopics([]string{"octocat", "atom", "electron", "api"}) client, _ := NewTest(s.URL) @@ -1188,6 +1189,7 @@ func TestGithub_ListUserRepos(t *testing.T) { r.SetClone("https://github.com/octocat/Hello-World.git") r.SetBranch("master") r.SetPrivate(false) + r.SetTopics([]string{"octocat", "atom", "electron", "api"}) want := []*library.Repo{r} diff --git a/scm/github/testdata/hooks/repository_edited.json b/scm/github/testdata/hooks/repository_edited.json index cb923aeaf..c9a41a1a1 100644 --- a/scm/github/testdata/hooks/repository_edited.json +++ b/scm/github/testdata/hooks/repository_edited.json @@ -97,7 +97,11 @@ "forks": 0, "open_issues": 2, "watchers": 0, - "default_branch": "main" + "default_branch": "main", + "topics": [ + "cloud", + "security" + ] }, "enterprise": { "id": 1, diff --git a/scm/github/webhook.go b/scm/github/webhook.go index d590eec12..3d86574ea 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -138,6 +138,8 @@ func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (* r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) + // uncomment this line when next version (>v51.0.0) of go-github is released + // r.SetTopics(repo.Topics) // convert payload to library build b := new(library.Build) @@ -234,6 +236,7 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) + r.SetTopics(repo.Topics) // convert payload to library build b := new(library.Build) @@ -300,6 +303,7 @@ func (c *client) processDeploymentEvent(h *library.Hook, payload *github.Deploym r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) + r.SetTopics(repo.Topics) // convert payload to library build b := new(library.Build) @@ -401,6 +405,7 @@ func (c *client) processIssueCommentEvent(h *library.Hook, payload *github.Issue r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) + r.SetTopics(repo.Topics) // convert payload to library build b := new(library.Build) @@ -451,6 +456,7 @@ func (c *client) processRepositoryEvent(h *library.Hook, payload *github.Reposit r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) r.SetActive(!repo.GetArchived()) + r.SetTopics(repo.Topics) // if action is renamed, then get the previous name from payload if payload.GetAction() == "renamed" { diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 437299070..08d1a0c0e 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -222,6 +222,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) wantBuild := new(library.Build) wantBuild.SetEvent("pull_request") @@ -392,6 +393,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) wantBuild := new(library.Build) wantBuild.SetEvent("deployment") @@ -511,6 +513,7 @@ func TestGithub_ProcessWebhook_Deployment_Commit(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) wantBuild := new(library.Build) wantBuild.SetEvent("deployment") @@ -767,6 +770,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) wantBuild := new(library.Build) wantBuild.SetEvent("comment") @@ -843,6 +847,7 @@ func TestGithub_ProcessWebhook_IssueComment_Created(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) wantBuild := new(library.Build) wantBuild.SetEvent("comment") @@ -976,6 +981,7 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { wantRepo.SetBranch("master") wantRepo.SetPrivate(false) wantRepo.SetPreviousName("Hello-Old-World") + wantRepo.SetTopics(nil) want := &types.Webhook{ Comment: "", @@ -1039,6 +1045,7 @@ func TestGitHub_ProcessWebhook_RepositoryArchived(t *testing.T) { wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) want := &types.Webhook{ Comment: "", @@ -1101,6 +1108,7 @@ func TestGitHub_ProcessWebhook_RepositoryEdited(t *testing.T) { wantRepo.SetLink("https://octocoders.github.io/Codertocat/Hello-World") wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") wantRepo.SetBranch("main") + wantRepo.SetTopics([]string{"cloud", "security"}) wantRepo.SetPrivate(false) want := &types.Webhook{ @@ -1165,6 +1173,7 @@ func TestGitHub_ProcessWebhook_Repository(t *testing.T) { wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics(nil) want := &types.Webhook{ Comment: "", From ae034bfd6dbf80a5dfb353cde076222b7f8b7be0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 13:51:40 -0500 Subject: [PATCH 202/298] fix(deps): update module gorm.io/gorm to v1.25.0 (#818) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3822e4315..ebd97be3d 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.4.8 gorm.io/driver/sqlite v1.4.4 - gorm.io/gorm v1.24.5 + gorm.io/gorm v1.25.0 k8s.io/apimachinery v0.26.2 ) diff --git a/go.sum b/go.sum index 9b87a5147..30432c879 100644 --- a/go.sum +++ b/go.sum @@ -816,8 +816,8 @@ gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE= -gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= +gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 00e378dd33ec19396f7c3b59c4d9c744244f7363 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 17 Apr 2023 12:59:40 -0600 Subject: [PATCH 203/298] enhance(webhook)!: verify repo owner has at least write access to SCM repo (#811) * enhance(webhook): verify repo owner has at least write access to SCM repo * replace perm check with error check * one database call is all we need * cuddle time --- api/webhook.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/api/webhook.go b/api/webhook.go index 4c657425e..bbfb90ac3 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -310,6 +310,18 @@ func PostWebhook(c *gin.Context) { return } + // confirm current repo owner has at least write access to repo (needed for status update later) + _, err = scm.FromContext(c).RepoAccess(u, u.GetToken(), r.GetOrg(), r.GetName()) + if err != nil { + retErr := fmt.Errorf("unable to publish build to queue: repository owner %s no longer has write access to repository %s", u.GetName(), r.GetFullName()) + util.HandleError(c, http.StatusUnauthorized, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return + } + // create SQL filters for querying pending and running builds for repo filters := map[string]interface{}{ "status": []string{constants.StatusPending, constants.StatusRunning}, From f5fe34aabbde01725625fb687106a44f454b7c8a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 14:05:13 -0500 Subject: [PATCH 204/298] fix(deps): update module github.com/prometheus/client_golang to v1.15.0 (#817) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 14 ++++---- go.sum | 109 ++++++++------------------------------------------------- 2 files changed, 22 insertions(+), 101 deletions(-) diff --git a/go.mod b/go.mod index ebd97be3d..8cadf56c3 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/hashicorp/vault/api v1.9.0 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_golang v1.15.0 github.com/redis/go-redis/v9 v9.0.2 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.4 @@ -62,7 +62,7 @@ require ( github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/goccy/go-json v0.10.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -88,7 +88,7 @@ require ( github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/microcosm-cc/bluemonday v1.0.22 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -98,8 +98,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect @@ -111,11 +111,11 @@ require ( golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.80.1 // indirect diff --git a/go.sum b/go.sum index 30432c879..65fa94049 100644 --- a/go.sum +++ b/go.sum @@ -54,11 +54,6 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= @@ -70,8 +65,6 @@ github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzH github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -85,8 +78,6 @@ github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZX github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -127,14 +118,6 @@ github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH8 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -146,13 +129,11 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 h1:fkxgJa0ispCsLsUHaEImsLPFUhFRrAQPoA3a1XlARxQ= github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -183,8 +164,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.7.1-0.20190322064113-39e2c31b7ca3/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= @@ -285,28 +266,19 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -327,8 +299,8 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA= github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -346,48 +318,25 @@ github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -400,9 +349,6 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs= @@ -410,7 +356,6 @@ github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -450,7 +395,6 @@ go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfG go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -498,7 +442,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -506,7 +449,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -529,9 +471,6 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -547,8 +486,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -565,13 +502,10 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -580,7 +514,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -594,8 +527,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -603,22 +534,18 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -631,7 +558,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= @@ -786,12 +712,10 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -799,10 +723,7 @@ gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 54f3f61ea50845d2ef62ffceaabc2d2b2e04da63 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:06:55 -0500 Subject: [PATCH 205/298] fix(deps): update module gorm.io/driver/postgres to v1.5.0 (#787) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 8cadf56c3..a94d8d5e4 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( golang.org/x/oauth2 v0.5.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 - gorm.io/driver/postgres v1.4.8 + gorm.io/driver/postgres v1.5.0 gorm.io/driver/sqlite v1.4.4 gorm.io/gorm v1.25.0 k8s.io/apimachinery v0.26.2 diff --git a/go.sum b/go.sum index 65fa94049..2e4e9d370 100644 --- a/go.sum +++ b/go.sum @@ -731,12 +731,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.4.8 h1:NDWizaclb7Q2aupT0jkwK8jx1HVCNzt+PQ8v/VnxviA= -gorm.io/driver/postgres v1.4.8/go.mod h1:O9MruWGNLUBUWVYfWuBClpf3HeGjOoybY0SNmCs3wsw= +gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= +gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From ad6fd58db086c7b6e99d7c81e00ca634adb68e5b Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 17 Apr 2023 15:17:55 -0600 Subject: [PATCH 206/298] chore(deps): update to jwt v5, remove iat workaround (#821) * chore(deps): update to jwt v5, remove iat workaround * go mod tidy --- cmd/vela-server/token.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- internal/token/compose_test.go | 2 +- internal/token/manager.go | 2 +- internal/token/mint.go | 2 +- internal/token/parse.go | 11 ++--------- internal/token/parse_test.go | 8 ++++---- internal/token/refresh_test.go | 2 +- router/middleware/auth/auth.go | 2 +- router/middleware/claims/claims_test.go | 12 ++++++------ router/middleware/claims/context_test.go | 2 +- router/middleware/perm/perm_test.go | 2 +- router/middleware/pipeline/pipeline_test.go | 2 +- router/middleware/user/user_test.go | 2 +- 15 files changed, 25 insertions(+), 32 deletions(-) diff --git a/cmd/vela-server/token.go b/cmd/vela-server/token.go index 2f406a16b..298ef283a 100644 --- a/cmd/vela-server/token.go +++ b/cmd/vela-server/token.go @@ -5,7 +5,7 @@ package main import ( - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/sirupsen/logrus" diff --git a/go.mod b/go.mod index a94d8d5e4..90333a3f0 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 - github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v50 v50.1.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 2e4e9d370..a183b997a 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,8 @@ github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= diff --git a/internal/token/compose_test.go b/internal/token/compose_test.go index 75f113e77..ff01b543d 100644 --- a/internal/token/compose_test.go +++ b/internal/token/compose_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - jwt "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v5" ) func TestToken_Compose(t *testing.T) { diff --git a/internal/token/manager.go b/internal/token/manager.go index 71d82fb49..22daf3636 100644 --- a/internal/token/manager.go +++ b/internal/token/manager.go @@ -7,7 +7,7 @@ package token import ( "time" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) type Manager struct { diff --git a/internal/token/mint.go b/internal/token/mint.go index 6f1a23941..7d2ff8f64 100644 --- a/internal/token/mint.go +++ b/internal/token/mint.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) // Claims struct is an extension of the JWT standard claims. It diff --git a/internal/token/parse.go b/internal/token/parse.go index 4cae4e986..ad5423ee6 100644 --- a/internal/token/parse.go +++ b/internal/token/parse.go @@ -7,7 +7,7 @@ package token import ( "errors" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" ) // ParseToken scans the signed JWT token as a string and extracts @@ -21,10 +21,7 @@ func (tm *Manager) ParseToken(token string) (*Claims, error) { var claims = new(Claims) // create a new JWT parser - p := &jwt.Parser{ - // explicitly only allow these signing methods - ValidMethods: []string{jwt.SigningMethodHS256.Name}, - } + p := jwt.NewParser(jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Name})) // parse and validate given token tkn, err := p.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) { @@ -34,10 +31,6 @@ func (tm *Manager) ParseToken(token string) (*Claims, error) { claims = t.Claims.(*Claims) name := claims.Subject - // according to JWT, the iat field is optional for security purposes and is purely informational. - // setting it to nil avoids any worries of race conditions. - claims.IssuedAt = nil - // check if subject has a value in claims; // we can save a db lookup attempt if len(name) == 0 { diff --git a/internal/token/parse_test.go b/internal/token/parse_test.go index 6c9076515..c7dc2422f 100644 --- a/internal/token/parse_test.go +++ b/internal/token/parse_test.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - jwt "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v5" ) func TestTokenManager_ParseToken(t *testing.T) { @@ -51,7 +51,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.UserAccessTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: u.GetName(), - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), }, }, @@ -69,7 +69,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.UserRefreshTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: u.GetName(), - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 30)), }, }, @@ -89,7 +89,7 @@ func TestTokenManager_ParseToken(t *testing.T) { TokenType: constants.WorkerBuildTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "worker", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 90)), }, }, diff --git a/internal/token/refresh_test.go b/internal/token/refresh_test.go index dda71cb4a..a1873f01e 100644 --- a/internal/token/refresh_test.go +++ b/internal/token/refresh_test.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/server/database/sqlite" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - jwt "github.com/golang-jwt/jwt/v4" + jwt "github.com/golang-jwt/jwt/v5" ) func TestTokenManager_Refresh(t *testing.T) { diff --git a/router/middleware/auth/auth.go b/router/middleware/auth/auth.go index 76291a3cb..968ceabfb 100644 --- a/router/middleware/auth/auth.go +++ b/router/middleware/auth/auth.go @@ -10,7 +10,7 @@ import ( "github.com/go-vela/types/constants" - "github.com/golang-jwt/jwt/v4/request" + "github.com/golang-jwt/jwt/v5/request" ) // RetrieveAccessToken gets the passed in access token from the header in the request. diff --git a/router/middleware/claims/claims_test.go b/router/middleware/claims/claims_test.go index 8447ff009..8934a4afd 100644 --- a/router/middleware/claims/claims_test.go +++ b/router/middleware/claims/claims_test.go @@ -16,7 +16,7 @@ import ( "github.com/go-vela/server/database" "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/internal/token" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -33,7 +33,7 @@ func TestClaims_Retrieve(t *testing.T) { IsActive: true, RegisteredClaims: jwt.RegisteredClaims{ Subject: "octocat", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 1)), }, } @@ -90,7 +90,7 @@ func TestClaims_Establish(t *testing.T) { IsActive: true, RegisteredClaims: jwt.RegisteredClaims{ Subject: "foo", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 5)), }, }, @@ -110,7 +110,7 @@ func TestClaims_Establish(t *testing.T) { Repo: "foo/bar", RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Minute * 35)), }, }, @@ -130,7 +130,7 @@ func TestClaims_Establish(t *testing.T) { TokenType: constants.WorkerAuthTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerAuthTokenDuration)), }, }, @@ -148,7 +148,7 @@ func TestClaims_Establish(t *testing.T) { TokenType: constants.WorkerRegisterTokenType, RegisteredClaims: jwt.RegisteredClaims{ Subject: "host", - IssuedAt: nil, + IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(tm.WorkerRegisterTokenDuration)), }, }, diff --git a/router/middleware/claims/context_test.go b/router/middleware/claims/context_test.go index 54713010c..b29fd739c 100644 --- a/router/middleware/claims/context_test.go +++ b/router/middleware/claims/context_test.go @@ -10,7 +10,7 @@ import ( "github.com/go-vela/server/internal/token" "github.com/go-vela/types/constants" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/gin-gonic/gin" ) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 61ebf596e..755db4a12 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -16,7 +16,7 @@ import ( "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/gin-gonic/gin" "github.com/go-vela/server/database" diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index 090a3b3f5..ec4e809ed 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -28,7 +28,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/urfave/cli/v2" ) diff --git a/router/middleware/user/user_test.go b/router/middleware/user/user_test.go index 46034914b..7561f8a7d 100644 --- a/router/middleware/user/user_test.go +++ b/router/middleware/user/user_test.go @@ -18,7 +18,7 @@ import ( "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/scm" "github.com/go-vela/server/scm/github" - "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v5" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" From 7e020e32ae806c0ced5fd26ea34da28974a3f45b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 09:43:30 -0500 Subject: [PATCH 207/298] fix(deps): update deps (patch) (#786) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 32 ++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 90333a3f0..5327000bf 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,10 @@ go 1.19 require ( github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/Masterminds/semver/v3 v3.2.0 + github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/alicebob/miniredis/v2 v2.30.0 - github.com/aws/aws-sdk-go v1.44.211 + github.com/alicebob/miniredis/v2 v2.30.1 + github.com/aws/aws-sdk-go v1.44.245 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 @@ -26,9 +26,9 @@ require ( github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.15.0 - github.com/redis/go-redis/v9 v9.0.2 + github.com/redis/go-redis/v9 v9.0.3 github.com/sirupsen/logrus v1.9.0 - github.com/spf13/afero v1.9.4 + github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.24.4 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 golang.org/x/oauth2 v0.5.0 @@ -107,7 +107,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.9 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 // indirect + github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.6.0 // indirect golang.org/x/net v0.7.0 // indirect diff --git a/go.sum b/go.sum index a183b997a..a37349c35 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,9 @@ github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYI github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= @@ -58,18 +59,18 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M= -github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= +github.com/alicebob/miniredis/v2 v2.30.1 h1:HM1rlQjq1bm9yQcsawJqSZBJ9AYgxvjkMsNtddh90+g= +github.com/alicebob/miniredis/v2 v2.30.1/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzHK4= -github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.245 h1:KtY2s4q31/kn33AdV63R5t77mdxsI7rq3YT7Mgo805M= +github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ= -github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8= +github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= @@ -337,8 +338,8 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= -github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu4k= +github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= @@ -351,8 +352,8 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs= -github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -383,8 +384,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191213034115-f46add6fdb5c/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= -github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= -github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -402,7 +403,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -471,6 +472,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -535,6 +537,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -558,6 +561,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= From c80300aedf4c7f8feb3090582719b2921af35683 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:20:39 -0500 Subject: [PATCH 208/298] fix(deps): update module github.com/google/go-github/v50 to v50.2.0 (#792) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 12 +++++++----- go.sum | 24 ++++++++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 5327000bf..1ced9d374 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 - github.com/google/go-github/v50 v50.1.0 + github.com/google/go-github/v50 v50.2.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.24.4 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 - golang.org/x/oauth2 v0.5.0 + golang.org/x/oauth2 v0.6.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.5.0 @@ -42,6 +42,7 @@ require ( require ( github.com/Masterminds/goutils v1.1.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect @@ -51,6 +52,7 @@ require ( github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudflare/circl v1.1.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect @@ -109,10 +111,10 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.6.0 // indirect - golang.org/x/net v0.7.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index a37349c35..b7584be05 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0 github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -73,6 +75,7 @@ github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -88,6 +91,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -184,8 +189,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v50 v50.1.0 h1:hMUpkZjklC5GJ+c3GquSqOP/T4BNsB7XohaPhtMOzRk= -github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= +github.com/google/go-github/v50 v50.2.0 h1:j2FyongEHlO9nxXLc+LP3wuBSVU9mVxfpdYUexMpIfk= +github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -405,8 +410,9 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -477,8 +483,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -488,8 +494,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -540,6 +546,7 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -564,8 +571,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 20e10f572f3a19a17be077b9eb9994c3f6cffdca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:30:24 -0500 Subject: [PATCH 209/298] chore(deps): update actions/setup-go action to v4 (#789) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/reviewdog.yml | 4 ++-- .github/workflows/spec.yml | 2 +- .github/workflows/test.yml | 2 +- .github/workflows/validate.yml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b3324deb..bdbb9a8ca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 02f90d774..fc792032f 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -20,7 +20,7 @@ jobs: fetch-depth: 0 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a8ce50154..f90fb83b0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: fetch-depth: 0 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index e403fbb13..0a0027c70 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index e380b1fb7..32a3211be 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e976579af..f3cf03420 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index f866fc839..b2dec4a9d 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v3 - name: install go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: # use version from go.mod file go-version-file: 'go.mod' From 98808aebd2ca61693452f4e064d75d9aea9085e0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:37:24 -0500 Subject: [PATCH 210/298] fix(deps): update module github.com/urfave/cli/v2 to v2.25.1 (#803) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1ced9d374..d49882f29 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/redis/go-redis/v9 v9.0.3 github.com/sirupsen/logrus v1.9.0 github.com/spf13/afero v1.9.5 - github.com/urfave/cli/v2 v2.24.4 + github.com/urfave/cli/v2 v2.25.1 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 golang.org/x/oauth2 v0.6.0 gopkg.in/square/go-jose.v2 v2.6.0 diff --git a/go.sum b/go.sum index b7584be05..146f8ce31 100644 --- a/go.sum +++ b/go.sum @@ -378,8 +378,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU= -github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw= +github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= From 7a0afdd94a643649907cc33f623d180a15f63845 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:43:15 -0500 Subject: [PATCH 211/298] fix(deps): update module golang.org/x/oauth2 to v0.7.0 (#804) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index d49882f29..6bc277348 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.25.1 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 - golang.org/x/oauth2 v0.6.0 + golang.org/x/oauth2 v0.7.0 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.5.0 @@ -112,9 +112,9 @@ require ( github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index 146f8ce31..7121dbdb8 100644 --- a/go.sum +++ b/go.sum @@ -483,8 +483,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -494,8 +494,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -554,8 +554,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -572,8 +572,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 3b38779f0cec879df6319ef5c163923b5b8cc983 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:51:03 -0500 Subject: [PATCH 212/298] fix(deps): update module github.com/google/go-github/v50 to v51 (#805) --- compiler/native/compile_test.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/github_test.go | 2 +- compiler/registry/github/template.go | 2 +- go.mod | 2 +- go.sum | 5 +++-- scm/github/access.go | 2 +- scm/github/authentication.go | 2 +- scm/github/changeset.go | 2 +- scm/github/deployment.go | 2 +- scm/github/github.go | 2 +- scm/github/github_test.go | 2 +- scm/github/repo.go | 2 +- scm/github/webhook.go | 2 +- 14 files changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 0dcb8e1e3..d1661278a 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/raw" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" "testing" "time" diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index f6d062898..f58d49f33 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -9,7 +9,7 @@ import ( "net/url" "strings" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index a3225c357..d5dcf02b6 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index d867ec929..fd62b7ee7 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // Template captures the templated pipeline configuration from the GitHub repo. diff --git a/go.mod b/go.mod index 6bc277348..cfed7db2e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 - github.com/google/go-github/v50 v50.2.0 + github.com/google/go-github/v51 v51.0.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 diff --git a/go.sum b/go.sum index 7121dbdb8..9d0352dd2 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,9 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v50 v50.2.0 h1:j2FyongEHlO9nxXLc+LP3wuBSVU9mVxfpdYUexMpIfk= -github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q= +github.com/google/go-github/v51 v51.0.0 h1:KCjsbgPV28VoRftdP+K2mQL16jniUsLAJknsOVKwHyU= +github.com/google/go-github/v51 v51.0.0/go.mod h1:kZj/rn/c1lSUbr/PFWl2hhusPV7a5XNYKcwPrd5L3Us= + github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/scm/github/access.go b/scm/github/access.go index e9a276662..fc86d3339 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // OrgAccess captures the user's access level for an org. diff --git a/scm/github/authentication.go b/scm/github/authentication.go index 23f21eb4a..72f4354e0 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -14,7 +14,7 @@ import ( "github.com/go-vela/server/random" "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // Authorize uses the given access token to authorize the user. diff --git a/scm/github/changeset.go b/scm/github/changeset.go index 5c46960d8..e5de2817f 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // Changeset captures the list of files changed for a commit. diff --git a/scm/github/deployment.go b/scm/github/deployment.go index 6617d1bf9..6f0cc60a9 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/raw" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // GetDeployment gets a deployment from the GitHub repo. diff --git a/scm/github/github.go b/scm/github/github.go index 2bad8eca3..bff19e2a3 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" "github.com/sirupsen/logrus" "golang.org/x/oauth2" diff --git a/scm/github/github_test.go b/scm/github/github_test.go index be1e084a0..cf9d4632e 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" "golang.org/x/oauth2" ) diff --git a/scm/github/repo.go b/scm/github/repo.go index d7019359b..3f57b1103 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // ConfigBackoff is a wrapper for Config that will retry five times if the function diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 3d86574ea..d79a11922 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -19,7 +19,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v50/github" + "github.com/google/go-github/v51/github" ) // ProcessWebhook parses the webhook from a repo. From 3fd62153dd5473b22631d4982db2aaad4b99a8af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:00:58 -0500 Subject: [PATCH 213/298] fix(deps): update module k8s.io/apimachinery to v0.27.1 (#819) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index cfed7db2e..a8ec48972 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( gorm.io/driver/postgres v1.5.0 gorm.io/driver/sqlite v1.4.4 gorm.io/gorm v1.25.0 - k8s.io/apimachinery v0.26.2 + k8s.io/apimachinery v0.27.1 ) require ( @@ -120,5 +120,5 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/klog/v2 v2.90.1 // indirect ) diff --git a/go.sum b/go.sum index 9d0352dd2..cf8c1df64 100644 --- a/go.sum +++ b/go.sum @@ -191,7 +191,6 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v51 v51.0.0 h1:KCjsbgPV28VoRftdP+K2mQL16jniUsLAJknsOVKwHyU= github.com/google/go-github/v51 v51.0.0/go.mod h1:kZj/rn/c1lSUbr/PFWl2hhusPV7a5XNYKcwPrd5L3Us= - github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -759,10 +758,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= -k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= +k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= From 3fec46cbef8ae8224d7cad31680e96e4b5513498 Mon Sep 17 00:00:00 2001 From: Nick Hackman Date: Tue, 18 Apr 2023 15:15:48 -0400 Subject: [PATCH 214/298] fix(compiler)!: webhook payload containing message with special characters causes failure (#793) * fix(compiler): update envsubst to v2 Use the implementation made upstream in https://github.com/drone/envsubst/pull/27 to fix escape sequence handling to prevent yaml parsing to fail due to invalid escape sequences. Issue: https://github.com/go-vela/community/issues/702 * test(compiler): handle escape sequences * chore: use latest go-vela/types --------- Co-authored-by: Jordan Brockopp Co-authored-by: Jacob Floyd Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> Co-authored-by: NickHackman --- compiler/native/substitute.go | 2 +- compiler/native/substitute_test.go | 24 ++++++++++++++++++++++++ go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/compiler/native/substitute.go b/compiler/native/substitute.go index fcfd2b263..402347aef 100644 --- a/compiler/native/substitute.go +++ b/compiler/native/substitute.go @@ -10,7 +10,7 @@ import ( "github.com/buildkite/yaml" - "github.com/drone/envsubst" + "github.com/drone/envsubst/v2" types "github.com/go-vela/types/yaml" ) diff --git a/compiler/native/substitute_test.go b/compiler/native/substitute_test.go index da27378ac..fc0718eb4 100644 --- a/compiler/native/substitute_test.go +++ b/compiler/native/substitute_test.go @@ -235,6 +235,30 @@ func Test_client_SubstituteSteps(t *testing.T) { }, wantErr: false, }, + { + name: "step contains escape sequences", + args: args{ + steps: yaml.StepSlice{ + { + Name: "sample", + Environment: map[string]string{ + "BUILD_MESSAGE": "`\\`\r", + "VELA_BUILD_MESSAGE": "`\\`\r", + }, + }, + }, + }, + want: yaml.StepSlice{ + { + Name: "sample", + Environment: map[string]string{ + "BUILD_MESSAGE": "`\\`\r", + "VELA_BUILD_MESSAGE": "`\\`\r", + }, + }, + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/go.mod b/go.mod index a8ec48972..615ff436d 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,10 @@ require ( github.com/alicebob/miniredis/v2 v2.30.1 github.com/aws/aws-sdk-go v1.44.245 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 - github.com/drone/envsubst v1.0.3 + github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 + github.com/go-vela/types v0.19.0-rc1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v51 v51.0.0 @@ -86,12 +86,12 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.7 // indirect + github.com/lib/pq v1.10.8 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microcosm-cc/bluemonday v1.0.22 // indirect + github.com/microcosm-cc/bluemonday v1.0.23 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/go.sum b/go.sum index cf8c1df64..cf07c5c14 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= -github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= +github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 h1:7QPwrLT79GlD5sizHf27aoY2RTvw62mO6x7mxkScNk0= +github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -136,8 +136,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5 h1:fkxgJa0ispCsLsUHaEImsLPFUhFRrAQPoA3a1XlARxQ= -github.com/go-vela/types v0.18.2-0.20230407145744-676c45c911b5/go.mod h1:6MzMhLaXKSZ9wiJveieqnBd2+4ZMS7yv7+POGSITyS8= +github.com/go-vela/types v0.19.0-rc1 h1:/l6l3DgqpifDlq30MMunu2V9bVD55vCDTkLSreUrs5k= +github.com/go-vela/types v0.19.0-rc1/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -291,8 +291,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= +github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -307,8 +307,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microcosm-cc/bluemonday v1.0.22 h1:p2tT7RNzRdCi0qmwxG+HbqD6ILkmwter1ZwVZn1oTxA= -github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= +github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= From 2913b6d7ac9699c93290c297ed0c8e72e1d5afe5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 19 Apr 2023 08:50:04 -0600 Subject: [PATCH 215/298] fix(scm): handle new go-github validation changes and ensure correct number for init hook (#822) * fix(scm): handle new go-github validation changes and ensure correct number for init hook * call validate from body rather than validate --- api/repo/create.go | 12 ++++++++---- api/repo/repair.go | 11 ++++++++++- scm/github/repo.go | 4 ++-- scm/github/repo_test.go | 2 +- scm/github/webhook.go | 9 ++++++++- scm/service.go | 2 +- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/api/repo/create.go b/api/repo/create.go index b1abe89de..295fe2b74 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -238,11 +238,15 @@ func CreateRepo(c *gin.Context) { r.SetHash(dbRepo.GetHash()) } - hook := new(library.Hook) + h := new(library.Hook) + if err == nil { + h, _ = database.FromContext(c).LastHookForRepo(dbRepo) + } + // check if we should create the webhook if c.Value("webhookvalidation").(bool) { // send API call to create the webhook - hook, _, err = scm.FromContext(c).Enable(u, r) + h, _, err = scm.FromContext(c).Enable(u, r, h) if err != nil { retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) @@ -300,9 +304,9 @@ func CreateRepo(c *gin.Context) { // create init hook in the DB after repo has been added in order to capture its ID if c.Value("webhookvalidation").(bool) { // update initialization hook - hook.SetRepoID(r.GetID()) + h.SetRepoID(r.GetID()) // create first hook for repo in the database - err = database.FromContext(c).CreateHook(hook) + err = database.FromContext(c).CreateHook(h) if err != nil { retErr := fmt.Errorf("unable to create initialization webhook for %s: %w", r.GetFullName(), err) diff --git a/api/repo/repair.go b/api/repo/repair.go index 0a5b7022a..424a7c0c1 100644 --- a/api/repo/repair.go +++ b/api/repo/repair.go @@ -77,8 +77,17 @@ func RepairRepo(c *gin.Context) { return } + hook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to get last hook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // send API call to create the webhook - hook, _, err := scm.FromContext(c).Enable(u, r) + hook, _, err = scm.FromContext(c).Enable(u, r, hook) if err != nil { retErr := fmt.Errorf("unable to create webhook for %s: %w", r.GetFullName(), err) diff --git a/scm/github/repo.go b/scm/github/repo.go index 3f57b1103..7ecd53341 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -151,7 +151,7 @@ func (c *client) Disable(u *library.User, org, name string) error { } // Enable activates a repo by creating the webhook. -func (c *client) Enable(u *library.User, r *library.Repo) (*library.Hook, string, error) { +func (c *client) Enable(u *library.User, r *library.Repo, h *library.Hook) (*library.Hook, string, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -200,7 +200,7 @@ func (c *client) Enable(u *library.User, r *library.Repo) (*library.Hook, string webhook.SetSourceID(r.GetName() + "-" + eventInitialize) webhook.SetCreated(hookInfo.GetCreatedAt().Unix()) webhook.SetEvent(eventInitialize) - webhook.SetNumber(1) + webhook.SetNumber(h.GetNumber() + 1) switch resp.StatusCode { case http.StatusUnprocessableEntity: diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 9c30ac5ab..9f95fb12a 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -621,7 +621,7 @@ func TestGithub_Enable(t *testing.T) { client, _ := NewTest(s.URL) // run test - got, _, err := client.Enable(u, r) + got, _, err := client.Enable(u, r, new(library.Hook)) if resp.Code != http.StatusOK { t.Errorf("Enable returned %v, want %v", resp.Code, http.StatusOK) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index d79a11922..11b317b33 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "mime" "net/http" "strconv" "strings" @@ -47,7 +48,13 @@ func (c *client) ProcessWebhook(request *http.Request) (*types.Webhook, error) { h.SetHost(request.Header.Get("X-GitHub-Enterprise-Host")) } - payload, err := github.ValidatePayload(request, nil) + // get content type + contentType, _, err := mime.ParseMediaType(request.Header.Get("Content-Type")) + if err != nil { + return nil, err + } + + payload, err := github.ValidatePayloadFromBody(contentType, request.Body, "", nil) if err != nil { return &types.Webhook{Hook: h}, nil } diff --git a/scm/service.go b/scm/service.go index 5c42105ba..bb0c0e275 100644 --- a/scm/service.go +++ b/scm/service.go @@ -98,7 +98,7 @@ type Service interface { Disable(*library.User, string, string) error // Enable defines a function that activates // a repo by creating the webhook. - Enable(*library.User, *library.Repo) (*library.Hook, string, error) + Enable(*library.User, *library.Repo, *library.Hook) (*library.Hook, string, error) // Update defines a function that updates // a webhook for a specified repo. Update(*library.User, *library.Repo, int64) error From 519876b0fad10de578c03a3bde4613cab04f2384 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 20 Apr 2023 13:35:17 -0600 Subject: [PATCH 216/298] fix(webhook): relocate topics & branch setting to avoid overwrite (#824) --- api/webhook.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/api/webhook.go b/api/webhook.go index bbfb90ac3..76f9c45c4 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -201,16 +201,6 @@ func PostWebhook(c *gin.Context) { b.SetRepoID(repo.GetID()) h.SetRepoID(repo.GetID()) - // update repo fields with any changes (necessary for repos enabled before repository event handling) - // TODO: eventually remove this in favor of some sync scripting? - if len(r.GetTopics()) != 0 { - repo.SetTopics(r.GetTopics()) - } - - if !strings.EqualFold(repo.GetBranch(), r.GetBranch()) { - repo.SetBranch(r.GetBranch()) - } - // send API call to capture the last hook for the repo lastHook, err := database.FromContext(c).LastHookForRepo(repo) if err != nil { @@ -480,6 +470,16 @@ func PostWebhook(c *gin.Context) { return } + // update repo fields with any changes from SCM process + // TODO: eventually remove this in favor of some sync scripting? + if len(r.GetTopics()) != 0 { + repo.SetTopics(r.GetTopics()) + } + + if !strings.EqualFold(repo.GetBranch(), r.GetBranch()) { + repo.SetBranch(r.GetBranch()) + } + // set the parent equal to the current repo counter b.SetParent(repo.GetCounter()) From 0410ae0e53931d134fe0fcb1e5f5d936898c5d0c Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 21 Apr 2023 11:32:16 -0600 Subject: [PATCH 217/298] fix(scm): correct init hook status and send accurate events (#825) --- api/repo/create.go | 10 ++++++++++ scm/github/repo.go | 1 + scm/github/repo_test.go | 1 + 3 files changed, 12 insertions(+) diff --git a/api/repo/create.go b/api/repo/create.go index 295fe2b74..d196c2a48 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -239,8 +239,18 @@ func CreateRepo(c *gin.Context) { } h := new(library.Hook) + + // err being nil means we have a record of this repo (dbRepo) if err == nil { h, _ = database.FromContext(c).LastHookForRepo(dbRepo) + + // make sure our record of the repo allowed events matches what we send to SCM + // what the dbRepo has should override default events on enable + r.SetAllowComment(dbRepo.GetAllowComment()) + r.SetAllowDeploy(dbRepo.GetAllowDeploy()) + r.SetAllowPull(dbRepo.GetAllowPull()) + r.SetAllowPush(dbRepo.GetAllowPush()) + r.SetAllowTag(dbRepo.GetAllowTag()) } // check if we should create the webhook diff --git a/scm/github/repo.go b/scm/github/repo.go index 7ecd53341..13bd1cc1d 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -201,6 +201,7 @@ func (c *client) Enable(u *library.User, r *library.Repo, h *library.Hook) (*lib webhook.SetCreated(hookInfo.GetCreatedAt().Unix()) webhook.SetEvent(eventInitialize) webhook.SetNumber(h.GetNumber() + 1) + webhook.SetStatus(constants.StatusSuccess) switch resp.StatusCode { case http.StatusUnprocessableEntity: diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 9f95fb12a..3dba1bac3 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -608,6 +608,7 @@ func TestGithub_Enable(t *testing.T) { wantHook.SetCreated(1315329987) wantHook.SetNumber(1) wantHook.SetEvent("initialize") + wantHook.SetStatus("success") r := new(library.Repo) r.SetID(1) From 7bdcd54fbc9532fb77adb3536cedceeb5383103a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:43:33 -0500 Subject: [PATCH 218/298] fix(deps): update module github.com/google/go-github/v51 to v52 (#826) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- compiler/native/compile_test.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/github_test.go | 2 +- compiler/registry/github/template.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- scm/github/access.go | 2 +- scm/github/authentication.go | 2 +- scm/github/changeset.go | 2 +- scm/github/deployment.go | 2 +- scm/github/github.go | 2 +- scm/github/github_test.go | 2 +- scm/github/repo.go | 2 +- scm/github/webhook.go | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index d1661278a..5ea927b33 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/raw" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" "testing" "time" diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index f58d49f33..11bc9594a 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -9,7 +9,7 @@ import ( "net/url" "strings" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index d5dcf02b6..08145430e 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index fd62b7ee7..59dde2708 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // Template captures the templated pipeline configuration from the GitHub repo. diff --git a/go.mod b/go.mod index 615ff436d..df4561d2e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/go-vela/types v0.19.0-rc1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 - github.com/google/go-github/v51 v51.0.0 + github.com/google/go-github/v52 v52.0.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 diff --git a/go.sum b/go.sum index cf07c5c14..074a05154 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v51 v51.0.0 h1:KCjsbgPV28VoRftdP+K2mQL16jniUsLAJknsOVKwHyU= -github.com/google/go-github/v51 v51.0.0/go.mod h1:kZj/rn/c1lSUbr/PFWl2hhusPV7a5XNYKcwPrd5L3Us= +github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M= +github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/scm/github/access.go b/scm/github/access.go index fc86d3339..e70693ccb 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // OrgAccess captures the user's access level for an org. diff --git a/scm/github/authentication.go b/scm/github/authentication.go index 72f4354e0..9efe41579 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -14,7 +14,7 @@ import ( "github.com/go-vela/server/random" "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // Authorize uses the given access token to authorize the user. diff --git a/scm/github/changeset.go b/scm/github/changeset.go index e5de2817f..4d41dd2e2 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // Changeset captures the list of files changed for a commit. diff --git a/scm/github/deployment.go b/scm/github/deployment.go index 6f0cc60a9..9945c6303 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/raw" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // GetDeployment gets a deployment from the GitHub repo. diff --git a/scm/github/github.go b/scm/github/github.go index bff19e2a3..75b1df60a 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" "github.com/sirupsen/logrus" "golang.org/x/oauth2" diff --git a/scm/github/github_test.go b/scm/github/github_test.go index cf9d4632e..2e4b5f398 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" "golang.org/x/oauth2" ) diff --git a/scm/github/repo.go b/scm/github/repo.go index 13bd1cc1d..d82c2aeac 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // ConfigBackoff is a wrapper for Config that will retry five times if the function diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 11b317b33..2168d4497 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -20,7 +20,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v51/github" + "github.com/google/go-github/v52/github" ) // ProcessWebhook parses the webhook from a repo. From 258460ed3eed5b0e615152158c9f555b8d15c2ec Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Sun, 23 Apr 2023 09:11:51 -0600 Subject: [PATCH 219/298] fix(deps): update process push webhook to account for changes in v52 (#827) * fix(deps): update process push webhook to account for changes in v52 * remove some unnecessary logic checks in webhook flow --- api/webhook.go | 10 ++-------- scm/github/testdata/hooks/push.json | 6 +++++- scm/github/testdata/hooks/push_no_sender.json | 6 +++++- scm/github/webhook.go | 3 +-- scm/github/webhook_test.go | 2 ++ 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/api/webhook.go b/api/webhook.go index 76f9c45c4..6bbf7cab3 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -471,14 +471,8 @@ func PostWebhook(c *gin.Context) { } // update repo fields with any changes from SCM process - // TODO: eventually remove this in favor of some sync scripting? - if len(r.GetTopics()) != 0 { - repo.SetTopics(r.GetTopics()) - } - - if !strings.EqualFold(repo.GetBranch(), r.GetBranch()) { - repo.SetBranch(r.GetBranch()) - } + repo.SetTopics(r.GetTopics()) + repo.SetBranch(r.GetBranch()) // set the parent equal to the current repo counter b.SetParent(repo.GetCounter()) diff --git a/scm/github/testdata/hooks/push.json b/scm/github/testdata/hooks/push.json index 9beb5bc86..7058efe6b 100644 --- a/scm/github/testdata/hooks/push.json +++ b/scm/github/testdata/hooks/push.json @@ -156,7 +156,11 @@ "watchers": 0, "default_branch": "master", "stargazers": 0, - "master_branch": "master" + "master_branch": "master", + "topics": [ + "go", + "vela" + ] }, "pusher": { "name": "Codertocat", diff --git a/scm/github/testdata/hooks/push_no_sender.json b/scm/github/testdata/hooks/push_no_sender.json index 79eac0888..f9bef26d3 100644 --- a/scm/github/testdata/hooks/push_no_sender.json +++ b/scm/github/testdata/hooks/push_no_sender.json @@ -156,7 +156,11 @@ "watchers": 0, "default_branch": "master", "stargazers": 0, - "master_branch": "master" + "master_branch": "master", + "topics": [ + "go", + "vela" + ] }, "pusher": { "name": "Codertocat", diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 2168d4497..ad4eda5e6 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -145,8 +145,7 @@ func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (* r.SetClone(repo.GetCloneURL()) r.SetBranch(repo.GetDefaultBranch()) r.SetPrivate(repo.GetPrivate()) - // uncomment this line when next version (>v51.0.0) of go-github is released - // r.SetTopics(repo.Topics) + r.SetTopics(repo.Topics) // convert payload to library build b := new(library.Build) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 08d1a0c0e..b1f3a1f0e 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -66,6 +66,7 @@ func TestGithub_ProcessWebhook_Push(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics([]string{"go", "vela"}) wantBuild := new(library.Build) wantBuild.SetEvent("push") @@ -144,6 +145,7 @@ func TestGithub_ProcessWebhook_Push_NoSender(t *testing.T) { wantRepo.SetClone("https://github.com/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) + wantRepo.SetTopics([]string{"go", "vela"}) wantBuild := new(library.Build) wantBuild.SetEvent("push") From 9f220304555337b6701269850c9764b4d02f3de6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 10:03:20 -0500 Subject: [PATCH 220/298] fix(deps): update deps (patch) (#823) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index df4561d2e..14d8bd4aa 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/alicebob/miniredis/v2 v2.30.1 - github.com/aws/aws-sdk-go v1.44.245 + github.com/alicebob/miniredis/v2 v2.30.2 + github.com/aws/aws-sdk-go v1.44.248 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 github.com/gin-gonic/gin v1.9.0 @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.2 - github.com/hashicorp/vault/api v1.9.0 + github.com/hashicorp/vault/api v1.9.1 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.15.0 diff --git a/go.sum b/go.sum index 074a05154..4c75efa69 100644 --- a/go.sum +++ b/go.sum @@ -61,11 +61,11 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.30.1 h1:HM1rlQjq1bm9yQcsawJqSZBJ9AYgxvjkMsNtddh90+g= -github.com/alicebob/miniredis/v2 v2.30.1/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= +github.com/alicebob/miniredis/v2 v2.30.2 h1:lc1UAUT9ZA7h4srlfBmBt2aorm5Yftk9nBjxz7EyY9I= +github.com/alicebob/miniredis/v2 v2.30.2/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.245 h1:KtY2s4q31/kn33AdV63R5t77mdxsI7rq3YT7Mgo805M= -github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.248 h1:GvkxpgsxqNc03LmhXiaxKpzbyxndnex7V+OThLx4g5M= +github.com/aws/aws-sdk-go v1.44.248/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -246,8 +246,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.9.0 h1:ab7dI6W8DuCY7yCU8blo0UCYl2oHre/dloCmzMWg9w8= -github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= From 7eda80aa14a51ef82dba73cda9f2556f48e346d7 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 25 Apr 2023 09:46:28 -0600 Subject: [PATCH 221/298] chore(release): pull in v0.19.0 types for release (#831) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 14d8bd4aa..b211c6b32 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.0-rc1 + github.com/go-vela/types v0.19.0 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 diff --git a/go.sum b/go.sum index 4c75efa69..1e096b7e5 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.0-rc1 h1:/l6l3DgqpifDlq30MMunu2V9bVD55vCDTkLSreUrs5k= -github.com/go-vela/types v0.19.0-rc1/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= +github.com/go-vela/types v0.19.0 h1:LUNQJjXzcjZ3wh1ACppq9bAvzbLKqPmEDcYFwz+8IAw= +github.com/go-vela/types v0.19.0/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= From b601b63cf860ce29b21f8e8c772526b4da4ace0b Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 26 Apr 2023 13:31:04 -0600 Subject: [PATCH 222/298] chore(release): upgrade types to v0.19.1 for patch release (#832) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b211c6b32..fd31f02c0 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.0 + github.com/go-vela/types v0.19.1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 diff --git a/go.sum b/go.sum index 1e096b7e5..60fa83003 100644 --- a/go.sum +++ b/go.sum @@ -136,8 +136,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.0 h1:LUNQJjXzcjZ3wh1ACppq9bAvzbLKqPmEDcYFwz+8IAw= -github.com/go-vela/types v0.19.0/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= +github.com/go-vela/types v0.19.1 h1:HA5tFwju/o1QbzjhASiDJhvpHmLLmLR9e327kWp0MXg= +github.com/go-vela/types v0.19.1/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= From 8c2fdb27d4a8ab8eb55e272a9135c6939c1ec28b Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 4 May 2023 09:10:15 -0600 Subject: [PATCH 223/298] revert(envsubst): roll back envsubst library upgrade due to multiline secret errors (#838) * revert(envsubst): roll back envsubst library upgrade due to multiline secret errors * upgrade types --- compiler/native/substitute.go | 2 +- compiler/native/substitute_test.go | 24 ------------------------ go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/compiler/native/substitute.go b/compiler/native/substitute.go index 402347aef..fcfd2b263 100644 --- a/compiler/native/substitute.go +++ b/compiler/native/substitute.go @@ -10,7 +10,7 @@ import ( "github.com/buildkite/yaml" - "github.com/drone/envsubst/v2" + "github.com/drone/envsubst" types "github.com/go-vela/types/yaml" ) diff --git a/compiler/native/substitute_test.go b/compiler/native/substitute_test.go index fc0718eb4..da27378ac 100644 --- a/compiler/native/substitute_test.go +++ b/compiler/native/substitute_test.go @@ -235,30 +235,6 @@ func Test_client_SubstituteSteps(t *testing.T) { }, wantErr: false, }, - { - name: "step contains escape sequences", - args: args{ - steps: yaml.StepSlice{ - { - Name: "sample", - Environment: map[string]string{ - "BUILD_MESSAGE": "`\\`\r", - "VELA_BUILD_MESSAGE": "`\\`\r", - }, - }, - }, - }, - want: yaml.StepSlice{ - { - Name: "sample", - Environment: map[string]string{ - "BUILD_MESSAGE": "`\\`\r", - "VELA_BUILD_MESSAGE": "`\\`\r", - }, - }, - }, - wantErr: false, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/go.mod b/go.mod index fd31f02c0..7e26a5732 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,10 @@ require ( github.com/alicebob/miniredis/v2 v2.30.2 github.com/aws/aws-sdk-go v1.44.248 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 - github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 + github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.1 + github.com/go-vela/types v0.19.2 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 diff --git a/go.sum b/go.sum index 60fa83003..478dcc750 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 h1:7QPwrLT79GlD5sizHf27aoY2RTvw62mO6x7mxkScNk0= -github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU= +github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= +github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -136,8 +136,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.1 h1:HA5tFwju/o1QbzjhASiDJhvpHmLLmLR9e327kWp0MXg= -github.com/go-vela/types v0.19.1/go.mod h1:BvqapqTPOfHeTLiFYMa/eAzYqnujdPEd358J8TXc7l0= +github.com/go-vela/types v0.19.2 h1:xU61CX2jdMuBCtLOg8a7Z2aEWYM1zZt37Ygx1oHGbjM= +github.com/go-vela/types v0.19.2/go.mod h1:ZvDjYCKU36yJS3sLxPLCny/HLF1U6YtlOienzv/cXB4= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= From af42abe27fd58800171d78e2a9ceb69df32b5a38 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 8 May 2023 12:23:04 -0600 Subject: [PATCH 224/298] fix(restart): correct build sender using claims subject (#839) --- api/build.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/build.go b/api/build.go index 94cb83d30..22a8833db 100644 --- a/api/build.go +++ b/api/build.go @@ -1029,6 +1029,7 @@ func GetBuild(c *gin.Context) { func RestartBuild(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) + cl := claims.Retrieve(c) b := build.Retrieve(c) o := org.Retrieve(c) r := repo.Retrieve(c) @@ -1092,6 +1093,7 @@ func RestartBuild(c *gin.Context) { b.SetHost("") b.SetRuntime("") b.SetDistribution("") + b.SetSender(cl.Subject) // update the PR event action if action was never set // for backwards compatibility with pre-0.14 releases. From f99a894333d4099f7fb3609db4d05250f1b1d541 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 10 May 2023 08:17:10 -0600 Subject: [PATCH 225/298] enhance(build): add ability to cancel pending builds (#840) * enhance(build): add ability to cancel pending builds * change build token for non-pending build status code to 409 * add 409 to api spec --- api/build.go | 147 ++++++++++++----------- router/middleware/executors/executors.go | 9 ++ 2 files changed, 85 insertions(+), 71 deletions(-) diff --git a/api/build.go b/api/build.go index 22a8833db..bf5394eef 100644 --- a/api/build.go +++ b/api/build.go @@ -1728,103 +1728,104 @@ func CancelBuild(c *gin.Context) { "user": u.GetName(), }).Infof("canceling build %s", entry) - // TODO: add support for removing builds from the queue - // - // check to see if build is not running - if !strings.EqualFold(b.GetStatus(), constants.StatusRunning) { - retErr := fmt.Errorf("found build %s but its status was %s", entry, b.GetStatus()) + switch b.GetStatus() { + case constants.StatusRunning: + // retrieve the worker info + w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) + if err != nil { + retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) + util.HandleError(c, http.StatusNotFound, retErr) - util.HandleError(c, http.StatusBadRequest, retErr) + return + } - return - } + 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() { + // prepare the request to the worker + client := http.DefaultClient + client.Timeout = 30 * time.Second - // retrieve the worker info - w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) - if err != nil { - retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) - util.HandleError(c, http.StatusNotFound, retErr) + // set the API endpoint path we send the request to + u := fmt.Sprintf("%s/api/v1/executors/%d/build/cancel", w.GetAddress(), executor.GetID()) - return - } + req, err := http.NewRequestWithContext(context.Background(), "DELETE", u, nil) + if err != nil { + retErr := fmt.Errorf("unable to form a request to %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) - 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() { - // prepare the request to the worker - client := http.DefaultClient - client.Timeout = 30 * time.Second + return + } - // set the API endpoint path we send the request to - u := fmt.Sprintf("%s/api/v1/executors/%d/build/cancel", w.GetAddress(), executor.GetID()) + tm := c.MustGet("token-manager").(*token.Manager) - req, err := http.NewRequestWithContext(context.Background(), "DELETE", u, nil) - if err != nil { - retErr := fmt.Errorf("unable to form a request to %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) + // set mint token options + mto := &token.MintTokenOpts{ + Hostname: "vela-server", + TokenType: constants.WorkerAuthTokenType, + TokenDuration: time.Minute * 1, + } - return - } + // mint token + tkn, err := tm.MintToken(mto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) - tm := c.MustGet("token-manager").(*token.Manager) + return + } - // set mint token options - mto := &token.MintTokenOpts{ - Hostname: "vela-server", - TokenType: constants.WorkerAuthTokenType, - TokenDuration: time.Minute * 1, - } + // add the token to authenticate to the worker + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) - // mint token - tkn, err := tm.MintToken(mto) - if err != nil { - retErr := fmt.Errorf("unable to generate auth token: %w", err) - util.HandleError(c, http.StatusInternalServerError, retErr) + // perform the request to the worker + resp, err := client.Do(req) + if err != nil { + retErr := fmt.Errorf("unable to connect to %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) - return - } + return + } + defer resp.Body.Close() - // add the token to authenticate to the worker - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + // Read Response Body + respBody, err := io.ReadAll(resp.Body) + if err != nil { + retErr := fmt.Errorf("unable to read response from %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) - // perform the request to the worker - resp, err := client.Do(req) - if err != nil { - retErr := fmt.Errorf("unable to connect to %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) + return + } - return - } - defer resp.Body.Close() - - // Read Response Body - respBody, err := io.ReadAll(resp.Body) - if err != nil { - retErr := fmt.Errorf("unable to read response from %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) + err = json.Unmarshal(respBody, b) + if err != nil { + retErr := fmt.Errorf("unable to parse response from %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) - return - } + return + } - err = json.Unmarshal(respBody, b) - if err != nil { - retErr := fmt.Errorf("unable to parse response from %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) + c.JSON(resp.StatusCode, b) return } + } + case constants.StatusPending: + break - c.JSON(resp.StatusCode, b) + default: + retErr := fmt.Errorf("found build %s but its status was %s", entry, b.GetStatus()) - return - } + util.HandleError(c, http.StatusBadRequest, retErr) + + return } // build has been abandoned // update the status in the build table b.SetStatus(constants.StatusCanceled) - err = database.FromContext(c).UpdateBuild(b) + err := database.FromContext(c).UpdateBuild(b) if err != nil { retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -1956,6 +1957,10 @@ func CancelBuild(c *gin.Context) { // description: Bad request // schema: // "$ref": "#/definitions/Error" +// '409': +// description: Conflict (requested build token for build not in pending state) +// schema: +// "$ref": "#/definitions/Error" // '500': // description: Unable to generate build token // schema: @@ -1979,10 +1984,10 @@ func GetBuildToken(c *gin.Context) { "user": cl.Subject, }).Infof("generating build token for build %s/%d", r.GetFullName(), b.GetNumber()) - // if build is not in a pending state, then a build token should not be needed - bad request + // if build is not in a pending state, then a build token should not be needed - conflict if !strings.EqualFold(b.GetStatus(), constants.StatusPending) { retErr := fmt.Errorf("unable to mint build token: build is not in pending state") - util.HandleError(c, http.StatusBadRequest, retErr) + util.HandleError(c, http.StatusConflict, retErr) return } diff --git a/router/middleware/executors/executors.go b/router/middleware/executors/executors.go index 145d134fb..777da7c37 100644 --- a/router/middleware/executors/executors.go +++ b/router/middleware/executors/executors.go @@ -31,6 +31,15 @@ func Establish() gin.HandlerFunc { return func(c *gin.Context) { e := new([]library.Executor) b := build.Retrieve(c) + + // if build has no host, we cannot establish executors + if len(b.GetHost()) == 0 { + ToContext(c, *e) + c.Next() + + return + } + // retrieve the worker w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) if err != nil { From cba432fcd1feaf89db7a7fc69bb460bfba2cbcba Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Thu, 11 May 2023 14:58:31 -0500 Subject: [PATCH 226/298] fix(docker-compose): fix env var names for tokens (#841) --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 91c830d0c..cb4ef0684 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,8 +38,8 @@ services: VELA_LOG_LEVEL: trace VELA_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' VELA_SERVER_PRIVATE_KEY: 'F534FF2A080E45F38E05DC70752E6787' - VELA_REFRESH_TOKEN_DURATION: 90m - VELA_ACCESS_TOKEN_DURATION: 60m + VELA_USER_REFRESH_TOKEN_DURATION: 90m + VELA_USER_ACCESS_TOKEN_DURATION: 60m VELA_DISABLE_WEBHOOK_VALIDATION: 'true' VELA_ENABLE_SECURE_COOKIE: 'false' VELA_REPO_ALLOWLIST: '*' From 5a7b9c53fd675d99298cbcafb8acbbb65a32a0e5 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 15 May 2023 09:03:10 -0500 Subject: [PATCH 227/298] refactor(database): move service logic into separate package (#816) --- api/build.go | 6 +- api/metrics.go | 4 +- api/service.go | 22 +- api/step.go | 2 +- api/webhook.go | 2 +- cmd/vela-server/database.go | 2 +- cmd/vela-server/secret.go | 2 +- database/context.go | 10 +- database/database.go | 2 +- database/hook/hook.go | 4 +- database/hook/{service.go => interface.go} | 4 +- database/{service.go => interface.go} | 73 ++--- database/log/{service.go => interface.go} | 4 +- database/log/log.go | 4 +- .../pipeline/{service.go => interface.go} | 4 +- database/pipeline/pipeline.go | 4 +- database/postgres/ddl/service.go | 32 --- database/postgres/dml/service.go | 67 ----- database/postgres/postgres.go | 89 +++--- database/postgres/postgres_test.go | 7 +- database/postgres/service.go | 94 ------ database/postgres/service_count.go | 90 ------ database/postgres/service_count_test.go | 194 ------------- database/postgres/service_list.go | 71 ----- database/postgres/service_list_test.go | 168 ----------- database/postgres/service_test.go | 267 ------------------ database/repo/{service.go => interface.go} | 4 +- database/repo/repo.go | 4 +- database/secret/{service.go => interface.go} | 4 +- database/secret/secret.go | 4 +- database/service/count.go | 25 ++ database/service/count_build.go | 31 ++ database/service/count_build_test.go | 104 +++++++ database/service/count_test.go | 97 +++++++ database/service/create.go | 38 +++ database/service/create_test.go | 75 +++++ database/service/delete.go | 30 ++ database/service/delete_test.go | 75 +++++ database/service/get.go | 34 +++ database/service/get_build.go | 39 +++ database/service/get_build_test.go | 92 ++++++ database/service/get_test.go | 87 ++++++ database/service/interface.go | 49 ++++ database/service/list.go | 54 ++++ database/service/list_build.go | 65 +++++ database/service/list_build_test.go | 114 ++++++++ database/service/list_image.go | 44 +++ database/service/list_image_test.go | 97 +++++++ database/service/list_status.go | 50 ++++ database/service/list_status_test.go | 114 ++++++++ database/service/list_test.go | 107 +++++++ database/service/opts.go | 44 +++ database/service/opts_test.go | 161 +++++++++++ database/service/service.go | 74 +++++ database/service/service_test.go | 224 +++++++++++++++ database/service/table.go | 76 +++++ database/service/table_test.go | 59 ++++ database/service/update.go | 38 +++ database/service/update_test.go | 75 +++++ database/setup.go | 4 +- database/sqlite/ddl/service.go | 32 --- database/sqlite/dml/service.go | 67 ----- database/sqlite/service.go | 94 ------ database/sqlite/service_count.go | 90 ------ database/sqlite/service_count_test.go | 198 ------------- database/sqlite/service_list.go | 71 ----- database/sqlite/service_list_test.go | 174 ------------ database/sqlite/service_test.go | 266 ----------------- database/sqlite/sqlite.go | 85 +++--- database/step/{service.go => interface.go} | 4 +- database/step/step.go | 4 +- database/user/{service.go => interface.go} | 4 +- database/user/user.go | 4 +- database/worker/{service.go => interface.go} | 4 +- database/worker/worker.go | 4 +- router/middleware/database.go | 2 +- router/middleware/database_test.go | 2 +- router/middleware/service/service.go | 2 +- secret/native/native.go | 4 +- secret/native/native_test.go | 4 +- secret/native/opts.go | 2 +- secret/native/opts_test.go | 4 +- secret/setup.go | 3 +- 83 files changed, 2363 insertions(+), 2181 deletions(-) rename database/hook/{service.go => interface.go} (95%) rename database/{service.go => interface.go} (63%) rename database/log/{service.go => interface.go} (95%) rename database/pipeline/{service.go => interface.go} (95%) delete mode 100644 database/postgres/ddl/service.go delete mode 100644 database/postgres/dml/service.go delete mode 100644 database/postgres/service.go delete mode 100644 database/postgres/service_count.go delete mode 100644 database/postgres/service_count_test.go delete mode 100644 database/postgres/service_list.go delete mode 100644 database/postgres/service_list_test.go delete mode 100644 database/postgres/service_test.go rename database/repo/{service.go => interface.go} (96%) rename database/secret/{service.go => interface.go} (97%) create mode 100644 database/service/count.go create mode 100644 database/service/count_build.go create mode 100644 database/service/count_build_test.go create mode 100644 database/service/count_test.go create mode 100644 database/service/create.go create mode 100644 database/service/create_test.go create mode 100644 database/service/delete.go create mode 100644 database/service/delete_test.go create mode 100644 database/service/get.go create mode 100644 database/service/get_build.go create mode 100644 database/service/get_build_test.go create mode 100644 database/service/get_test.go create mode 100644 database/service/interface.go create mode 100644 database/service/list.go create mode 100644 database/service/list_build.go create mode 100644 database/service/list_build_test.go create mode 100644 database/service/list_image.go create mode 100644 database/service/list_image_test.go create mode 100644 database/service/list_status.go create mode 100644 database/service/list_status_test.go create mode 100644 database/service/list_test.go create mode 100644 database/service/opts.go create mode 100644 database/service/opts_test.go create mode 100644 database/service/service.go create mode 100644 database/service/service_test.go create mode 100644 database/service/table.go create mode 100644 database/service/table_test.go create mode 100644 database/service/update.go create mode 100644 database/service/update_test.go delete mode 100644 database/sqlite/ddl/service.go delete mode 100644 database/sqlite/dml/service.go delete mode 100644 database/sqlite/service.go delete mode 100644 database/sqlite/service_count.go delete mode 100644 database/sqlite/service_count_test.go delete mode 100644 database/sqlite/service_list.go delete mode 100644 database/sqlite/service_list_test.go delete mode 100644 database/sqlite/service_test.go rename database/step/{service.go => interface.go} (95%) rename database/user/{service.go => interface.go} (94%) rename database/worker/{service.go => interface.go} (94%) diff --git a/api/build.go b/api/build.go index bf5394eef..60f7f8eb1 100644 --- a/api/build.go +++ b/api/build.go @@ -1571,7 +1571,7 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { // and services, for the build in the configured backend. // TODO: // - return build and error. -func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r *library.Repo) error { +func planBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) @@ -1625,7 +1625,7 @@ func planBuild(database database.Service, p *pipeline.Build, b *library.Build, r // without execution. This will kill all resources, // like steps and services, for the build in the // configured backend. -func cleanBuild(database database.Service, b *library.Build, services []*library.Service, steps []*library.Step, e error) { +func cleanBuild(database database.Interface, b *library.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) @@ -1881,7 +1881,7 @@ func CancelBuild(c *gin.Context) { for page > 0 { // retrieve build services (per page) from the database - servicesPart, err := database.FromContext(c).GetBuildServiceList(b, page, perPage) + servicesPart, _, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) if err != nil { retErr := fmt.Errorf("unable to retrieve services for build %s: %w", entry, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/api/metrics.go b/api/metrics.go index 4bdeb044e..d68ab35e7 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -350,7 +350,7 @@ func recordGauges(c *gin.Context) { // service_image_count if q.ServiceImageCount { // send API call to capture the total number of service images - serviceImageMap, err := database.FromContext(c).GetServiceImageCount() + serviceImageMap, err := database.FromContext(c).ListServiceImageCount() if err != nil { logrus.Errorf("unable to get count of all service images: %v", err) } @@ -363,7 +363,7 @@ func recordGauges(c *gin.Context) { // service_status_count if q.ServiceStatusCount { // send API call to capture the total number of service statuses - serviceStatusMap, err := database.FromContext(c).GetServiceStatusCount() + serviceStatusMap, err := database.FromContext(c).ListServiceStatusCount() if err != nil { logrus.Errorf("unable to get count of all service statuses: %v", err) } diff --git a/api/service.go b/api/service.go index a2136a96e..66b81b080 100644 --- a/api/service.go +++ b/api/service.go @@ -130,7 +130,7 @@ func CreateService(c *gin.Context) { } // send API call to capture the created service - s, _ := database.FromContext(c).GetService(input.GetNumber(), b) + s, _ := database.FromContext(c).GetServiceForBuild(b, input.GetNumber()) c.JSON(http.StatusCreated, s) } @@ -238,18 +238,8 @@ func GetServices(c *gin.Context) { // ensure per_page isn't above or below allowed values perPage = util.MaxInt(1, util.MinInt(100, perPage)) - // send API call to capture the total number of services for the build - t, err := database.FromContext(c).GetBuildServiceCount(b) - if err != nil { - retErr := fmt.Errorf("unable to get services count for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // send API call to capture the list of services for the build - s, err := database.FromContext(c).GetBuildServiceList(b, page, perPage) + s, t, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get services for build %s: %w", entry, err) @@ -462,7 +452,7 @@ func UpdateService(c *gin.Context) { } // send API call to capture the updated service - s, _ = database.FromContext(c).GetService(s.GetNumber(), b) + s, _ = database.FromContext(c).GetServiceForBuild(b, s.GetNumber()) c.JSON(http.StatusOK, s) } @@ -534,7 +524,7 @@ func DeleteService(c *gin.Context) { }).Infof("deleting service %s", entry) // send API call to remove the service - err := database.FromContext(c).DeleteService(s.GetID()) + err := database.FromContext(c).DeleteService(s) if err != nil { retErr := fmt.Errorf("unable to delete service %s: %w", entry, err) @@ -549,7 +539,7 @@ func DeleteService(c *gin.Context) { // 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(database database.Service, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { +func planServices(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { // variable to store planned services services := []*library.Service{} @@ -572,7 +562,7 @@ func planServices(database database.Service, p *pipeline.Build, b *library.Build } // send API call to capture the created service - s, err = database.GetService(s.GetNumber(), b) + s, err = database.GetServiceForBuild(b, s.GetNumber()) if err != nil { return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) } diff --git a/api/step.go b/api/step.go index 465ce89f0..23d72fac4 100644 --- a/api/step.go +++ b/api/step.go @@ -540,7 +540,7 @@ func DeleteStep(c *gin.Context) { // 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(database database.Service, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { +func planSteps(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { // variable to store planned steps steps := []*library.Step{} diff --git a/api/webhook.go b/api/webhook.go index 6bbf7cab3..501caffa6 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -707,7 +707,7 @@ func PostWebhook(c *gin.Context) { // publishToQueue is a helper function that creates // a build item and publishes it to the queue. -func publishToQueue(queue queue.Service, db database.Service, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { +func publishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { item := types.ToItem(p, b, r, u) logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) diff --git a/cmd/vela-server/database.go b/cmd/vela-server/database.go index cee4f9a83..e4db992ec 100644 --- a/cmd/vela-server/database.go +++ b/cmd/vela-server/database.go @@ -13,7 +13,7 @@ import ( ) // helper function to setup the database from the CLI arguments. -func setupDatabase(c *cli.Context) (database.Service, error) { +func setupDatabase(c *cli.Context) (database.Interface, error) { logrus.Debug("Creating database client from CLI configuration") // database configuration diff --git a/cmd/vela-server/secret.go b/cmd/vela-server/secret.go index ee780dce0..56e6c0572 100644 --- a/cmd/vela-server/secret.go +++ b/cmd/vela-server/secret.go @@ -15,7 +15,7 @@ import ( ) // helper function to setup the secrets engines from the CLI arguments. -func setupSecrets(c *cli.Context, d database.Service) (map[string]secret.Service, error) { +func setupSecrets(c *cli.Context, d database.Interface) (map[string]secret.Service, error) { logrus.Debug("Creating secret clients from CLI configuration") secrets := make(map[string]secret.Service) diff --git a/database/context.go b/database/context.go index 7e315511c..f3a872602 100644 --- a/database/context.go +++ b/database/context.go @@ -15,14 +15,14 @@ type Setter interface { Set(string, interface{}) } -// FromContext returns the database Service associated with this context. -func FromContext(c context.Context) Service { +// FromContext returns the database Interface associated with this context. +func FromContext(c context.Context) Interface { v := c.Value(key) if v == nil { return nil } - d, ok := v.(Service) + d, ok := v.(Interface) if !ok { return nil } @@ -30,8 +30,8 @@ func FromContext(c context.Context) Service { return d } -// ToContext adds the database Service to this context if it supports +// ToContext adds the database Interface to this context if it supports // the Setter interface. -func ToContext(c Setter, d Service) { +func ToContext(c Setter, d Interface) { c.Set(key, d) } diff --git a/database/database.go b/database/database.go index a6e8c8958..ad26dd82a 100644 --- a/database/database.go +++ b/database/database.go @@ -20,7 +20,7 @@ import ( // * Postgres // * Sqlite // . -func New(s *Setup) (Service, error) { +func New(s *Setup) (Interface, error) { // validate the setup being provided // // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Validate diff --git a/database/hook/hook.go b/database/hook/hook.go index 279bc3d2a..5225f901a 100644 --- a/database/hook/hook.go +++ b/database/hook/hook.go @@ -14,13 +14,13 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the HookService interface. + // config represents the settings required to create the engine that implements the HookInterface interface. config struct { // specifies to skip creating tables and indexes for the Hook engine SkipCreation bool } - // engine represents the hook functionality that implements the HookService interface. + // engine represents the hook functionality that implements the HookInterface interface. engine struct { // engine configuration settings used in hook functions config *config diff --git a/database/hook/service.go b/database/hook/interface.go similarity index 95% rename from database/hook/service.go rename to database/hook/interface.go index 99a389fef..a1e5c5fe0 100644 --- a/database/hook/service.go +++ b/database/hook/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// HookService represents the Vela interface for hook +// HookInterface represents the Vela interface for hook // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type HookService interface { +type HookInterface interface { // Hook Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/service.go b/database/interface.go similarity index 63% rename from database/service.go rename to database/interface.go index 306c77720..b7d1b6fee 100644 --- a/database/service.go +++ b/database/interface.go @@ -10,15 +10,16 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "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/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/library" ) -// Service represents the interface for Vela integrating +// Interface represents the interface for Vela integrating // with the different supported Database backends. -type Service interface { +type Interface interface { // Database Interface Functions // Driver defines a function that outputs @@ -76,67 +77,39 @@ type Service interface { // deletes a build by unique ID. DeleteBuild(int64) error - // HookService provides the interface for functionality + // HookInterface provides the interface for functionality // related to hooks stored in the database. - hook.HookService + hook.HookInterface - // LogService provides the interface for functionality + // LogInterface provides the interface for functionality // related to logs stored in the database. - log.LogService + log.LogInterface - // PipelineService provides the interface for functionality + // PipelineInterface provides the interface for functionality // related to pipelines stored in the database. - pipeline.PipelineService + pipeline.PipelineInterface - // RepoService provides the interface for functionality + // RepoInterface provides the interface for functionality // related to repos stored in the database. - repo.RepoService + repo.RepoInterface - // SecretService provides the interface for functionality + // SecretInterface provides the interface for functionality // related to secrets stored in the database. - secret.SecretService + secret.SecretInterface - // StepService provides the interface for functionality - // related to steps stored in the database. - step.StepService - - // Service Database Interface Functions + // ServiceInterface provides the interface for functionality + // related to services stored in the database. + service.ServiceInterface - // GetService defines a function that - // gets a step by number and build ID. - GetService(int, *library.Build) (*library.Service, error) - // GetServiceList defines a function that - // gets a list of all steps. - GetServiceList() ([]*library.Service, error) - // GetBuildServiceList defines a function - // that gets a list of steps by build ID. - GetBuildServiceList(*library.Build, int, int) ([]*library.Service, error) - // GetBuildServiceCount defines a function - // that gets the count of steps by build ID. - GetBuildServiceCount(*library.Build) (int64, error) - // GetServiceImageCount defines a function that - // gets a list of all service images and the - // count of their occurrence. - GetServiceImageCount() (map[string]float64, error) - // GetServiceStatusCount defines a function that - // gets a list of all service statuses and the - // count of their occurrence. - GetServiceStatusCount() (map[string]float64, error) - // CreateService defines a function that - // creates a new step. - CreateService(*library.Service) error - // UpdateService defines a function that - // updates a step. - UpdateService(*library.Service) error - // DeleteService defines a function that - // deletes a step by unique ID. - DeleteService(int64) error + // StepInterface provides the interface for functionality + // related to steps stored in the database. + step.StepInterface - // UserService provides the interface for functionality + // UserInterface provides the interface for functionality // related to users stored in the database. - user.UserService + user.UserInterface - // WorkerService provides the interface for functionality + // WorkerInterface provides the interface for functionality // related to workers stored in the database. - worker.WorkerService + worker.WorkerInterface } diff --git a/database/log/service.go b/database/log/interface.go similarity index 95% rename from database/log/service.go rename to database/log/interface.go index 00e686ee9..8c72a5098 100644 --- a/database/log/service.go +++ b/database/log/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// LogService represents the Vela interface for log +// LogInterface represents the Vela interface for log // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type LogService interface { +type LogInterface interface { // Log Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/log/log.go b/database/log/log.go index 22604e411..35d25400f 100644 --- a/database/log/log.go +++ b/database/log/log.go @@ -14,7 +14,7 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the LogService interface. + // config represents the settings required to create the engine that implements the LogInterface interface. config struct { // specifies the level of compression to use for the Log engine CompressionLevel int @@ -22,7 +22,7 @@ type ( SkipCreation bool } - // engine represents the log functionality that implements the LogService interface. + // engine represents the log functionality that implements the LogInterface interface. engine struct { // engine configuration settings used in log functions config *config diff --git a/database/pipeline/service.go b/database/pipeline/interface.go similarity index 95% rename from database/pipeline/service.go rename to database/pipeline/interface.go index c619fda46..eaafa59fe 100644 --- a/database/pipeline/service.go +++ b/database/pipeline/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// PipelineService represents the Vela interface for pipeline +// PipelineInterface represents the Vela interface for pipeline // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type PipelineService interface { +type PipelineInterface interface { // Pipeline Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/pipeline/pipeline.go b/database/pipeline/pipeline.go index b99bdbfef..a48cc6e07 100644 --- a/database/pipeline/pipeline.go +++ b/database/pipeline/pipeline.go @@ -14,7 +14,7 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the PipelineService interface. + // config represents the settings required to create the engine that implements the PipelineInterface interface. config struct { // specifies the level of compression to use for the Pipeline engine CompressionLevel int @@ -22,7 +22,7 @@ type ( SkipCreation bool } - // engine represents the pipeline functionality that implements the PipelineService interface. + // engine represents the pipeline functionality that implements the PipelineInterface interface. engine struct { // engine configuration settings used in pipeline functions config *config diff --git a/database/postgres/ddl/service.go b/database/postgres/ddl/service.go deleted file mode 100644 index b714586b5..000000000 --- a/database/postgres/ddl/service.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateServiceTable represents a query to - // create the services table for Vela. - CreateServiceTable = ` -CREATE TABLE -IF NOT EXISTS -services ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - name VARCHAR(250), - image VARCHAR(500), - status VARCHAR(250), - error VARCHAR(500), - exit_code INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - host VARCHAR(250), - runtime VARCHAR(250), - distribution VARCHAR(250), - UNIQUE(build_id, number) -); -` -) diff --git a/database/postgres/dml/service.go b/database/postgres/dml/service.go deleted file mode 100644 index 66e009406..000000000 --- a/database/postgres/dml/service.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListServices represents a query to - // list all services in the database. - ListServices = ` -SELECT * -FROM services; -` - - // ListBuildServices represents a query to list - // all services for a build_id in the database. - ListBuildServices = ` -SELECT * -FROM services -WHERE build_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectBuildServicesCount represents a query to select - // the count of services for a build_id in the database. - SelectBuildServicesCount = ` -SELECT count(*) as count -FROM services -WHERE build_id = ? -` - - // SelectServiceImagesCount represents a query to select - // the count of an images appearances in the database. - SelectServiceImagesCount = ` -SELECT image, count(image) as count -FROM services -GROUP BY image -` - - // SelectServiceStatusesCount represents a query to select - // the count of service status appearances in the database. - SelectServiceStatusesCount = ` -SELECT status, count(status) as count -FROM services -GROUP BY status; -` - - // SelectBuildService represents a query to select a - // service for a build_id and number in the database. - SelectBuildService = ` -SELECT * -FROM services -WHERE build_id = ? -AND number = ? -LIMIT 1; -` - - // DeleteService represents a query to - // remove a service from the database. - DeleteService = ` -DELETE -FROM services -WHERE id = ?; -` -) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index c96883b59..2adbfdd31 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -15,6 +15,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "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/user" "github.com/go-vela/server/database/worker" @@ -49,22 +50,24 @@ type ( Postgres *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry - // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService - hook.HookService - // https://pkg.go.dev/github.com/go-vela/server/database/log#LogService - log.LogService - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService - pipeline.PipelineService - // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService - repo.RepoService - // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService - secret.SecretService - // https://pkg.go.dev/github.com/go-vela/server/database/step#StepService - step.StepService - // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService - user.UserService - // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService - worker.WorkerService + // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface + hook.HookInterface + // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface + log.LogInterface + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineInterface + pipeline.PipelineInterface + // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface + repo.RepoInterface + // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface + secret.SecretInterface + // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface + service.ServiceInterface + // https://pkg.go.dev/github.com/go-vela/server/database/step#StepInterface + step.StepInterface + // https://pkg.go.dev/github.com/go-vela/server/database/user#UserInterface + user.UserInterface + // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerInterface + worker.WorkerInterface } ) @@ -178,6 +181,8 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the service queries + _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the step queries _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries @@ -272,12 +277,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the services table - err = c.Postgres.Exec(ddl.CreateServiceTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) - } - return nil } @@ -317,10 +316,10 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error - // create the database agnostic hook service + // create the database agnostic engine for hooks // // https://pkg.go.dev/github.com/go-vela/server/database/hook#New - c.HookService, err = hook.New( + c.HookInterface, err = hook.New( hook.WithClient(c.Postgres), hook.WithLogger(c.Logger), hook.WithSkipCreation(c.config.SkipCreation), @@ -329,10 +328,10 @@ func createServices(c *client) error { return err } - // create the database agnostic log service + // create the database agnostic engine for logs // // https://pkg.go.dev/github.com/go-vela/server/database/log#New - c.LogService, err = log.New( + c.LogInterface, err = log.New( log.WithClient(c.Postgres), log.WithCompressionLevel(c.config.CompressionLevel), log.WithLogger(c.Logger), @@ -342,10 +341,10 @@ func createServices(c *client) error { return err } - // create the database agnostic pipeline service + // create the database agnostic engine for pipelines // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New - c.PipelineService, err = pipeline.New( + c.PipelineInterface, err = pipeline.New( pipeline.WithClient(c.Postgres), pipeline.WithCompressionLevel(c.config.CompressionLevel), pipeline.WithLogger(c.Logger), @@ -355,10 +354,10 @@ func createServices(c *client) error { return err } - // create the database agnostic repo service + // create the database agnostic engine for repos // // https://pkg.go.dev/github.com/go-vela/server/database/repo#New - c.RepoService, err = repo.New( + c.RepoInterface, err = repo.New( repo.WithClient(c.Postgres), repo.WithEncryptionKey(c.config.EncryptionKey), repo.WithLogger(c.Logger), @@ -368,10 +367,10 @@ func createServices(c *client) error { return err } - // create the database agnostic secret service + // create the database agnostic engine for secrets // // https://pkg.go.dev/github.com/go-vela/server/database/secret#New - c.SecretService, err = secret.New( + c.SecretInterface, err = secret.New( secret.WithClient(c.Postgres), secret.WithEncryptionKey(c.config.EncryptionKey), secret.WithLogger(c.Logger), @@ -381,10 +380,22 @@ func createServices(c *client) error { return err } - // create the database agnostic step service + // create the database agnostic engine for services // - // https://pkg.go.dev/github.com/go-vela/server/database/repo#New - c.StepService, err = step.New( + // https://pkg.go.dev/github.com/go-vela/server/database/service#New + c.ServiceInterface, err = service.New( + service.WithClient(c.Postgres), + service.WithLogger(c.Logger), + service.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for steps + // + // https://pkg.go.dev/github.com/go-vela/server/database/step#New + c.StepInterface, err = step.New( step.WithClient(c.Postgres), step.WithLogger(c.Logger), step.WithSkipCreation(c.config.SkipCreation), @@ -393,10 +404,10 @@ func createServices(c *client) error { return err } - // create the database agnostic user service + // create the database agnostic engine for users // // https://pkg.go.dev/github.com/go-vela/server/database/user#New - c.UserService, err = user.New( + c.UserInterface, err = user.New( user.WithClient(c.Postgres), user.WithEncryptionKey(c.config.EncryptionKey), user.WithLogger(c.Logger), @@ -406,10 +417,10 @@ func createServices(c *client) error { return err } - // create the database agnostic worker service + // create the database agnostic engine for workers // // https://pkg.go.dev/github.com/go-vela/server/database/worker#New - c.WorkerService, err = worker.New( + c.WorkerInterface, err = worker.New( worker.WithClient(c.Postgres), worker.WithLogger(c.Logger), worker.WithSkipCreation(c.config.SkipCreation), diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 03c49a7d6..6074c65ca 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -16,6 +16,7 @@ import ( "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "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/user" "github.com/go-vela/server/database/worker" @@ -82,7 +83,6 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the index queries _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -107,6 +107,8 @@ func TestPostgres_setupDatabase(t *testing.T) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the service queries + _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the step queries _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries @@ -176,7 +178,6 @@ func TestPostgres_createTables(t *testing.T) { // ensure the mock expects the table queries _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateServiceTable).WillReturnResult(sqlmock.NewResult(1, 1)) tests := []struct { failure bool @@ -273,6 +274,8 @@ func TestPostgres_createServices(t *testing.T) { _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the service queries + _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the step queries _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the user queries diff --git a/database/postgres/service.go b/database/postgres/service.go deleted file mode 100644 index 011a09770..000000000 --- a/database/postgres/service.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetService gets a service by number and build ID from the database. -func (c *client) GetService(number int, b *library.Build) (*library.Service, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "service": number, - }).Tracef("getting service %d for build %d from the database", number, b.GetNumber()) - - // variable to store query results - s := new(database.Service) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableService). - Raw(dml.SelectBuildService, b.GetID(), number). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return s.ToLibrary(), result.Error -} - -// CreateService creates a new service in the database. -func (c *client) CreateService(s *library.Service) error { - c.Logger.WithFields(logrus.Fields{ - "service": s.GetNumber(), - }).Tracef("creating service %s in the database", s.GetName()) - - // cast to database type - service := database.ServiceFromLibrary(s) - - // validate the necessary fields are populated - err := service.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableService). - Create(service).Error -} - -// UpdateService updates a service in the database. -func (c *client) UpdateService(s *library.Service) error { - c.Logger.WithFields(logrus.Fields{ - "service": s.GetNumber(), - }).Tracef("updating service %s in the database", s.GetName()) - - // cast to database type - service := database.ServiceFromLibrary(s) - - // validate the necessary fields are populated - err := service.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableService). - Save(service).Error -} - -// DeleteService deletes a service by unique ID from the database. -func (c *client) DeleteService(id int64) error { - c.Logger.Tracef("deleting service %d from the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableService). - Exec(dml.DeleteService, id).Error -} diff --git a/database/postgres/service_count.go b/database/postgres/service_count.go deleted file mode 100644 index 426239bc2..000000000 --- a/database/postgres/service_count.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildServiceCount gets a count of all services by build ID from the database. -func (c *client) GetBuildServiceCount(b *library.Build) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("getting count of services for build %d from the database", b.GetNumber()) - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableService). - Raw(dml.SelectBuildServicesCount, b.GetID()). - Pluck("count", &s).Error - - return s, err -} - -// GetServiceImageCount gets a count of all service images -// and the count of their occurrence in the database. -func (c *client) GetServiceImageCount() (map[string]float64, error) { - c.Logger.Tracef("getting count of all images for services from the database") - - type imageCount struct { - Image string - Count int - } - - // variable to store query results - images := new([]imageCount) - counts := make(map[string]float64) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableService). - Raw(dml.SelectServiceImagesCount). - Scan(images).Error - - for _, image := range *images { - counts[image.Image] = float64(image.Count) - } - - return counts, err -} - -// GetServiceStatusCount gets a list of all service statuses -// and the count of their occurrence in the database. -func (c *client) GetServiceStatusCount() (map[string]float64, error) { - c.Logger.Trace("getting count of all statuses for services from the database") - - type statusCount struct { - Status string - Count int - } - - // variable to store query results - s := new([]statusCount) - counts := map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - } - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableService). - Raw(dml.SelectServiceStatusesCount). - Scan(s).Error - - for _, status := range *s { - counts[status.Status] = float64(status.Count) - } - - return counts, err -} diff --git a/database/postgres/service_count_test.go b/database/postgres/service_count_test.go deleted file mode 100644 index 52226e296..000000000 --- a/database/postgres/service_count_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuildServiceCount(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildServicesCount, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildServiceCount(_build) - - if test.failure { - if err == nil { - t.Errorf("GetBuildServiceCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildServiceCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildServiceCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetServiceImageCount(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectServiceImagesCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"image", "count"}).AddRow("foo", 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{"foo": 0}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceImageCount() - - if test.failure { - if err == nil { - t.Errorf("GetServiceImageCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceImageCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceImageCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetServiceStatusCount(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectServiceStatusesCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"status", "count"}). - AddRow("failure", 0). - AddRow("killed", 0). - AddRow("pending", 0). - AddRow("running", 0). - AddRow("success", 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - }, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceStatusCount() - - if test.failure { - if err == nil { - t.Errorf("GetServiceStatusCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceStatusCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceStatusCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/service_list.go b/database/postgres/service_list.go deleted file mode 100644 index b26536d56..000000000 --- a/database/postgres/service_list.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetServiceList gets a list of all services from the database. -func (c *client) GetServiceList() ([]*library.Service, error) { - c.Logger.Trace("listing services from the database") - - // variable to store query results - s := new([]database.Service) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableService). - Raw(dml.ListServices). - Scan(s).Error - - // variable we want to return - services := []*library.Service{} - // iterate through all query results - for _, service := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := service - - // convert query result to library type - services = append(services, tmp.ToLibrary()) - } - - return services, err -} - -// GetBuildServiceList gets a list of services by build ID from the database. -func (c *client) GetBuildServiceList(b *library.Build, page, perPage int) ([]*library.Service, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("listing services for build %d from the database", b.GetNumber()) - - // variable to store query results - s := new([]database.Service) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableService). - Raw(dml.ListBuildServices, b.GetID(), perPage, offset). - Scan(s).Error - - // variable we want to return - services := []*library.Service{} - // iterate through all query results - for _, service := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := service - - // convert query result to library type - services = append(services, tmp.ToLibrary()) - } - - return services, err -} diff --git a/database/postgres/service_list_test.go b/database/postgres/service_list_test.go deleted file mode 100644 index 40c267d27..000000000 --- a/database/postgres/service_list_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetServiceList(t *testing.T) { - // setup types - _serviceOne := testService() - _serviceOne.SetID(1) - _serviceOne.SetRepoID(1) - _serviceOne.SetBuildID(1) - _serviceOne.SetNumber(1) - _serviceOne.SetName("foo") - _serviceOne.SetImage("bar") - - _serviceTwo := testService() - _serviceTwo.SetID(2) - _serviceTwo.SetRepoID(1) - _serviceTwo.SetBuildID(1) - _serviceTwo.SetNumber(1) - _serviceTwo.SetName("bar") - _serviceTwo.SetImage("foo") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListServices).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", 0, 0, 0, 0, "", "", ""). - AddRow(2, 1, 1, 1, "bar", "foo", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Service - }{ - { - failure: false, - want: []*library.Service{_serviceOne, _serviceTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceList() - - if test.failure { - if err == nil { - t.Errorf("GetServiceList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetBuildServiceList(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _serviceOne := testService() - _serviceOne.SetID(1) - _serviceOne.SetRepoID(1) - _serviceOne.SetBuildID(1) - _serviceOne.SetNumber(1) - _serviceOne.SetName("foo") - _serviceOne.SetImage("bar") - - _serviceTwo := testService() - _serviceTwo.SetID(2) - _serviceTwo.SetRepoID(1) - _serviceTwo.SetBuildID(1) - _serviceTwo.SetNumber(1) - _serviceTwo.SetName("bar") - _serviceTwo.SetImage("foo") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListBuildServices, 1, 1, 10).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", 0, 0, 0, 0, "", "", ""). - AddRow(2, 1, 1, 1, "bar", "foo", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Service - }{ - { - failure: false, - want: []*library.Service{_serviceOne, _serviceTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildServiceList(_build, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetBuildServiceList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildServiceList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildServiceList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/service_test.go b/database/postgres/service_test.go deleted file mode 100644 index 5c88561e5..000000000 --- a/database/postgres/service_test.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - sqlmock "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetService(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildService, 1, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []string{"id", "repo_id", "build_id", "number", "name", "image", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}, - ).AddRow(1, 1, 1, 1, "foo", "bar", "", "", 0, 0, 0, 0, "", "", "") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Service - }{ - { - failure: false, - want: _service, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetService(1, _build) - - if test.failure { - if err == nil { - t.Errorf("GetService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetService returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetService is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateService(t *testing.T) { - // setup types - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "services" ("build_id","repo_id","number","name","image","status","error","exit_code","created","started","finished","host","runtime","distribution","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). - WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateService(_service) - - if test.failure { - if err == nil { - t.Errorf("CreateService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateService returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateService(t *testing.T) { - // setup types - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "services" SET "build_id"=$1,"repo_id"=$2,"number"=$3,"name"=$4,"image"=$5,"status"=$6,"error"=$7,"exit_code"=$8,"created"=$9,"started"=$10,"finished"=$11,"host"=$12,"runtime"=$13,"distribution"=$14 WHERE "id" = $15`). - WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateService(_service) - - if test.failure { - if err == nil { - t.Errorf("UpdateService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateService returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteService(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteService, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteService(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteService returned err: %v", err) - } - } -} - -// testService is a test helper function to create a -// library Service type with all fields set to their -// zero values. -func testService() *library.Service { - i64 := int64(0) - i := 0 - str := "" - - return &library.Service{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - Number: &i, - Name: &str, - Image: &str, - Status: &str, - Error: &str, - ExitCode: &i, - Created: &i64, - Started: &i64, - Finished: &i64, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/repo/service.go b/database/repo/interface.go similarity index 96% rename from database/repo/service.go rename to database/repo/interface.go index 7695333ff..a53ad3a0a 100644 --- a/database/repo/service.go +++ b/database/repo/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// RepoService represents the Vela interface for repo +// RepoInterface represents the Vela interface for repo // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type RepoService interface { +type RepoInterface interface { // Repo Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/repo/repo.go b/database/repo/repo.go index e0f768741..1da6a8ab8 100644 --- a/database/repo/repo.go +++ b/database/repo/repo.go @@ -14,7 +14,7 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the RepoService interface. + // config represents the settings required to create the engine that implements the RepoInterface interface. config struct { // specifies the encryption key to use for the Repo engine EncryptionKey string @@ -22,7 +22,7 @@ type ( SkipCreation bool } - // engine represents the repo functionality that implements the RepoService interface. + // engine represents the repo functionality that implements the RepoInterface interface. engine struct { // engine configuration settings used in repo functions config *config diff --git a/database/secret/service.go b/database/secret/interface.go similarity index 97% rename from database/secret/service.go rename to database/secret/interface.go index 7637a91b8..c6bee369a 100644 --- a/database/secret/service.go +++ b/database/secret/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// SecretService represents the Vela interface for secret +// SecretInterface represents the Vela interface for secret // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type SecretService interface { +type SecretInterface interface { // Secret Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/secret/secret.go b/database/secret/secret.go index 9f19279f4..fa342f5d5 100644 --- a/database/secret/secret.go +++ b/database/secret/secret.go @@ -14,7 +14,7 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the SecretService interface. + // config represents the settings required to create the engine that implements the SecretInterface interface. config struct { // specifies the encryption key to use for the Secret engine EncryptionKey string @@ -22,7 +22,7 @@ type ( SkipCreation bool } - // engine represents the secret functionality that implements the SecretService interface. + // engine represents the secret functionality that implements the SecretInterface interface. engine struct { // engine configuration settings used in secret functions config *config diff --git a/database/service/count.go b/database/service/count.go new file mode 100644 index 000000000..08b488933 --- /dev/null +++ b/database/service/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" +) + +// CountServices gets the count of all services from the database. +func (e *engine) CountServices() (int64, error) { + e.logger.Tracef("getting count of all services from the database") + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Count(&s). + Error + + return s, err +} diff --git a/database/service/count_build.go b/database/service/count_build.go new file mode 100644 index 000000000..0cd773570 --- /dev/null +++ b/database/service/count_build.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountServicesForBuild gets the count of services by build ID from the database. +func (e *engine) CountServicesForBuild(b *library.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()) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Where("build_id = ?", b.GetID()). + Where(filters). + Count(&s). + Error + + return s, err +} diff --git a/database/service/count_build_test.go b/database/service/count_build_test.go new file mode 100644 index 000000000..08c964da7 --- /dev/null +++ b/database/service/count_build_test.go @@ -0,0 +1,104 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_CountServicesForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(2) + _serviceTwo.SetNumber(1) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "services" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountServicesForBuild(_build, filters) + + if test.failure { + if err == nil { + t.Errorf("CountServicesForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountServicesForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountServicesForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/count_test.go b/database/service/count_test.go new file mode 100644 index 000000000..226d4b879 --- /dev/null +++ b/database/service/count_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_CountServices(t *testing.T) { + // setup types + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(2) + _serviceTwo.SetNumber(1) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "services"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountServices() + + if test.failure { + if err == nil { + t.Errorf("CountServices for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountServices for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountServices for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/create.go b/database/service/create.go new file mode 100644 index 000000000..56574e23b --- /dev/null +++ b/database/service/create.go @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateService creates a new service in the database. +func (e *engine) CreateService(s *library.Service) error { + e.logger.WithFields(logrus.Fields{ + "service": s.GetNumber(), + }).Tracef("creating service %s in the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#ServiceFromLibrary + service := database.ServiceFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.Validate + err := service.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableService). + Create(service). + Error +} diff --git a/database/service/create_test.go b/database/service/create_test.go new file mode 100644 index 000000000..4e84ed090 --- /dev/null +++ b/database/service/create_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_CreateService(t *testing.T) { + // setup types + _service := testService() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + _service.SetName("foo") + _service.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "services" +("build_id","repo_id","number","name","image","status","error","exit_code","created","started","finished","host","runtime","distribution","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). + WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateService(_service) + + if test.failure { + if err == nil { + t.Errorf("CreateService for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateService for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/service/delete.go b/database/service/delete.go new file mode 100644 index 000000000..86c0c21b2 --- /dev/null +++ b/database/service/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteService deletes an existing service from the database. +func (e *engine) DeleteService(s *library.Service) error { + e.logger.WithFields(logrus.Fields{ + "service": s.GetNumber(), + }).Tracef("deleting service %s from the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#ServiceFromLibrary + service := database.ServiceFromLibrary(s) + + // send query to the database + return e.client. + Table(constants.TableService). + Delete(service). + Error +} diff --git a/database/service/delete_test.go b/database/service/delete_test.go new file mode 100644 index 000000000..d63c55c05 --- /dev/null +++ b/database/service/delete_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_DeleteService(t *testing.T) { + // setup types + _service := testService() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + _service.SetName("foo") + _service.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "services" WHERE "services"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_service) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteService(_service) + + if test.failure { + if err == nil { + t.Errorf("DeleteService for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteService for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/service/get.go b/database/service/get.go new file mode 100644 index 000000000..7678168b2 --- /dev/null +++ b/database/service/get.go @@ -0,0 +1,34 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetService gets a service by ID from the database. +func (e *engine) GetService(id int64) (*library.Service, error) { + e.logger.Tracef("getting service %d from the database", id) + + // variable to store query results + s := new(database.Service) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Where("id = ?", id). + Take(s). + Error + if err != nil { + return nil, err + } + + // return the service + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/service/get_build.go b/database/service/get_build.go new file mode 100644 index 000000000..5321cc728 --- /dev/null +++ b/database/service/get_build.go @@ -0,0 +1,39 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetServiceForBuild gets a service by number and build ID from the database. +func (e *engine) GetServiceForBuild(b *library.Build, number int) (*library.Service, error) { + e.logger.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "service": number, + }).Tracef("getting service %d from the database", number) + + // variable to store query results + s := new(database.Service) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Where("build_id = ?", b.GetID()). + Where("number = ?", number). + Take(s). + Error + if err != nil { + return nil, err + } + + // return the service + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.ToLibrary + return s.ToLibrary(), nil +} diff --git a/database/service/get_build_test.go b/database/service/get_build_test.go new file mode 100644 index 000000000..36747ad65 --- /dev/null +++ b/database/service/get_build_test.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestService_Engine_GetServiceForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _service := testService() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + _service.SetName("foo") + _service.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "services" WHERE build_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_service) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Service + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _service, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _service, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetServiceForBuild(_build, 1) + + if test.failure { + if err == nil { + t.Errorf("GetServiceForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetServiceForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetServiceForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/get_test.go b/database/service/get_test.go new file mode 100644 index 000000000..13bd6691a --- /dev/null +++ b/database/service/get_test.go @@ -0,0 +1,87 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestService_Engine_GetService(t *testing.T) { + // setup types + _service := testService() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + _service.SetName("foo") + _service.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "services" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_service) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Service + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _service, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _service, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetService(1) + + if test.failure { + if err == nil { + t.Errorf("GetService for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetService for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetService for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/interface.go b/database/service/interface.go new file mode 100644 index 000000000..29cb0f457 --- /dev/null +++ b/database/service/interface.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/library" +) + +// ServiceInterface represents the Vela interface for service +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type ServiceInterface interface { + // Service Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateServiceTable defines a function that creates the services table. + CreateServiceTable(string) error + + // Service Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountServices defines a function that gets the count of all services. + CountServices() (int64, error) + // CountServicesForBuild defines a function that gets the count of services by build ID. + CountServicesForBuild(*library.Build, map[string]interface{}) (int64, error) + // CreateService defines a function that creates a new service. + CreateService(*library.Service) error + // DeleteService defines a function that deletes an existing service. + DeleteService(*library.Service) error + // GetService defines a function that gets a service by ID. + GetService(int64) (*library.Service, error) + // GetServiceForBuild defines a function that gets a service by number and build ID. + GetServiceForBuild(*library.Build, int) (*library.Service, error) + // ListServices defines a function that gets a list of all services. + ListServices() ([]*library.Service, error) + // ListServicesForBuild defines a function that gets a list of services by build ID. + ListServicesForBuild(*library.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() (map[string]float64, error) + // ListServiceStatusCount defines a function that gets a list of all service statuses and the count of their occurrence. + ListServiceStatusCount() (map[string]float64, error) + // UpdateService defines a function that updates an existing service. + UpdateService(*library.Service) error +} diff --git a/database/service/list.go b/database/service/list.go new file mode 100644 index 000000000..c7b1b6b13 --- /dev/null +++ b/database/service/list.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListServices gets a list of all services from the database. +func (e *engine) ListServices() ([]*library.Service, error) { + e.logger.Trace("listing all services from the database") + + // variables to store query results and return value + count := int64(0) + w := new([]database.Service) + services := []*library.Service{} + + // count the results + count, err := e.CountServices() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return services, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableService). + Find(&w). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, service := range *w { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := service + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.ToLibrary + services = append(services, tmp.ToLibrary()) + } + + return services, nil +} diff --git a/database/service/list_build.go b/database/service/list_build.go new file mode 100644 index 000000000..caffb2d5c --- /dev/null +++ b/database/service/list_build.go @@ -0,0 +1,65 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListServicesForBuild gets a list of all services from the database. +func (e *engine) ListServicesForBuild(b *library.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()) + + // variables to store query results and return value + count := int64(0) + s := new([]database.Service) + services := []*library.Service{} + + // count the results + count, err := e.CountServicesForBuild(b, filters) + if err != nil { + return services, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return services, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableService). + Where("build_id = ?", b.GetID()). + Where(filters). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, service := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := service + + // convert query result to library type + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.ToLibrary + services = append(services, tmp.ToLibrary()) + } + + return services, count, nil +} diff --git a/database/service/list_build_test.go b/database/service/list_build_test.go new file mode 100644 index 000000000..3b6d97161 --- /dev/null +++ b/database/service/list_build_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestService_Engine_ListServicesForBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(1) + _serviceTwo.SetNumber(2) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "services" WHERE build_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(2, 1, 1, 2, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "services" WHERE build_id = $1 ORDER BY id DESC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Service + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Service{_serviceTwo, _serviceOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Service{_serviceTwo, _serviceOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListServicesForBuild(_build, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListServicesForBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListServicesForBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListServicesForBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/list_image.go b/database/service/list_image.go new file mode 100644 index 000000000..6625420dc --- /dev/null +++ b/database/service/list_image.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "database/sql" + + "github.com/go-vela/types/constants" +) + +// ListServiceImageCount gets a list of all service images and the count of their occurrence from the database. +func (e *engine) ListServiceImageCount() (map[string]float64, error) { + e.logger.Tracef("getting count of all images for services from the database") + + // variables to store query results and return value + s := []struct { + Image sql.NullString + Count sql.NullInt32 + }{} + images := make(map[string]float64) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Select("image", " count(image) as count"). + Group("image"). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, value := range s { + // check if the image returned is not empty + if value.Image.Valid { + images[value.Image.String] = float64(value.Count.Int32) + } + } + + return images, nil +} diff --git a/database/service/list_image_test.go b/database/service/list_image_test.go new file mode 100644 index 000000000..f4e2f228e --- /dev/null +++ b/database/service/list_image_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_ListServiceImageCount(t *testing.T) { + // setup types + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(1) + _serviceTwo.SetNumber(2) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"image", "count"}).AddRow("bar", 2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT "image", count(image) as count FROM "services" GROUP BY "image"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want map[string]float64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: map[string]float64{"bar": 2}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: map[string]float64{"bar": 2}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListServiceImageCount() + + if test.failure { + if err == nil { + t.Errorf("ListServiceImageCount for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListServiceImageCount for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListServiceImageCount for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/list_status.go b/database/service/list_status.go new file mode 100644 index 000000000..01aedeac1 --- /dev/null +++ b/database/service/list_status.go @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "database/sql" + + "github.com/go-vela/types/constants" +) + +// ListServiceStatusCount gets a list of all service statuses and the count of their occurrence from the database. +func (e *engine) ListServiceStatusCount() (map[string]float64, error) { + e.logger.Tracef("getting count of all statuses for services from the database") + + // variables to store query results and return value + s := []struct { + Status sql.NullString + Count sql.NullInt32 + }{} + statuses := map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + } + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableService). + Select("status", " count(status) as count"). + Group("status"). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, value := range s { + // check if the status returned is not empty + if value.Status.Valid { + statuses[value.Status.String] = float64(value.Count.Int32) + } + } + + return statuses, nil +} diff --git a/database/service/list_status_test.go b/database/service/list_status_test.go new file mode 100644 index 000000000..85b7808af --- /dev/null +++ b/database/service/list_status_test.go @@ -0,0 +1,114 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_ListServiceStatusCount(t *testing.T) { + // setup types + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(1) + _serviceTwo.SetNumber(2) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"status", "count"}). + AddRow("pending", 0). + AddRow("failure", 0). + AddRow("killed", 0). + AddRow("running", 0). + AddRow("success", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT "status", count(status) as count FROM "services" GROUP BY "status"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want map[string]float64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + }, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: map[string]float64{ + "pending": 0, + "failure": 0, + "killed": 0, + "running": 0, + "success": 0, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListServiceStatusCount() + + if test.failure { + if err == nil { + t.Errorf("ListServiceStatusCount for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListServiceStatusCount for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListServiceStatusCount for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/list_test.go b/database/service/list_test.go new file mode 100644 index 000000000..72b60d5cf --- /dev/null +++ b/database/service/list_test.go @@ -0,0 +1,107 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestService_Engine_ListServices(t *testing.T) { + // setup types + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(2) + _serviceTwo.SetNumber(1) + _serviceTwo.SetName("bar") + _serviceTwo.SetImage("foo") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "services"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "build_id", "number", "name", "image", "stage", "status", "error", "exit_code", "created", "started", "finished", "host", "runtime", "distribution"}). + AddRow(1, 1, 1, 1, "foo", "bar", "", "", "", 0, 0, 0, 0, "", "", ""). + AddRow(2, 1, 2, 1, "bar", "foo", "", "", "", 0, 0, 0, 0, "", "", "") + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "services"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Service + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Service{_serviceOne, _serviceTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Service{_serviceOne, _serviceTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListServices() + + if test.failure { + if err == nil { + t.Errorf("ListServices for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListServices for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListServices for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/opts.go b/database/service/opts.go new file mode 100644 index 000000000..2201b1abd --- /dev/null +++ b/database/service/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Services. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Services. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the service engine + e.client = client + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Services. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the service engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Services. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the service engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/service/opts_test.go b/database/service/opts_test.go new file mode 100644 index 000000000..62ce5adf8 --- /dev/null +++ b/database/service/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestService_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestService_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestService_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/service/service.go b/database/service/service.go new file mode 100644 index 000000000..548164c0f --- /dev/null +++ b/database/service/service.go @@ -0,0 +1,74 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the ServiceInterface interface. + config struct { + // specifies to skip creating tables and indexes for the Service engine + SkipCreation bool + } + + // engine represents the service functionality that implements the ServiceInterface interface. + engine struct { + // engine configuration settings used in service functions + config *config + + // gorm.io/gorm database client used in service functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in service functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with services in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Service engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating service database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of services table in the database") + + return e, nil + } + + // create the services table + err := e.CreateServiceTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableService, err) + } + + return e, nil +} diff --git a/database/service/service_test.go b/database/service/service_test.go new file mode 100644 index 000000000..7749f43d3 --- /dev/null +++ b/database/service/service_test.go @@ -0,0 +1,224 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestService_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres service engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite service engine: %v", err) + } + + 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), + } +} diff --git a/database/service/table.go b/database/service/table.go new file mode 100644 index 000000000..48f8dc712 --- /dev/null +++ b/database/service/table.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres services table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +services ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + name VARCHAR(250), + image VARCHAR(500), + status VARCHAR(250), + error VARCHAR(500), + exit_code INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + host VARCHAR(250), + runtime VARCHAR(250), + distribution VARCHAR(250), + UNIQUE(build_id, number) +); +` + + // CreateSqliteTable represents a query to create the Sqlite services table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +services ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + build_id INTEGER, + number INTEGER, + name TEXT, + image TEXT, + status TEXT, + error TEXT, + exit_code INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + host TEXT, + runtime TEXT, + distribution TEXT, + UNIQUE(build_id, number) +); +` +) + +// CreateServiceTable creates the services table in the database. +func (e *engine) CreateServiceTable(driver string) error { + e.logger.Tracef("creating services table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the services table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the services table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/service/table_test.go b/database/service/table_test.go new file mode 100644 index 000000000..1b4d1b7de --- /dev/null +++ b/database/service/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_CreateServiceTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateServiceTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateServiceTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateServiceTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/service/update.go b/database/service/update.go new file mode 100644 index 000000000..ceaa7b6b8 --- /dev/null +++ b/database/service/update.go @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateService updates an existing service in the database. +func (e *engine) UpdateService(s *library.Service) error { + e.logger.WithFields(logrus.Fields{ + "service": s.GetNumber(), + }).Tracef("updating service %s in the database", s.GetName()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#ServiceFromLibrary + service := database.ServiceFromLibrary(s) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#Service.Validate + err := service.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableService). + Save(service). + Error +} diff --git a/database/service/update_test.go b/database/service/update_test.go new file mode 100644 index 000000000..e9fe61955 --- /dev/null +++ b/database/service/update_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_UpdateService(t *testing.T) { + // setup types + _service := testService() + _service.SetID(1) + _service.SetRepoID(1) + _service.SetBuildID(1) + _service.SetNumber(1) + _service.SetName("foo") + _service.SetImage("bar") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "services" SET "build_id"=$1,"repo_id"=$2,"number"=$3,"name"=$4,"image"=$5,"status"=$6,"error"=$7,"exit_code"=$8,"created"=$9,"started"=$10,"finished"=$11,"host"=$12,"runtime"=$13,"distribution"=$14 WHERE "id" = $15`). + WithArgs(1, 1, 1, "foo", "bar", nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_service) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateService(_service) + + if test.failure { + if err == nil { + t.Errorf("UpdateService for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateService for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/setup.go b/database/setup.go index fa13ecdff..a4b553d4d 100644 --- a/database/setup.go +++ b/database/setup.go @@ -41,7 +41,7 @@ type Setup struct { // Postgres creates and returns a Vela service capable of // integrating with a Postgres database system. -func (s *Setup) Postgres() (Service, error) { +func (s *Setup) Postgres() (Interface, error) { logrus.Trace("creating postgres database client from setup") // create new Postgres database service @@ -60,7 +60,7 @@ func (s *Setup) Postgres() (Service, error) { // Sqlite creates and returns a Vela service capable of // integrating with a Sqlite database system. -func (s *Setup) Sqlite() (Service, error) { +func (s *Setup) Sqlite() (Interface, error) { logrus.Trace("creating sqlite database client from setup") // create new Sqlite database service diff --git a/database/sqlite/ddl/service.go b/database/sqlite/ddl/service.go deleted file mode 100644 index 3b8f9527e..000000000 --- a/database/sqlite/ddl/service.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateServiceTable represents a query to - // create the services table for Vela. - CreateServiceTable = ` -CREATE TABLE -IF NOT EXISTS -services ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - build_id INTEGER, - number INTEGER, - name TEXT, - image TEXT, - status TEXT, - error TEXT, - exit_code INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - host TEXT, - runtime TEXT, - distribution TEXT, - UNIQUE(build_id, number) -); -` -) diff --git a/database/sqlite/dml/service.go b/database/sqlite/dml/service.go deleted file mode 100644 index 66e009406..000000000 --- a/database/sqlite/dml/service.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListServices represents a query to - // list all services in the database. - ListServices = ` -SELECT * -FROM services; -` - - // ListBuildServices represents a query to list - // all services for a build_id in the database. - ListBuildServices = ` -SELECT * -FROM services -WHERE build_id = ? -ORDER BY id DESC -LIMIT ? -OFFSET ?; -` - - // SelectBuildServicesCount represents a query to select - // the count of services for a build_id in the database. - SelectBuildServicesCount = ` -SELECT count(*) as count -FROM services -WHERE build_id = ? -` - - // SelectServiceImagesCount represents a query to select - // the count of an images appearances in the database. - SelectServiceImagesCount = ` -SELECT image, count(image) as count -FROM services -GROUP BY image -` - - // SelectServiceStatusesCount represents a query to select - // the count of service status appearances in the database. - SelectServiceStatusesCount = ` -SELECT status, count(status) as count -FROM services -GROUP BY status; -` - - // SelectBuildService represents a query to select a - // service for a build_id and number in the database. - SelectBuildService = ` -SELECT * -FROM services -WHERE build_id = ? -AND number = ? -LIMIT 1; -` - - // DeleteService represents a query to - // remove a service from the database. - DeleteService = ` -DELETE -FROM services -WHERE id = ?; -` -) diff --git a/database/sqlite/service.go b/database/sqlite/service.go deleted file mode 100644 index ecc9dad6b..000000000 --- a/database/sqlite/service.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetService gets a service by number and build ID from the database. -func (c *client) GetService(number int, b *library.Build) (*library.Service, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "service": number, - }).Tracef("getting service %d for build %d from the database", number, b.GetNumber()) - - // variable to store query results - s := new(database.Service) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableService). - Raw(dml.SelectBuildService, b.GetID(), number). - Scan(s) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return s.ToLibrary(), result.Error -} - -// CreateService creates a new service in the database. -func (c *client) CreateService(s *library.Service) error { - c.Logger.WithFields(logrus.Fields{ - "service": s.GetNumber(), - }).Tracef("creating service %s in the database", s.GetName()) - - // cast to database type - service := database.ServiceFromLibrary(s) - - // validate the necessary fields are populated - err := service.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableService). - Create(service).Error -} - -// UpdateService updates a service in the database. -func (c *client) UpdateService(s *library.Service) error { - c.Logger.WithFields(logrus.Fields{ - "service": s.GetNumber(), - }).Tracef("updating service %s in the database", s.GetName()) - - // cast to database type - service := database.ServiceFromLibrary(s) - - // validate the necessary fields are populated - err := service.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableService). - Save(service).Error -} - -// DeleteService deletes a service by unique ID from the database. -func (c *client) DeleteService(id int64) error { - c.Logger.Tracef("deleting service %d from the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableService). - Exec(dml.DeleteService, id).Error -} diff --git a/database/sqlite/service_count.go b/database/sqlite/service_count.go deleted file mode 100644 index 4979e9527..000000000 --- a/database/sqlite/service_count.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildServiceCount gets a count of all services by build ID from the database. -func (c *client) GetBuildServiceCount(b *library.Build) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("getting count of services for build %d from the database", b.GetNumber()) - - // variable to store query results - var s int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableService). - Raw(dml.SelectBuildServicesCount, b.GetID()). - Pluck("count", &s).Error - - return s, err -} - -// GetServiceImageCount gets a count of all service images -// and the count of their occurrence in the database. -func (c *client) GetServiceImageCount() (map[string]float64, error) { - c.Logger.Tracef("getting count of all images for services from the database") - - type imageCount struct { - Image string - Count int - } - - // variable to store query results - images := new([]imageCount) - counts := make(map[string]float64) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableService). - Raw(dml.SelectServiceImagesCount). - Scan(images).Error - - for _, image := range *images { - counts[image.Image] = float64(image.Count) - } - - return counts, err -} - -// GetServiceStatusCount gets a list of all service statuses -// and the count of their occurrence in the database. -func (c *client) GetServiceStatusCount() (map[string]float64, error) { - c.Logger.Trace("getting count of all statuses for services from the database") - - type statusCount struct { - Status string - Count int - } - - // variable to store query results - s := new([]statusCount) - counts := map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - } - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableService). - Raw(dml.SelectServiceStatusesCount). - Scan(s).Error - - for _, status := range *s { - counts[status.Status] = float64(status.Count) - } - - return counts, err -} diff --git a/database/sqlite/service_count_test.go b/database/sqlite/service_count_test.go deleted file mode 100644 index 13d533a82..000000000 --- a/database/sqlite/service_count_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the service table - err = _database.Sqlite.Exec(ddl.CreateServiceTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableService, err) - } -} - -func TestSqlite_Client_GetBuildServiceCount(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _serviceOne := testService() - _serviceOne.SetID(1) - _serviceOne.SetRepoID(1) - _serviceOne.SetBuildID(1) - _serviceOne.SetNumber(1) - _serviceOne.SetName("foo") - _serviceOne.SetImage("bar") - - _serviceTwo := testService() - _serviceTwo.SetID(2) - _serviceTwo.SetRepoID(1) - _serviceTwo.SetBuildID(1) - _serviceTwo.SetNumber(2) - _serviceTwo.SetName("bar") - _serviceTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - // create the services in the database - err := _database.CreateService(_serviceOne) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - - err = _database.CreateService(_serviceTwo) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - - got, err := _database.GetBuildServiceCount(_build) - - if test.failure { - if err == nil { - t.Errorf("GetBuildServiceCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildServiceCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildServiceCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetServiceImageCount(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceImageCount() - - if test.failure { - if err == nil { - t.Errorf("GetServiceImageCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceImageCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceImageCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetServiceStatusCount(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want map[string]float64 - }{ - { - failure: false, - want: map[string]float64{ - "pending": 0, - "failure": 0, - "killed": 0, - "running": 0, - "success": 0, - }, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetServiceStatusCount() - - if test.failure { - if err == nil { - t.Errorf("GetServiceStatusCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceStatusCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceStatusCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/service_list.go b/database/sqlite/service_list.go deleted file mode 100644 index eb16406af..000000000 --- a/database/sqlite/service_list.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetServiceList gets a list of all services from the database. -func (c *client) GetServiceList() ([]*library.Service, error) { - c.Logger.Trace("listing services from the database") - - // variable to store query results - s := new([]database.Service) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableService). - Raw(dml.ListServices). - Scan(s).Error - - // variable we want to return - services := []*library.Service{} - // iterate through all query results - for _, service := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := service - - // convert query result to library type - services = append(services, tmp.ToLibrary()) - } - - return services, err -} - -// GetBuildServiceList gets a list of services by build ID from the database. -func (c *client) GetBuildServiceList(b *library.Build, page, perPage int) ([]*library.Service, error) { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("listing services for build %d from the database", b.GetNumber()) - - // variable to store query results - s := new([]database.Service) - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableService). - Raw(dml.ListBuildServices, b.GetID(), perPage, offset). - Scan(s).Error - - // variable we want to return - services := []*library.Service{} - // iterate through all query results - for _, service := range *s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := service - - // convert query result to library type - services = append(services, tmp.ToLibrary()) - } - - return services, err -} diff --git a/database/sqlite/service_list_test.go b/database/sqlite/service_list_test.go deleted file mode 100644 index a9c556d97..000000000 --- a/database/sqlite/service_list_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the service table - err = _database.Sqlite.Exec(ddl.CreateServiceTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableService, err) - } -} - -func TestSqlite_Client_GetServiceList(t *testing.T) { - // setup types - _serviceOne := testService() - _serviceOne.SetID(1) - _serviceOne.SetRepoID(1) - _serviceOne.SetBuildID(1) - _serviceOne.SetNumber(1) - _serviceOne.SetName("foo") - _serviceOne.SetImage("bar") - - _serviceTwo := testService() - _serviceTwo.SetID(2) - _serviceTwo.SetRepoID(1) - _serviceTwo.SetBuildID(1) - _serviceTwo.SetNumber(2) - _serviceTwo.SetName("bar") - _serviceTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Service - }{ - { - failure: false, - want: []*library.Service{_serviceOne, _serviceTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - for _, service := range test.want { - // create the service in the database - err := _database.CreateService(service) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - } - - got, err := _database.GetServiceList() - - if test.failure { - if err == nil { - t.Errorf("GetServiceList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetServiceList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetServiceList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetBuildServiceList(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _serviceOne := testService() - _serviceOne.SetID(1) - _serviceOne.SetRepoID(1) - _serviceOne.SetBuildID(1) - _serviceOne.SetNumber(1) - _serviceOne.SetName("foo") - _serviceOne.SetImage("bar") - - _serviceTwo := testService() - _serviceTwo.SetID(2) - _serviceTwo.SetRepoID(1) - _serviceTwo.SetBuildID(1) - _serviceTwo.SetNumber(2) - _serviceTwo.SetName("bar") - _serviceTwo.SetImage("foo") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Service - }{ - { - failure: false, - want: []*library.Service{_serviceTwo, _serviceOne}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - for _, service := range test.want { - // create the service in the database - err := _database.CreateService(service) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - } - - got, err := _database.GetBuildServiceList(_build, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetBuildServiceList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildServiceList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildServiceList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/service_test.go b/database/sqlite/service_test.go deleted file mode 100644 index 3982ddf36..000000000 --- a/database/sqlite/service_test.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetService(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Service - }{ - { - failure: false, - want: _service, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the service in the database - err := _database.CreateService(test.want) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - } - - got, err := _database.GetService(1, _build) - - // cleanup the services table - _ = _database.Sqlite.Exec("DELETE FROM services;") - - if test.failure { - if err == nil { - t.Errorf("GetService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetService returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetService is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateService(t *testing.T) { - // setup types - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - err := _database.CreateService(_service) - - if test.failure { - if err == nil { - t.Errorf("CreateService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateService returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateService(t *testing.T) { - // setup types - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - // create the service in the database - err := _database.CreateService(_service) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - - err = _database.UpdateService(_service) - - if test.failure { - if err == nil { - t.Errorf("UpdateService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateService returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteService(t *testing.T) { - // setup types - _service := testService() - _service.SetID(1) - _service.SetRepoID(1) - _service.SetBuildID(1) - _service.SetNumber(1) - _service.SetName("foo") - _service.SetImage("bar") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the services table - defer _database.Sqlite.Exec("delete from services;") - - // create the service in the database - err := _database.CreateService(_service) - if err != nil { - t.Errorf("unable to create test service: %v", err) - } - - err = _database.DeleteService(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteService should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteService returned err: %v", err) - } - } -} - -// testService is a test helper function to create a -// library Service type with all fields set to their -// zero values. -func testService() *library.Service { - i64 := int64(0) - i := 0 - str := "" - - return &library.Service{ - ID: &i64, - BuildID: &i64, - RepoID: &i64, - Number: &i, - Name: &str, - Image: &str, - Status: &str, - Error: &str, - ExitCode: &i, - Created: &i64, - Started: &i64, - Finished: &i64, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index abc382a37..d16f7cf09 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -13,6 +13,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/secret" + "github.com/go-vela/server/database/service" "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" @@ -48,22 +49,24 @@ type ( Sqlite *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry - // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookService - hook.HookService - // https://pkg.go.dev/github.com/go-vela/server/database/log#LogService - log.LogService - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineService - pipeline.PipelineService - // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoService - repo.RepoService - // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretService - secret.SecretService - // https://pkg.go.dev/github.com/go-vela/server/database/step#StepService - step.StepService - // https://pkg.go.dev/github.com/go-vela/server/database/user#UserService - user.UserService - // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerService - worker.WorkerService + // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface + hook.HookInterface + // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface + log.LogInterface + // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineInterface + pipeline.PipelineInterface + // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface + repo.RepoInterface + // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface + secret.SecretInterface + // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface + service.ServiceInterface + // https://pkg.go.dev/github.com/go-vela/server/database/step#StepInterface + step.StepInterface + // https://pkg.go.dev/github.com/go-vela/server/database/user#UserInterface + user.UserInterface + // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerInterface + worker.WorkerInterface } ) @@ -245,12 +248,6 @@ func createTables(c *client) error { return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } - // create the services table - err = c.Sqlite.Exec(ddl.CreateServiceTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableService, err) - } - return nil } @@ -290,10 +287,10 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error - // create the database agnostic hook service + // create the database agnostic engine for hooks // // https://pkg.go.dev/github.com/go-vela/server/database/hook#New - c.HookService, err = hook.New( + c.HookInterface, err = hook.New( hook.WithClient(c.Sqlite), hook.WithLogger(c.Logger), hook.WithSkipCreation(c.config.SkipCreation), @@ -302,10 +299,10 @@ func createServices(c *client) error { return err } - // create the database agnostic log service + // create the database agnostic engine for logs // // https://pkg.go.dev/github.com/go-vela/server/database/log#New - c.LogService, err = log.New( + c.LogInterface, err = log.New( log.WithClient(c.Sqlite), log.WithCompressionLevel(c.config.CompressionLevel), log.WithLogger(c.Logger), @@ -315,10 +312,10 @@ func createServices(c *client) error { return err } - // create the database agnostic pipeline service + // create the database agnostic engine for pipelines // // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New - c.PipelineService, err = pipeline.New( + c.PipelineInterface, err = pipeline.New( pipeline.WithClient(c.Sqlite), pipeline.WithCompressionLevel(c.config.CompressionLevel), pipeline.WithLogger(c.Logger), @@ -328,10 +325,10 @@ func createServices(c *client) error { return err } - // create the database agnostic repo service + // create the database agnostic engine for repos // // https://pkg.go.dev/github.com/go-vela/server/database/repo#New - c.RepoService, err = repo.New( + c.RepoInterface, err = repo.New( repo.WithClient(c.Sqlite), repo.WithEncryptionKey(c.config.EncryptionKey), repo.WithLogger(c.Logger), @@ -341,10 +338,10 @@ func createServices(c *client) error { return err } - // create the database agnostic secret service + // create the database agnostic engine for secrets // // https://pkg.go.dev/github.com/go-vela/server/database/secret#New - c.SecretService, err = secret.New( + c.SecretInterface, err = secret.New( secret.WithClient(c.Sqlite), secret.WithEncryptionKey(c.config.EncryptionKey), secret.WithLogger(c.Logger), @@ -354,10 +351,22 @@ func createServices(c *client) error { return err } - // create the database agnostic step service + // create the database agnostic engine for services + // + // https://pkg.go.dev/github.com/go-vela/server/database/service#New + c.ServiceInterface, err = service.New( + service.WithClient(c.Sqlite), + service.WithLogger(c.Logger), + service.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for steps // // https://pkg.go.dev/github.com/go-vela/server/database/step#New - c.StepService, err = step.New( + c.StepInterface, err = step.New( step.WithClient(c.Sqlite), step.WithLogger(c.Logger), step.WithSkipCreation(c.config.SkipCreation), @@ -366,10 +375,10 @@ func createServices(c *client) error { return err } - // create the database agnostic user service + // create the database agnostic engine for users // // https://pkg.go.dev/github.com/go-vela/server/database/user#New - c.UserService, err = user.New( + c.UserInterface, err = user.New( user.WithClient(c.Sqlite), user.WithEncryptionKey(c.config.EncryptionKey), user.WithLogger(c.Logger), @@ -379,10 +388,10 @@ func createServices(c *client) error { return err } - // create the database agnostic worker service + // create the database agnostic engine for workers // // https://pkg.go.dev/github.com/go-vela/server/database/worker#New - c.WorkerService, err = worker.New( + c.WorkerInterface, err = worker.New( worker.WithClient(c.Sqlite), worker.WithLogger(c.Logger), worker.WithSkipCreation(c.config.SkipCreation), diff --git a/database/step/service.go b/database/step/interface.go similarity index 95% rename from database/step/service.go rename to database/step/interface.go index 4007e537a..a410f2600 100644 --- a/database/step/service.go +++ b/database/step/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// StepService represents the Vela interface for step +// StepInterface represents the Vela interface for step // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type StepService interface { +type StepInterface interface { // Step Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/step/step.go b/database/step/step.go index 94017b04c..43e905797 100644 --- a/database/step/step.go +++ b/database/step/step.go @@ -14,13 +14,13 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the StepService interface. + // config represents the settings required to create the engine that implements the StepInterface interface. config struct { // specifies to skip creating tables and indexes for the Step engine SkipCreation bool } - // engine represents the step functionality that implements the StepService interface. + // engine represents the step functionality that implements the StepInterface interface. engine struct { // engine configuration settings used in step functions config *config diff --git a/database/user/service.go b/database/user/interface.go similarity index 94% rename from database/user/service.go rename to database/user/interface.go index b33c8cd63..ad5986fad 100644 --- a/database/user/service.go +++ b/database/user/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// UserService represents the Vela interface for user +// UserInterface represents the Vela interface for user // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type UserService interface { +type UserInterface interface { // User Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/user/user.go b/database/user/user.go index 9bef43843..99e1f9701 100644 --- a/database/user/user.go +++ b/database/user/user.go @@ -14,7 +14,7 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the UserService interface. + // config represents the settings required to create the engine that implements the UserInterface interface. config struct { // specifies the encryption key to use for the User engine EncryptionKey string @@ -22,7 +22,7 @@ type ( SkipCreation bool } - // engine represents the user functionality that implements the UserService interface. + // engine represents the user functionality that implements the UserInterface interface. engine struct { // engine configuration settings used in user functions config *config diff --git a/database/worker/service.go b/database/worker/interface.go similarity index 94% rename from database/worker/service.go rename to database/worker/interface.go index b02c6f854..9e7fe1169 100644 --- a/database/worker/service.go +++ b/database/worker/interface.go @@ -8,11 +8,11 @@ import ( "github.com/go-vela/types/library" ) -// WorkerService represents the Vela interface for worker +// WorkerInterface represents the Vela interface for worker // functions with the supported Database backends. // //nolint:revive // ignore name stutter -type WorkerService interface { +type WorkerInterface interface { // Worker Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language diff --git a/database/worker/worker.go b/database/worker/worker.go index d870fb1ba..d18aa6408 100644 --- a/database/worker/worker.go +++ b/database/worker/worker.go @@ -14,13 +14,13 @@ import ( ) type ( - // config represents the settings required to create the engine that implements the WorkerService interface. + // config represents the settings required to create the engine that implements the WorkerInterface interface. config struct { // specifies to skip creating tables and indexes for the Worker engine SkipCreation bool } - // engine represents the worker functionality that implements the WorkerService interface. + // engine represents the worker functionality that implements the WorkerInterface interface. engine struct { // engine configuration settings used in worker functions config *config diff --git a/router/middleware/database.go b/router/middleware/database.go index f4037b7df..fbbf91eea 100644 --- a/router/middleware/database.go +++ b/router/middleware/database.go @@ -11,7 +11,7 @@ import ( // Database is a middleware function that initializes the database and // attaches to the context of every http.Request. -func Database(d database.Service) gin.HandlerFunc { +func Database(d database.Interface) gin.HandlerFunc { return func(c *gin.Context) { database.ToContext(c, d) c.Next() diff --git a/router/middleware/database_test.go b/router/middleware/database_test.go index dd8b95a37..a3480a9f5 100644 --- a/router/middleware/database_test.go +++ b/router/middleware/database_test.go @@ -17,7 +17,7 @@ import ( func TestMiddleware_Database(t *testing.T) { // setup types - var got database.Service + var got database.Interface want, _ := sqlite.NewTest() diff --git a/router/middleware/service/service.go b/router/middleware/service/service.go index be36fb7b6..30abf92d0 100644 --- a/router/middleware/service/service.go +++ b/router/middleware/service/service.go @@ -75,7 +75,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading service %s/%d/%d", r.GetFullName(), b.GetNumber(), number) - s, err := database.FromContext(c).GetService(number, b) + s, err := database.FromContext(c).GetServiceForBuild(b, number) if err != nil { retErr := fmt.Errorf("unable to read service %s/%d/%d: %w", r.GetFullName(), b.GetNumber(), number, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/secret/native/native.go b/secret/native/native.go index 4109d8e4f..99b015715 100644 --- a/secret/native/native.go +++ b/secret/native/native.go @@ -12,7 +12,7 @@ import ( // client represents a struct to hold native secret setup. type client struct { // client to interact with database for secret operations - Database database.Service + Database database.Interface // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry } @@ -25,7 +25,7 @@ func New(opts ...ClientOpt) (*client, error) { c := new(client) // create new fields - c.Database = *new(database.Service) + c.Database = *new(database.Interface) // create new logger for the client // diff --git a/secret/native/native_test.go b/secret/native/native_test.go index 070dba97b..1b7daaa2f 100644 --- a/secret/native/native_test.go +++ b/secret/native/native_test.go @@ -23,8 +23,8 @@ func TestNative_New(t *testing.T) { // setup tests tests := []struct { failure bool - database database.Service - want database.Service + database database.Interface + want database.Interface }{ { failure: false, diff --git a/secret/native/opts.go b/secret/native/opts.go index 160b554c6..0c4396348 100644 --- a/secret/native/opts.go +++ b/secret/native/opts.go @@ -14,7 +14,7 @@ import ( type ClientOpt func(*client) error // WithDatabase sets the Vela database service in the secret client for Native. -func WithDatabase(d database.Service) ClientOpt { +func WithDatabase(d database.Interface) ClientOpt { return func(c *client) error { c.Logger.Trace("configuring database service in native secret client") diff --git a/secret/native/opts_test.go b/secret/native/opts_test.go index dea0ef22e..1cda40700 100644 --- a/secret/native/opts_test.go +++ b/secret/native/opts_test.go @@ -24,8 +24,8 @@ func TestNative_ClientOpt_WithDatabase(t *testing.T) { // setup tests tests := []struct { failure bool - database database.Service - want database.Service + database database.Interface + want database.Interface }{ { failure: false, diff --git a/secret/setup.go b/secret/setup.go index cdebe406b..e0a28a8a8 100644 --- a/secret/setup.go +++ b/secret/setup.go @@ -13,7 +13,6 @@ import ( "github.com/go-vela/server/secret/native" "github.com/go-vela/server/secret/vault" "github.com/go-vela/types/constants" - "github.com/sirupsen/logrus" ) @@ -27,7 +26,7 @@ type Setup struct { Driver string // specifies the database service to use for the secret client - Database database.Service + Database database.Interface // specifies the address to use for the secret client Address string From 3aa414e46ced00ce3019f0d58120801a7c4cd233 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 15 May 2023 11:58:37 -0500 Subject: [PATCH 228/298] refactor(api): move worker logic to separate package (#828) * refactor(api): move worker handlers to new package * chore: address review feedback Co-authored-by: Jacob Floyd --------- Co-authored-by: Jacob Floyd Co-authored-by: Kelly Merrick Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> Co-authored-by: Driscoll <43050003+chrispdriscoll@users.noreply.github.com> Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/worker.go | 509 ------------------------------------------ api/worker/create.go | 141 ++++++++++++ api/worker/delete.go | 70 ++++++ api/worker/get.go | 69 ++++++ api/worker/list.go | 62 +++++ api/worker/refresh.go | 138 ++++++++++++ api/worker/update.go | 115 ++++++++++ router/worker.go | 20 +- 8 files changed, 605 insertions(+), 519 deletions(-) delete mode 100644 api/worker.go create mode 100644 api/worker/create.go create mode 100644 api/worker/delete.go create mode 100644 api/worker/get.go create mode 100644 api/worker/list.go create mode 100644 api/worker/refresh.go create mode 100644 api/worker/update.go diff --git a/api/worker.go b/api/worker.go deleted file mode 100644 index 5d949779e..000000000 --- a/api/worker.go +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strings" - "time" - - "github.com/go-vela/server/internal/token" - "github.com/go-vela/server/router/middleware/claims" - "github.com/go-vela/server/router/middleware/user" - "github.com/go-vela/types/constants" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/worker" - "github.com/go-vela/server/util" - - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/workers workers CreateWorker -// -// Create a worker for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Payload containing the worker to create -// required: true -// schema: -// "$ref": "#/definitions/Worker" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the worker and retrieved auth token -// schema: -// "$ref": "#definitions/Token" -// '400': -// description: Unable to create the worker -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the worker -// schema: -// "$ref": "#/definitions/Error" - -// CreateWorker represents the API handler to -// create a worker in the configured backend. -func CreateWorker(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - cl := claims.Retrieve(c) - - // capture body from API request - input := new(library.Worker) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new worker: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // verify input host name matches worker hostname - if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, input.GetHostname()) { - retErr := fmt.Errorf("unable to add worker; claims subject %s does not match worker hostname %s", cl.Subject, input.GetHostname()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - input.SetLastCheckedIn(time.Now().Unix()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - "worker": input.GetHostname(), - }).Infof("creating new worker %s", input.GetHostname()) - - err = database.FromContext(c).CreateWorker(input) - if err != nil { - retErr := fmt.Errorf("unable to create worker: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - switch cl.TokenType { - // if symmetric token configured, send back symmetric token - case constants.ServerWorkerTokenType: - if secret, ok := c.Value("secret").(string); ok { - tkn := new(library.Token) - tkn.SetToken(secret) - c.JSON(http.StatusCreated, tkn) - - return - } - - retErr := fmt.Errorf("symmetric token provided but not configured in server") - util.HandleError(c, http.StatusBadRequest, retErr) - - return - // if worker register token, send back auth token - default: - tm := c.MustGet("token-manager").(*token.Manager) - - wmto := &token.MintTokenOpts{ - TokenType: constants.WorkerAuthTokenType, - TokenDuration: tm.WorkerAuthTokenDuration, - Hostname: cl.Subject, - } - - tkn := new(library.Token) - - wt, err := tm.MintToken(wmto) - if err != nil { - retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", input.GetHostname(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - tkn.SetToken(wt) - - c.JSON(http.StatusCreated, tkn) - } -} - -// swagger:operation GET /api/v1/workers workers GetWorkers -// -// Retrieve a list of workers for the configured backend -// -// --- -// produces: -// - application/json -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the list of workers -// schema: -// type: array -// items: -// "$ref": "#/definitions/Worker" -// '500': -// description: Unable to retrieve the list of workers -// schema: -// "$ref": "#/definitions/Error" - -// GetWorkers represents the API handler to capture a -// list of workers from the configured backend. -func GetWorkers(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - }).Info("reading workers") - - w, err := database.FromContext(c).ListWorkers() - if err != nil { - retErr := fmt.Errorf("unable to get workers: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, w) -} - -// swagger:operation GET /api/v1/workers/{worker} workers GetWorker -// -// Retrieve a worker for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: worker -// description: Hostname of the worker -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the worker -// schema: -// "$ref": "#/definitions/Worker" -// '404': -// description: Unable to retrieve the worker -// schema: -// "$ref": "#/definitions/Error" - -// GetWorker represents the API handler to capture a -// worker from the configured backend. -func GetWorker(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - w := worker.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - "worker": w.GetHostname(), - }).Infof("reading worker %s", w.GetHostname()) - - w, err := database.FromContext(c).GetWorkerForHostname(w.GetHostname()) - if err != nil { - retErr := fmt.Errorf("unable to get workers: %w", err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - c.JSON(http.StatusOK, w) -} - -// swagger:operation PUT /api/v1/workers/{worker} workers UpdateWorker -// -// Update a worker for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Payload containing the worker to update -// required: true -// schema: -// "$ref": "#/definitions/Worker" -// - in: path -// name: worker -// description: Name of the worker -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the worker -// schema: -// "$ref": "#/definitions/Worker" -// '400': -// description: Unable to update the worker -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to update the worker -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the worker -// schema: -// "$ref": "#/definitions/Error" - -// UpdateWorker represents the API handler to -// update a worker in the configured backend. -func UpdateWorker(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - w := worker.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - "worker": w.GetHostname(), - }).Infof("updating worker %s", w.GetHostname()) - - // capture body from API request - input := new(library.Worker) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for worker %s: %w", w.GetHostname(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - if len(input.GetAddress()) > 0 { - // update admin if set - w.SetAddress(input.GetAddress()) - } - - if len(input.GetRoutes()) > 0 { - // update routes if set - w.SetRoutes(input.GetRoutes()) - } - - if input.GetActive() { - // update active if set - w.SetActive(input.GetActive()) - } - - // send API call to update the worker - err = database.FromContext(c).UpdateWorker(w) - if err != nil { - retErr := fmt.Errorf("unable to update worker %s: %w", w.GetHostname(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated worker - w, _ = database.FromContext(c).GetWorkerForHostname(w.GetHostname()) - - c.JSON(http.StatusOK, w) -} - -// swagger:operation POST /api/v1/workers/{worker}/refresh workers RefreshWorkerAuth -// -// Refresh authorization token for worker -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: worker -// description: Name of the worker -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully refreshed auth -// schema: -// "$ref": "#/definitions/Token" -// '400': -// description: Unable to refresh worker auth -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to refresh worker auth -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to refresh worker auth -// schema: -// "$ref": "#/definitions/Error" - -// RefreshWorkerAuth represents the API handler to -// refresh the auth token for a worker. -func RefreshWorkerAuth(c *gin.Context) { - // capture middleware values - w := worker.Retrieve(c) - cl := claims.Retrieve(c) - - // if we are not using a symmetric token, and the subject does not match the input, request should be denied - if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, w.GetHostname()) { - retErr := fmt.Errorf("unable to refresh worker auth: claims subject %s does not match worker hostname %s", cl.Subject, w.GetHostname()) - - logrus.WithFields(logrus.Fields{ - "subject": cl.Subject, - "worker": w.GetHostname(), - }).Warnf("attempted refresh of worker %s using token from worker %s", w.GetHostname(), cl.Subject) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // set last checked in time - w.SetLastCheckedIn(time.Now().Unix()) - - // send API call to update the worker - err := database.FromContext(c).UpdateWorker(w) - if err != nil { - retErr := fmt.Errorf("unable to update worker %s: %w", w.GetHostname(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "worker": w.GetHostname(), - }).Infof("refreshing worker %s authentication", w.GetHostname()) - - switch cl.TokenType { - // if symmetric token configured, send back symmetric token - case constants.ServerWorkerTokenType: - if secret, ok := c.Value("secret").(string); ok { - tkn := new(library.Token) - tkn.SetToken(secret) - c.JSON(http.StatusOK, tkn) - - return - } - - retErr := fmt.Errorf("symmetric token provided but not configured in server") - util.HandleError(c, http.StatusBadRequest, retErr) - - return - // if worker auth / register token, send back auth token - case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: - tm := c.MustGet("token-manager").(*token.Manager) - - wmto := &token.MintTokenOpts{ - TokenType: constants.WorkerAuthTokenType, - TokenDuration: tm.WorkerAuthTokenDuration, - Hostname: cl.Subject, - } - - tkn := new(library.Token) - - wt, err := tm.MintToken(wmto) - if err != nil { - retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", w.GetHostname(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - tkn.SetToken(wt) - - c.JSON(http.StatusOK, tkn) - } -} - -// swagger:operation DELETE /api/v1/workers/{worker} workers DeleteWorker -// -// Delete a worker for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: worker -// description: Name of the worker -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted of worker -// schema: -// type: string -// '500': -// description: Unable to delete worker -// schema: -// "$ref": "#/definitions/Error" - -// DeleteWorker represents the API handler to remove -// a worker from the configured backend. -func DeleteWorker(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - w := worker.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "user": u.GetName(), - "worker": w.GetHostname(), - }).Infof("deleting worker %s", w.GetHostname()) - - // send API call to remove the step - err := database.FromContext(c).DeleteWorker(w) - if err != nil { - retErr := fmt.Errorf("unable to delete worker %s: %w", w.GetHostname(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("worker %s deleted", w.GetHostname())) -} diff --git a/api/worker/create.go b/api/worker/create.go new file mode 100644 index 000000000..b7d1bf286 --- /dev/null +++ b/api/worker/create.go @@ -0,0 +1,141 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/workers workers CreateWorker +// +// Create a worker for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Payload containing the worker to create +// required: true +// schema: +// "$ref": "#/definitions/Worker" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the worker and retrieved auth token +// schema: +// "$ref": "#definitions/Token" +// '400': +// description: Unable to create the worker +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the worker +// schema: +// "$ref": "#/definitions/Error" + +// CreateWorker represents the API handler to +// create a worker in the configured backend. +func CreateWorker(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + cl := claims.Retrieve(c) + + // capture body from API request + input := new(library.Worker) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new worker: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // verify input host name matches worker hostname + if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, input.GetHostname()) { + retErr := fmt.Errorf("unable to add worker; claims subject %s does not match worker hostname %s", cl.Subject, input.GetHostname()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + input.SetLastCheckedIn(time.Now().Unix()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + "worker": input.GetHostname(), + }).Infof("creating new worker %s", input.GetHostname()) + + err = database.FromContext(c).CreateWorker(input) + if err != nil { + retErr := fmt.Errorf("unable to create worker: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + switch cl.TokenType { + // if symmetric token configured, send back symmetric token + case constants.ServerWorkerTokenType: + if secret, ok := c.Value("secret").(string); ok { + tkn := new(library.Token) + tkn.SetToken(secret) + c.JSON(http.StatusCreated, tkn) + + return + } + + retErr := fmt.Errorf("symmetric token provided but not configured in server") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + // if worker register token, send back auth token + default: + tm := c.MustGet("token-manager").(*token.Manager) + + wmto := &token.MintTokenOpts{ + TokenType: constants.WorkerAuthTokenType, + TokenDuration: tm.WorkerAuthTokenDuration, + Hostname: cl.Subject, + } + + tkn := new(library.Token) + + wt, err := tm.MintToken(wmto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", input.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + tkn.SetToken(wt) + + c.JSON(http.StatusCreated, tkn) + } +} diff --git a/api/worker/delete.go b/api/worker/delete.go new file mode 100644 index 000000000..fa0ad5e65 --- /dev/null +++ b/api/worker/delete.go @@ -0,0 +1,70 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/workers/{worker} workers DeleteWorker +// +// Delete a worker for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: worker +// description: Name of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted of worker +// schema: +// type: string +// '500': +// description: Unable to delete worker +// schema: +// "$ref": "#/definitions/Error" + +// DeleteWorker represents the API handler to remove +// a worker from the configured backend. +func DeleteWorker(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + w := worker.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + "worker": w.GetHostname(), + }).Infof("deleting worker %s", w.GetHostname()) + + // send API call to remove the step + err := database.FromContext(c).DeleteWorker(w) + if err != nil { + retErr := fmt.Errorf("unable to delete worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("worker %s deleted", w.GetHostname())) +} diff --git a/api/worker/get.go b/api/worker/get.go new file mode 100644 index 000000000..88b323532 --- /dev/null +++ b/api/worker/get.go @@ -0,0 +1,69 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/workers/{worker} workers GetWorker +// +// Retrieve a worker for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: worker +// description: Hostname of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the worker +// schema: +// "$ref": "#/definitions/Worker" +// '404': +// description: Unable to retrieve the worker +// schema: +// "$ref": "#/definitions/Error" + +// GetWorker represents the API handler to capture a +// worker from the configured backend. +func GetWorker(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + w := worker.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + "worker": w.GetHostname(), + }).Infof("reading worker %s", w.GetHostname()) + + w, err := database.FromContext(c).GetWorkerForHostname(w.GetHostname()) + if err != nil { + retErr := fmt.Errorf("unable to get workers: %w", err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + c.JSON(http.StatusOK, w) +} diff --git a/api/worker/list.go b/api/worker/list.go new file mode 100644 index 000000000..2587ba07f --- /dev/null +++ b/api/worker/list.go @@ -0,0 +1,62 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/workers workers ListWorkers +// +// Retrieve a list of workers for the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the list of workers +// schema: +// type: array +// items: +// "$ref": "#/definitions/Worker" +// '500': +// description: Unable to retrieve the list of workers +// schema: +// "$ref": "#/definitions/Error" + +// ListWorkers represents the API handler to capture a +// list of workers from the configured backend. +func ListWorkers(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + }).Info("reading workers") + + w, err := database.FromContext(c).ListWorkers() + if err != nil { + retErr := fmt.Errorf("unable to get workers: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, w) +} diff --git a/api/worker/refresh.go b/api/worker/refresh.go new file mode 100644 index 000000000..cd4aa7ef3 --- /dev/null +++ b/api/worker/refresh.go @@ -0,0 +1,138 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/router/middleware/worker" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/workers/{worker}/refresh workers RefreshWorkerAuth +// +// Refresh authorization token for worker +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: worker +// description: Name of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully refreshed auth +// schema: +// "$ref": "#/definitions/Token" +// '400': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to refresh worker auth +// schema: +// "$ref": "#/definitions/Error" + +// Refresh represents the API handler to +// refresh the auth token for a worker. +func Refresh(c *gin.Context) { + // capture middleware values + w := worker.Retrieve(c) + cl := claims.Retrieve(c) + + // if we are not using a symmetric token, and the subject does not match the input, request should be denied + if !strings.EqualFold(cl.TokenType, constants.ServerWorkerTokenType) && !strings.EqualFold(cl.Subject, w.GetHostname()) { + retErr := fmt.Errorf("unable to refresh worker auth: claims subject %s does not match worker hostname %s", cl.Subject, w.GetHostname()) + + logrus.WithFields(logrus.Fields{ + "subject": cl.Subject, + "worker": w.GetHostname(), + }).Warnf("attempted refresh of worker %s using token from worker %s", w.GetHostname(), cl.Subject) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // set last checked in time + w.SetLastCheckedIn(time.Now().Unix()) + + // send API call to update the worker + err := database.FromContext(c).UpdateWorker(w) + if err != nil { + retErr := fmt.Errorf("unable to update worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "worker": w.GetHostname(), + }).Infof("refreshing worker %s authentication", w.GetHostname()) + + switch cl.TokenType { + // if symmetric token configured, send back symmetric token + case constants.ServerWorkerTokenType: + if secret, ok := c.Value("secret").(string); ok { + tkn := new(library.Token) + tkn.SetToken(secret) + c.JSON(http.StatusOK, tkn) + + return + } + + retErr := fmt.Errorf("symmetric token provided but not configured in server") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + // if worker auth / register token, send back auth token + case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: + tm := c.MustGet("token-manager").(*token.Manager) + + wmto := &token.MintTokenOpts{ + TokenType: constants.WorkerAuthTokenType, + TokenDuration: tm.WorkerAuthTokenDuration, + Hostname: cl.Subject, + } + + tkn := new(library.Token) + + wt, err := tm.MintToken(wmto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token for worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + tkn.SetToken(wt) + + c.JSON(http.StatusOK, tkn) + } +} diff --git a/api/worker/update.go b/api/worker/update.go new file mode 100644 index 000000000..0c2f9c4fb --- /dev/null +++ b/api/worker/update.go @@ -0,0 +1,115 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package worker + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/workers/{worker} workers UpdateWorker +// +// Update a worker for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Payload containing the worker to update +// required: true +// schema: +// "$ref": "#/definitions/Worker" +// - in: path +// name: worker +// description: Name of the worker +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the worker +// schema: +// "$ref": "#/definitions/Worker" +// '400': +// description: Unable to update the worker +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to update the worker +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the worker +// schema: +// "$ref": "#/definitions/Error" + +// UpdateWorker represents the API handler to +// update a worker in the configured backend. +func UpdateWorker(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + w := worker.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "user": u.GetName(), + "worker": w.GetHostname(), + }).Infof("updating worker %s", w.GetHostname()) + + // capture body from API request + input := new(library.Worker) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + if len(input.GetAddress()) > 0 { + // update address if set + w.SetAddress(input.GetAddress()) + } + + if len(input.GetRoutes()) > 0 { + // update routes if set + w.SetRoutes(input.GetRoutes()) + } + + if input.GetActive() { + // update active if set + w.SetActive(input.GetActive()) + } + + // send API call to update the worker + err = database.FromContext(c).UpdateWorker(w) + if err != nil { + retErr := fmt.Errorf("unable to update worker %s: %w", w.GetHostname(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated worker + w, _ = database.FromContext(c).GetWorkerForHostname(w.GetHostname()) + + c.JSON(http.StatusOK, w) +} diff --git a/router/worker.go b/router/worker.go index 100a24975..7bb114c69 100644 --- a/router/worker.go +++ b/router/worker.go @@ -6,10 +6,10 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/worker" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/perm" - "github.com/go-vela/server/router/middleware/worker" + wmiddleware "github.com/go-vela/server/router/middleware/worker" ) // WorkerHandlers is a function that extends the provided base router group @@ -23,18 +23,18 @@ import ( // DELETE /api/v1/workers/:worker . func WorkerHandlers(base *gin.RouterGroup) { // Workers endpoints - workers := base.Group("/workers") + _workers := base.Group("/workers") { - workers.POST("", perm.MustWorkerRegisterToken(), middleware.Payload(), api.CreateWorker) - workers.GET("", api.GetWorkers) + _workers.POST("", perm.MustWorkerRegisterToken(), middleware.Payload(), worker.CreateWorker) + _workers.GET("", worker.ListWorkers) // Worker endpoints - w := workers.Group("/:worker") + _worker := _workers.Group("/:worker") { - w.GET("", worker.Establish(), api.GetWorker) - w.PUT("", perm.MustPlatformAdmin(), worker.Establish(), api.UpdateWorker) - w.POST("/refresh", perm.MustWorkerAuthToken(), worker.Establish(), api.RefreshWorkerAuth) - w.DELETE("", perm.MustPlatformAdmin(), worker.Establish(), api.DeleteWorker) + _worker.GET("", wmiddleware.Establish(), worker.GetWorker) + _worker.PUT("", perm.MustPlatformAdmin(), wmiddleware.Establish(), worker.UpdateWorker) + _worker.POST("/refresh", perm.MustWorkerAuthToken(), wmiddleware.Establish(), worker.Refresh) + _worker.DELETE("", perm.MustPlatformAdmin(), wmiddleware.Establish(), worker.DeleteWorker) } // end of worker endpoints } // end of workers endpoints } From fa4ffd73abd84f7d3f13160aa9cc1f3cbf49bf68 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 17 May 2023 15:15:53 -0600 Subject: [PATCH 229/298] refactor(api): move deployment logic to separate package (#847) --- api/deployment.go | 338 --------------------------------------- api/deployment/create.go | 107 +++++++++++++ api/deployment/doc.go | 10 ++ api/deployment/get.go | 100 ++++++++++++ api/deployment/list.go | 170 ++++++++++++++++++++ api/pipeline/doc.go | 10 ++ api/repo/doc.go | 10 ++ api/user/doc.go | 10 ++ api/worker/doc.go | 10 ++ router/deployment.go | 8 +- 10 files changed, 431 insertions(+), 342 deletions(-) delete mode 100644 api/deployment.go create mode 100644 api/deployment/create.go create mode 100644 api/deployment/doc.go create mode 100644 api/deployment/get.go create mode 100644 api/deployment/list.go create mode 100644 api/pipeline/doc.go create mode 100644 api/repo/doc.go create mode 100644 api/user/doc.go create mode 100644 api/worker/doc.go diff --git a/api/deployment.go b/api/deployment.go deleted file mode 100644 index 82433b613..000000000 --- a/api/deployment.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "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/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/deployments/{org}/{repo} deployment CreateDeployment -// -// Create a deployment for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the deployment -// schema: -// "$ref": "#/definitions/Deployment" -// '400': -// description: Unable to create the deployment -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the deployment -// schema: -// "$ref": "#/definitions/Error" - -// CreateDeployment represents the API handler to -// create a deployment in the configured backend. -func CreateDeployment(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("creating new deployment for repo %s", r.GetFullName()) - - // capture body from API request - input := new(library.Deployment) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new deployment for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in deployment object - input.SetRepoID(r.GetID()) - input.SetUser(u.GetName()) - - if len(input.GetDescription()) == 0 { - input.SetDescription("Deployment request from Vela") - } - - if len(input.GetTask()) == 0 { - input.SetTask("deploy:vela") - } - - // send API call to create the deployment - err = scm.FromContext(c).CreateDeployment(u, r, input) - if err != nil { - retErr := fmt.Errorf("unable to create new deployment for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusCreated, input) -} - -// swagger:operation GET /api/v1/deployments/{org}/{repo} deployment GetDeployments -// -// Get a list of deployments for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the list of deployments -// schema: -// type: array -// items: -// "$ref": "#/definitions/Deployment" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of deployments -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of deployments -// schema: -// "$ref": "#/definitions/Error" - -// GetDeployments represents the API handler to capture -// a list of deployments from the configured backend. -func GetDeployments(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading deployments for repo %s", r.GetFullName()) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the total number of deployments for the repo - t, err := scm.FromContext(c).GetDeploymentCount(u, r) - if err != nil { - retErr := fmt.Errorf("unable to get deployment count for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the list of deployments for the repo - d, err := scm.FromContext(c).GetDeploymentList(u, r, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get deployments for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - dWithBs := []*library.Deployment{} - - for _, deployment := range d { - b, err := database.FromContext(c).GetDeploymentBuildList(*deployment.URL) - if err != nil { - retErr := fmt.Errorf("unable to get builds for deployment %d: %w", deployment.GetID(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - builds := []library.Build{} - for _, build := range b { - builds = append(builds, *build) - } - - deployment.SetBuilds(builds) - - dWithBs = append(dWithBs, deployment) - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, dWithBs) -} - -// swagger:operation GET /api/v1/deployments/{org}/{repo}/{deployment} deployment GetDeployment -// -// Get a deployment from the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: deployment -// description: Name of the org -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the deployment -// schema: -// "$ref": "#/definitions/Deployment" -// '400': -// description: Unable to retrieve the deployment -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the deployment -// schema: -// "$ref": "#/definitions/Error" - -// GetDeployment represents the API handler to -// capture a deployment from the configured backend. -func GetDeployment(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - deployment := util.PathParameter(c, "deployment") - - entry := fmt.Sprintf("%s/%s", r.GetFullName(), deployment) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading deployment %s", entry) - - number, err := strconv.Atoi(deployment) - if err != nil { - retErr := fmt.Errorf("invalid deployment parameter provided: %s", deployment) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the deployment - d, err := scm.FromContext(c).GetDeployment(u, r, int64(number)) - if err != nil { - retErr := fmt.Errorf("unable to get deployment %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, d) -} diff --git a/api/deployment/create.go b/api/deployment/create.go new file mode 100644 index 000000000..1ad549c07 --- /dev/null +++ b/api/deployment/create.go @@ -0,0 +1,107 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package deployment + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/deployments/{org}/{repo} deployments CreateDeployment +// +// Create a deployment for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the deployment +// schema: +// "$ref": "#/definitions/Deployment" +// '400': +// description: Unable to create the deployment +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the deployment +// schema: +// "$ref": "#/definitions/Error" + +// CreateDeployment represents the API handler to +// create a deployment in the configured backend. +func CreateDeployment(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("creating new deployment for repo %s", r.GetFullName()) + + // capture body from API request + input := new(library.Deployment) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new deployment for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in deployment object + input.SetRepoID(r.GetID()) + input.SetUser(u.GetName()) + + if len(input.GetDescription()) == 0 { + input.SetDescription("Deployment request from Vela") + } + + if len(input.GetTask()) == 0 { + input.SetTask("deploy:vela") + } + + // send API call to create the deployment + err = scm.FromContext(c).CreateDeployment(u, r, input) + if err != nil { + retErr := fmt.Errorf("unable to create new deployment for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusCreated, input) +} diff --git a/api/deployment/doc.go b/api/deployment/doc.go new file mode 100644 index 000000000..c6118b8f3 --- /dev/null +++ b/api/deployment/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package deployment provides the deployment handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/deployment" +package deployment diff --git a/api/deployment/get.go b/api/deployment/get.go new file mode 100644 index 000000000..ff6827d3a --- /dev/null +++ b/api/deployment/get.go @@ -0,0 +1,100 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package deployment + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/deployments/{org}/{repo}/{deployment} deployments GetDeployment +// +// Get a deployment from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: deployment +// description: Number of the deployment +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the deployment +// schema: +// "$ref": "#/definitions/Deployment" +// '400': +// description: Unable to retrieve the deployment +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the deployment +// schema: +// "$ref": "#/definitions/Error" + +// GetDeployment represents the API handler to +// capture a deployment from the configured backend. +func GetDeployment(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + deployment := util.PathParameter(c, "deployment") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), deployment) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading deployment %s", entry) + + number, err := strconv.Atoi(deployment) + if err != nil { + retErr := fmt.Errorf("invalid deployment parameter provided: %s", deployment) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the deployment + d, err := scm.FromContext(c).GetDeployment(u, r, int64(number)) + if err != nil { + retErr := fmt.Errorf("unable to get deployment %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, d) +} diff --git a/api/deployment/list.go b/api/deployment/list.go new file mode 100644 index 000000000..bc5f9e97a --- /dev/null +++ b/api/deployment/list.go @@ -0,0 +1,170 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package deployment + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/deployments/{org}/{repo} deployments ListDeployments +// +// Get a list of deployments for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the list of deployments +// schema: +// type: array +// items: +// "$ref": "#/definitions/Deployment" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of deployments +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of deployments +// schema: +// "$ref": "#/definitions/Error" + +// ListDeployments represents the API handler to capture +// a list of deployments from the configured backend. +func ListDeployments(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading deployments for repo %s", r.GetFullName()) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the total number of deployments for the repo + t, err := scm.FromContext(c).GetDeploymentCount(u, r) + if err != nil { + retErr := fmt.Errorf("unable to get deployment count for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the list of deployments for the repo + d, err := scm.FromContext(c).GetDeploymentList(u, r, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get deployments for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + dWithBs := []*library.Deployment{} + + for _, deployment := range d { + b, err := database.FromContext(c).GetDeploymentBuildList(*deployment.URL) + if err != nil { + retErr := fmt.Errorf("unable to get builds for deployment %d: %w", deployment.GetID(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + builds := []library.Build{} + for _, build := range b { + builds = append(builds, *build) + } + + deployment.SetBuilds(builds) + + dWithBs = append(dWithBs, deployment) + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, dWithBs) +} diff --git a/api/pipeline/doc.go b/api/pipeline/doc.go new file mode 100644 index 000000000..0b2c02901 --- /dev/null +++ b/api/pipeline/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package pipeline provides the pipeline handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/pipeline" +package pipeline diff --git a/api/repo/doc.go b/api/repo/doc.go new file mode 100644 index 000000000..82eb5304e --- /dev/null +++ b/api/repo/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package repo provides the repo handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/repo" +package repo diff --git a/api/user/doc.go b/api/user/doc.go new file mode 100644 index 000000000..7f1ce6bc5 --- /dev/null +++ b/api/user/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package user provides the user handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/user" +package user diff --git a/api/worker/doc.go b/api/worker/doc.go new file mode 100644 index 000000000..86da09ed7 --- /dev/null +++ b/api/worker/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package worker provides the worker handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/worker" +package worker diff --git a/router/deployment.go b/router/deployment.go index 9a5b15e27..eabbc48c6 100644 --- a/router/deployment.go +++ b/router/deployment.go @@ -8,7 +8,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/deployment" "github.com/go-vela/server/router/middleware/perm" "github.com/go-vela/server/router/middleware/repo" ) @@ -23,8 +23,8 @@ func DeploymentHandlers(base *gin.RouterGroup) { // Deployments endpoints deployments := base.Group("/deployments/:org/:repo", org.Establish(), repo.Establish()) { - deployments.POST("", perm.MustWrite(), api.CreateDeployment) - deployments.GET("", perm.MustRead(), api.GetDeployments) - deployments.GET("/:deployment", perm.MustRead(), api.GetDeployment) + deployments.POST("", perm.MustWrite(), deployment.CreateDeployment) + deployments.GET("", perm.MustRead(), deployment.ListDeployments) + deployments.GET("/:deployment", perm.MustRead(), deployment.GetDeployment) } // end of deployments endpoints } From cd6a651381fc8bea7dcc8318b69cddccd44a9a71 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 18 May 2023 09:00:57 -0600 Subject: [PATCH 230/298] refactor(api): move scm logic to separate package (#848) --- api/scm/doc.go | 10 +++ api/scm/sync.go | 137 ++++++++++++++++++++++++++++++++ api/{scm.go => scm/sync_org.go} | 127 +---------------------------- router/scm.go | 6 +- 4 files changed, 154 insertions(+), 126 deletions(-) create mode 100644 api/scm/doc.go create mode 100644 api/scm/sync.go rename api/{scm.go => scm/sync_org.go} (54%) diff --git a/api/scm/doc.go b/api/scm/doc.go new file mode 100644 index 000000000..5d66cafed --- /dev/null +++ b/api/scm/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package scm provides the scm handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/scm" +package scm diff --git a/api/scm/sync.go b/api/scm/sync.go new file mode 100644 index 000000000..b160f5fa0 --- /dev/null +++ b/api/scm/sync.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 scm + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/scm/repos/{org}/{repo}/sync scm SyncRepo +// +// Sync up scm service and database in the context of a specific repo +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully synchronized repo +// schema: +// type: string +// '500': +// description: Unable to synchronize repo +// schema: +// "$ref": "#/definitions/Error" + +// SyncRepo represents the API handler to +// synchronize a single repository between +// SCM service and the database should a discrepancy +// exist. Primarily used for deleted repos or to align +// subscribed events with allowed events. +func SyncRepo(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logger := logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }) + + logger.Infof("syncing repo %s", r.GetFullName()) + + // retrieve repo from source code manager service + _, err := scm.FromContext(c).GetRepo(u, r) + + // if there is an error retrieving repo, we know it is deleted: set to inactive + if err != nil { + // set repo to inactive - do not delete + r.SetActive(false) + + // update repo in database + err := database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // exit with success as hook sync will be unnecessary + c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) + + return + } + + // verify the user is an admin of the repo + // we cannot use our normal permissions check due to the possibility the repo was deleted + perm, err := scm.FromContext(c).RepoAccess(u, u.GetToken(), o, r.GetName()) + if err != nil { + logger.Errorf("unable to get user %s access level for org %s", u.GetName(), o) + } + + if !strings.EqualFold(perm, "admin") { + retErr := fmt.Errorf("user %s does not have 'admin' permissions for the repo %s", u.GetName(), r.GetFullName()) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + // if we have webhook validation, update the repo hook in the SCM + if c.Value("webhookvalidation").(bool) { + // grab last hook from repo to fetch the webhook ID + lastHook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update webhook + err = scm.FromContext(c).Update(u, r, lastHook.GetWebhookID()) + if err != nil { + retErr := fmt.Errorf("unable to update repo webhook for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) +} diff --git a/api/scm.go b/api/scm/sync_org.go similarity index 54% rename from api/scm.go rename to api/scm/sync_org.go index ee0898ff8..ac18ec551 100644 --- a/api/scm.go +++ b/api/scm/sync_org.go @@ -2,17 +2,15 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package api +package scm import ( "fmt" "net/http" - "strings" "github.com/gin-gonic/gin" "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/scm" "github.com/go-vela/server/util" @@ -20,7 +18,7 @@ import ( "github.com/sirupsen/logrus" ) -// swagger:operation GET /api/v1/scm/orgs/{org}/sync scm SyncRepos +// swagger:operation GET /api/v1/scm/orgs/{org}/sync scm SyncReposForOrg // // Sync up repos from scm service and database in a specified org // @@ -45,12 +43,12 @@ import ( // schema: // "$ref": "#/definitions/Error" -// SyncRepos represents the API handler to +// SyncReposForOrg represents the API handler to // synchronize organization repositories between // SCM Service and the database should a discrepancy // exist. Primarily used for deleted repos or to align // subscribed events with allowed events. -func SyncRepos(c *gin.Context) { +func SyncReposForOrg(c *gin.Context) { // capture middleware values o := org.Retrieve(c) u := user.Retrieve(c) @@ -151,120 +149,3 @@ func SyncRepos(c *gin.Context) { c.JSON(http.StatusOK, fmt.Sprintf("org %s repos synced", o)) } - -// swagger:operation GET /api/v1/scm/repos/{org}/{repo}/sync scm SyncRepo -// -// Sync up scm service and database in the context of a specific repo -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully synchronized repo -// schema: -// type: string -// '500': -// description: Unable to synchronize repo -// schema: -// "$ref": "#/definitions/Error" - -// SyncRepo represents the API handler to -// synchronize a single repository between -// SCM service and the database should a discrepancy -// exist. Primarily used for deleted repos or to align -// subscribed events with allowed events. -func SyncRepo(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logger := logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }) - - logger.Infof("syncing repo %s", r.GetFullName()) - - // retrieve repo from source code manager service - _, err := scm.FromContext(c).GetRepo(u, r) - - // if there is an error retrieving repo, we know it is deleted: set to inactive - if err != nil { - // set repo to inactive - do not delete - r.SetActive(false) - - // update repo in database - err := database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // exit with success as hook sync will be unnecessary - c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) - - return - } - - // verify the user is an admin of the repo - // we cannot use our normal permissions check due to the possibility the repo was deleted - perm, err := scm.FromContext(c).RepoAccess(u, u.GetToken(), o, r.GetName()) - if err != nil { - logger.Errorf("unable to get user %s access level for org %s", u.GetName(), o) - } - - if !strings.EqualFold(perm, "admin") { - retErr := fmt.Errorf("user %s does not have 'admin' permissions for the repo %s", u.GetName(), r.GetFullName()) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - // if we have webhook validation, update the repo hook in the SCM - if c.Value("webhookvalidation").(bool) { - // grab last hook from repo to fetch the webhook ID - lastHook, err := database.FromContext(c).LastHookForRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to retrieve last hook for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // update webhook - err = scm.FromContext(c).Update(u, r, lastHook.GetWebhookID()) - if err != nil { - retErr := fmt.Errorf("unable to update repo webhook for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - c.JSON(http.StatusOK, fmt.Sprintf("repo %s synced", r.GetFullName())) -} diff --git a/router/scm.go b/router/scm.go index 85b2a0d9f..40d745087 100644 --- a/router/scm.go +++ b/router/scm.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/scm" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" ) @@ -23,7 +23,7 @@ func ScmHandlers(base *gin.RouterGroup) { // SCM org endpoints org := orgs.Group("/:org", org.Establish()) { - org.GET("/sync", api.SyncRepos) + org.GET("/sync", scm.SyncReposForOrg) } // end of SCM org endpoints } // end of SCM orgs endpoints @@ -33,7 +33,7 @@ func ScmHandlers(base *gin.RouterGroup) { // SCM repo endpoints repo := repos.Group("/:org/:repo", org.Establish(), repo.Establish()) { - repo.GET("/sync", api.SyncRepo) + repo.GET("/sync", scm.SyncRepo) } // end of SCM repo endpoints } // end of SCM repos endpoints } From 61419f437d2809f2e6cffe8f999262d16b16de62 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Thu, 18 May 2023 12:43:26 -0500 Subject: [PATCH 231/298] refactor(api): move hook handlers to new package (#829) Co-authored-by: Jacob Floyd --- api/hook.go | 674 ------------------------------------------ api/hook/create.go | 129 ++++++++ api/hook/delete.go | 115 +++++++ api/hook/get.go | 101 +++++++ api/hook/list.go | 136 +++++++++ api/hook/redeliver.go | 115 +++++++ api/hook/update.go | 173 +++++++++++ router/hook.go | 16 +- 8 files changed, 777 insertions(+), 682 deletions(-) delete mode 100644 api/hook.go create mode 100644 api/hook/create.go create mode 100644 api/hook/delete.go create mode 100644 api/hook/get.go create mode 100644 api/hook/list.go create mode 100644 api/hook/redeliver.go create mode 100644 api/hook/update.go diff --git a/api/hook.go b/api/hook.go deleted file mode 100644 index 1787f9975..000000000 --- a/api/hook.go +++ /dev/null @@ -1,674 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - "time" - - "github.com/gin-gonic/gin" - "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/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/hooks/{org}/{repo} webhook CreateHook -// -// Create a webhook for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: body -// name: body -// description: Webhook payload that we expect from the user or VCS -// required: true -// schema: -// "$ref": "#/definitions/Webhook" -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: The webhook has been created -// schema: -// "$ref": "#/definitions/Webhook" -// '400': -// description: The webhook was unable to be created -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: The webhook was unable to be created -// schema: -// "$ref": "#/definitions/Error" - -// CreateHook represents the API handler to create -// a webhook in the configured backend. -func CreateHook(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("creating new hook for repo %s", r.GetFullName()) - - // capture body from API request - input := new(library.Hook) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new hook for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the last hook for the repo - lastHook, err := database.FromContext(c).LastHookForRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // update fields in webhook object - input.SetRepoID(r.GetID()) - input.SetNumber(1) - - if input.GetCreated() == 0 { - input.SetCreated(time.Now().UTC().Unix()) - } - - if lastHook != nil { - input.SetNumber( - lastHook.GetNumber() + 1, - ) - } - - // send API call to create the webhook - err = database.FromContext(c).CreateHook(input) - if err != nil { - retErr := fmt.Errorf("unable to create hook for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created webhook - h, _ := database.FromContext(c).GetHookForRepo(r, input.GetNumber()) - - c.JSON(http.StatusCreated, h) -} - -// swagger:operation GET /api/v1/hooks/{org}/{repo} webhook GetHooks -// -// Retrieve the webhooks for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved webhooks -// schema: -// type: array -// items: -// "$ref": "#/definitions/Webhook" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve webhooks -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve webhooks -// schema: -// "$ref": "#/definitions/Error" - -// GetHooks represents the API handler to capture a list -// of webhooks from the configured backend. -func GetHooks(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading hooks for repo %s", r.GetFullName()) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of steps for the build - h, t, err := database.FromContext(c).ListHooksForRepo(r, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get hooks for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, h) -} - -// swagger:operation GET /api/v1/hooks/{org}/{repo}/{hook} webhook GetHook -// -// Retrieve a webhook for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: hook -// description: Number of the hook -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the webhook -// schema: -// "$ref": "#/definitions/Webhook" -// '400': -// description: Unable to retrieve the webhook -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the webhook -// schema: -// "$ref": "#/definitions/Error" - -// GetHook represents the API handler to capture a -// webhook from the configured backend. -func GetHook(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - hook := util.PathParameter(c, "hook") - - entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "hook": hook, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading hook %s", entry) - - number, err := strconv.Atoi(hook) - if err != nil { - retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the webhook - h, err := database.FromContext(c).GetHookForRepo(r, number) - if err != nil { - retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, h) -} - -// swagger:operation PUT /api/v1/hooks/{org}/{repo}/{hook} webhook UpdateHook -// -// Update a webhook for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: hook -// description: Number of the hook -// required: true -// type: integer -// - in: body -// name: body -// description: Webhook payload that we expect from the user or VCS -// required: true -// schema: -// "$ref": "#/definitions/Webhook" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the webhook -// schema: -// "$ref": "#/definitions/Webhook" -// '400': -// description: The webhook was unable to be updated -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: The webhook was unable to be updated -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: The webhook was unable to be updated -// schema: -// "$ref": "#/definitions/Error" - -// UpdateHook represents the API handler to update -// a webhook in the configured backend. -func UpdateHook(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - hook := util.PathParameter(c, "hook") - - entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "hook": hook, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("updating hook %s", entry) - - // capture body from API request - input := new(library.Hook) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for hook %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - number, err := strconv.Atoi(hook) - if err != nil { - retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the webhook - h, err := database.FromContext(c).GetHookForRepo(r, number) - if err != nil { - retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // update webhook fields if provided - if input.GetCreated() > 0 { - // update created if set - h.SetCreated(input.GetCreated()) - } - - if len(input.GetHost()) > 0 { - // update host if set - h.SetHost(input.GetHost()) - } - - if len(input.GetEvent()) > 0 { - // update event if set - h.SetEvent(input.GetEvent()) - } - - if len(input.GetBranch()) > 0 { - // update branch if set - h.SetBranch(input.GetBranch()) - } - - if len(input.GetError()) > 0 { - // update error if set - h.SetError(input.GetError()) - } - - if len(input.GetStatus()) > 0 { - // update status if set - h.SetStatus(input.GetStatus()) - } - - if len(input.GetLink()) > 0 { - // update link if set - h.SetLink(input.GetLink()) - } - - // send API call to update the webhook - err = database.FromContext(c).UpdateHook(h) - if err != nil { - retErr := fmt.Errorf("unable to update hook %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated user - h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) - - c.JSON(http.StatusOK, h) -} - -// swagger:operation DELETE /api/v1/hooks/{org}/{repo}/{hook} webhook DeleteHook -// -// Delete a webhook for the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: hook -// description: Number of the hook -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the webhook -// schema: -// type: string -// '400': -// description: The webhook was unable to be deleted -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: The webhook was unable to be deleted -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: The webhook was unable to be deleted -// schema: -// "$ref": "#/definitions/Error" - -// DeleteHook represents the API handler to remove -// a webhook from the configured backend. -func DeleteHook(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - hook := util.PathParameter(c, "hook") - - entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "hook": hook, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("deleting hook %s", entry) - - number, err := strconv.Atoi(hook) - if err != nil { - retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the webhook - h, err := database.FromContext(c).GetHookForRepo(r, number) - if err != nil { - retErr := fmt.Errorf("unable to get hook %s: %w", hook, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // send API call to remove the webhook - err = database.FromContext(c).DeleteHook(h) - if err != nil { - retErr := fmt.Errorf("unable to delete hook %s: %w", hook, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("hook %s deleted", entry)) -} - -// swagger:operation POST /api/v1/hooks/{org}/{repo}/{hook}/redeliver webhook RedeliverHook -// -// Redeliver a webhook from the SCM -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: hook -// description: Number of the hook -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully redelivered the webhook -// schema: -// "$ref": "#/definitions/Webhook" -// '400': -// description: The webhook was unable to be redelivered -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: The webhook was unable to be redelivered -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: The webhook was unable to be redelivered -// schema: -// "$ref": "#/definitions/Error" - -// RedeliverHook represents the API handler to redeliver -// a webhook from the SCM. - -func RedeliverHook(c *gin.Context) { - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - hook := util.PathParameter(c, "hook") - - entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "hook": hook, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("redelivering hook %s", entry) - - number, err := strconv.Atoi(hook) - if err != nil { - retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the webhook - h, err := database.FromContext(c).GetHookForRepo(r, number) - if err != nil { - retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - err = scm.FromContext(c).RedeliverWebhook(c, u, r, h) - if err != nil { - retErr := fmt.Errorf("unable to redeliver hook %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("hook %s redelivered", entry)) -} diff --git a/api/hook/create.go b/api/hook/create.go new file mode 100644 index 000000000..70f524524 --- /dev/null +++ b/api/hook/create.go @@ -0,0 +1,129 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/hooks/{org}/{repo} webhook CreateHook +// +// Create a webhook for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: body +// name: body +// description: Webhook payload that we expect from the user or VCS +// required: true +// schema: +// "$ref": "#/definitions/Webhook" +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: The webhook has been created +// schema: +// "$ref": "#/definitions/Webhook" +// '400': +// description: The webhook was unable to be created +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: The webhook was unable to be created +// schema: +// "$ref": "#/definitions/Error" + +// CreateHook represents the API handler to create +// a webhook in the configured backend. +func CreateHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("creating new hook for repo %s", r.GetFullName()) + + // capture body from API request + input := new(library.Hook) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the last hook for the repo + lastHook, err := database.FromContext(c).LastHookForRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to get last hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // update fields in webhook object + input.SetRepoID(r.GetID()) + input.SetNumber(1) + + if input.GetCreated() == 0 { + input.SetCreated(time.Now().UTC().Unix()) + } + + if lastHook != nil { + input.SetNumber( + lastHook.GetNumber() + 1, + ) + } + + // send API call to create the webhook + err = database.FromContext(c).CreateHook(input) + if err != nil { + retErr := fmt.Errorf("unable to create hook for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created webhook + h, _ := database.FromContext(c).GetHookForRepo(r, input.GetNumber()) + + c.JSON(http.StatusCreated, h) +} diff --git a/api/hook/delete.go b/api/hook/delete.go new file mode 100644 index 000000000..7ada1f0fb --- /dev/null +++ b/api/hook/delete.go @@ -0,0 +1,115 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/hooks/{org}/{repo}/{hook} webhook DeleteHook +// +// Delete a webhook for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: hook +// description: Number of the hook +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the webhook +// schema: +// type: string +// '400': +// description: The webhook was unable to be deleted +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: The webhook was unable to be deleted +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: The webhook was unable to be deleted +// schema: +// "$ref": "#/definitions/Error" + +// DeleteHook represents the API handler to remove +// a webhook from the configured backend. +func DeleteHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + hook := util.PathParameter(c, "hook") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "hook": hook, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("deleting hook %s", entry) + + number, err := strconv.Atoi(hook) + if err != nil { + retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the webhook + h, err := database.FromContext(c).GetHookForRepo(r, number) + if err != nil { + retErr := fmt.Errorf("unable to get hook %s: %w", hook, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // send API call to remove the webhook + err = database.FromContext(c).DeleteHook(h) + if err != nil { + retErr := fmt.Errorf("unable to delete hook %s: %w", hook, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("hook %s deleted", entry)) +} diff --git a/api/hook/get.go b/api/hook/get.go new file mode 100644 index 000000000..458183dcb --- /dev/null +++ b/api/hook/get.go @@ -0,0 +1,101 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/hooks/{org}/{repo}/{hook} webhook GetHook +// +// Retrieve a webhook for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: hook +// description: Number of the hook +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the webhook +// schema: +// "$ref": "#/definitions/Webhook" +// '400': +// description: Unable to retrieve the webhook +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the webhook +// schema: +// "$ref": "#/definitions/Error" + +// GetHook represents the API handler to capture a +// webhook from the configured backend. +func GetHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + hook := util.PathParameter(c, "hook") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "hook": hook, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading hook %s", entry) + + number, err := strconv.Atoi(hook) + if err != nil { + retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the webhook + h, err := database.FromContext(c).GetHookForRepo(r, number) + if err != nil { + retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, h) +} diff --git a/api/hook/list.go b/api/hook/list.go new file mode 100644 index 000000000..2cb6d05fe --- /dev/null +++ b/api/hook/list.go @@ -0,0 +1,136 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/hooks/{org}/{repo} webhook ListHooks +// +// Retrieve the webhooks for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved webhooks +// schema: +// type: array +// items: +// "$ref": "#/definitions/Webhook" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve webhooks +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve webhooks +// schema: +// "$ref": "#/definitions/Error" + +// ListHooks represents the API handler to capture a list +// of webhooks from the configured backend. +func ListHooks(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading hooks for repo %s", r.GetFullName()) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of steps for the build + h, t, err := database.FromContext(c).ListHooksForRepo(r, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get hooks for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, h) +} diff --git a/api/hook/redeliver.go b/api/hook/redeliver.go new file mode 100644 index 000000000..4afcb8a79 --- /dev/null +++ b/api/hook/redeliver.go @@ -0,0 +1,115 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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/scm" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/hooks/{org}/{repo}/{hook}/redeliver webhook RedeliverHook +// +// Redeliver a webhook from the SCM +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: hook +// description: Number of the hook +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully redelivered the webhook +// schema: +// "$ref": "#/definitions/Webhook" +// '400': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: The webhook was unable to be redelivered +// schema: +// "$ref": "#/definitions/Error" + +// RedeliverHook represents the API handler to redeliver +// a webhook from the SCM. +func RedeliverHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + hook := util.PathParameter(c, "hook") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "hook": hook, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("redelivering hook %s", entry) + + number, err := strconv.Atoi(hook) + if err != nil { + retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the webhook + h, err := database.FromContext(c).GetHookForRepo(r, number) + if err != nil { + retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + err = scm.FromContext(c).RedeliverWebhook(c, u, r, h) + if err != nil { + retErr := fmt.Errorf("unable to redeliver hook %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("hook %s redelivered", entry)) +} diff --git a/api/hook/update.go b/api/hook/update.go new file mode 100644 index 000000000..f8beeb1ec --- /dev/null +++ b/api/hook/update.go @@ -0,0 +1,173 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package hook + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/hooks/{org}/{repo}/{hook} webhook UpdateHook +// +// Update a webhook for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: hook +// description: Number of the hook +// required: true +// type: integer +// - in: body +// name: body +// description: Webhook payload that we expect from the user or VCS +// required: true +// schema: +// "$ref": "#/definitions/Webhook" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the webhook +// schema: +// "$ref": "#/definitions/Webhook" +// '400': +// description: The webhook was unable to be updated +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: The webhook was unable to be updated +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: The webhook was unable to be updated +// schema: +// "$ref": "#/definitions/Error" + +// UpdateHook represents the API handler to update +// a webhook in the configured backend. +func UpdateHook(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + hook := util.PathParameter(c, "hook") + + entry := fmt.Sprintf("%s/%s", r.GetFullName(), hook) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "hook": hook, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("updating hook %s", entry) + + // capture body from API request + input := new(library.Hook) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for hook %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + number, err := strconv.Atoi(hook) + if err != nil { + retErr := fmt.Errorf("invalid hook parameter provided: %s", hook) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the webhook + h, err := database.FromContext(c).GetHookForRepo(r, number) + if err != nil { + retErr := fmt.Errorf("unable to get hook %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // update webhook fields if provided + if input.GetCreated() > 0 { + // update created if set + h.SetCreated(input.GetCreated()) + } + + if len(input.GetHost()) > 0 { + // update host if set + h.SetHost(input.GetHost()) + } + + if len(input.GetEvent()) > 0 { + // update event if set + h.SetEvent(input.GetEvent()) + } + + if len(input.GetBranch()) > 0 { + // update branch if set + h.SetBranch(input.GetBranch()) + } + + if len(input.GetError()) > 0 { + // update error if set + h.SetError(input.GetError()) + } + + if len(input.GetStatus()) > 0 { + // update status if set + h.SetStatus(input.GetStatus()) + } + + if len(input.GetLink()) > 0 { + // update link if set + h.SetLink(input.GetLink()) + } + + // send API call to update the webhook + err = database.FromContext(c).UpdateHook(h) + if err != nil { + retErr := fmt.Errorf("unable to update hook %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated user + h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) + + c.JSON(http.StatusOK, h) +} diff --git a/router/hook.go b/router/hook.go index 8237cc87a..f5e1aa1db 100644 --- a/router/hook.go +++ b/router/hook.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/hook" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/perm" "github.com/go-vela/server/router/middleware/repo" @@ -23,13 +23,13 @@ import ( // POST /api/v1/hooks/:org/:repo/:hook/redeliver . func HookHandlers(base *gin.RouterGroup) { // Hooks endpoints - hooks := base.Group("/hooks/:org/:repo", org.Establish(), repo.Establish()) + _hooks := base.Group("/hooks/:org/:repo", org.Establish(), repo.Establish()) { - hooks.POST("", perm.MustPlatformAdmin(), api.CreateHook) - hooks.GET("", perm.MustRead(), api.GetHooks) - hooks.GET("/:hook", perm.MustRead(), api.GetHook) - hooks.PUT("/:hook", perm.MustPlatformAdmin(), api.UpdateHook) - hooks.DELETE("/:hook", perm.MustPlatformAdmin(), api.DeleteHook) - hooks.POST("/:hook/redeliver", perm.MustWrite(), api.RedeliverHook) + _hooks.POST("", perm.MustPlatformAdmin(), hook.CreateHook) + _hooks.GET("", perm.MustRead(), hook.ListHooks) + _hooks.GET("/:hook", perm.MustRead(), hook.GetHook) + _hooks.PUT("/:hook", perm.MustPlatformAdmin(), hook.UpdateHook) + _hooks.DELETE("/:hook", perm.MustPlatformAdmin(), hook.DeleteHook) + _hooks.POST("/:hook/redeliver", perm.MustWrite(), hook.RedeliverHook) } // end of hooks endpoints } From d0f63b14f175096e69af41bbb678457b280d7a33 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Thu, 18 May 2023 12:47:17 -0500 Subject: [PATCH 232/298] feat(database): add support for schedules (#834) * feat(api/types): add support for schedules * feat(database/types): add support for schedules * feat(database): add support for schedules * chore: update go dependencies * feat(database): add schedule engine * fix: parse entry for schedules * enhance: switch to adhocore/gronx * chore: update go deps * chore: address linter feedback * chore: remove new types * chore: updates for removed types * chore: update go dependencies * chore: address review feedback --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- database/interface.go | 5 + database/postgres/postgres.go | 18 +++ database/postgres/postgres_test.go | 8 + database/schedule/count.go | 25 +++ database/schedule/count_active.go | 26 +++ database/schedule/count_active_test.go | 102 ++++++++++++ database/schedule/count_repo.go | 31 ++++ database/schedule/count_repo_test.go | 106 +++++++++++++ database/schedule/count_test.go | 100 ++++++++++++ database/schedule/create.go | 35 ++++ database/schedule/create_test.go | 76 +++++++++ database/schedule/delete.go | 28 ++++ database/schedule/delete_test.go | 76 +++++++++ database/schedule/get.go | 31 ++++ database/schedule/get_repo.go | 37 +++++ database/schedule/get_repo_test.go | 94 +++++++++++ database/schedule/get_test.go | 88 ++++++++++ database/schedule/index.go | 24 +++ database/schedule/index_test.go | 59 +++++++ database/schedule/interface.go | 49 ++++++ database/schedule/list.go | 52 ++++++ database/schedule/list_active.go | 53 +++++++ database/schedule/list_active_test.go | 111 +++++++++++++ database/schedule/list_repo.go | 63 ++++++++ database/schedule/list_repo_test.go | 115 ++++++++++++++ database/schedule/list_test.go | 110 +++++++++++++ database/schedule/opts.go | 44 +++++ database/schedule/opts_test.go | 161 +++++++++++++++++++ database/schedule/schedule.go | 80 ++++++++++ database/schedule/schedule_test.go | 212 +++++++++++++++++++++++++ database/schedule/table.go | 66 ++++++++ database/schedule/table_test.go | 59 +++++++ database/schedule/update.go | 35 ++++ database/schedule/update_test.go | 85 ++++++++++ database/sqlite/sqlite.go | 15 ++ go.mod | 4 +- go.sum | 9 +- 37 files changed, 2288 insertions(+), 4 deletions(-) create mode 100644 database/schedule/count.go create mode 100644 database/schedule/count_active.go create mode 100644 database/schedule/count_active_test.go create mode 100644 database/schedule/count_repo.go create mode 100644 database/schedule/count_repo_test.go create mode 100644 database/schedule/count_test.go create mode 100644 database/schedule/create.go create mode 100644 database/schedule/create_test.go create mode 100644 database/schedule/delete.go create mode 100644 database/schedule/delete_test.go create mode 100644 database/schedule/get.go create mode 100644 database/schedule/get_repo.go create mode 100644 database/schedule/get_repo_test.go create mode 100644 database/schedule/get_test.go create mode 100644 database/schedule/index.go create mode 100644 database/schedule/index_test.go create mode 100644 database/schedule/interface.go create mode 100644 database/schedule/list.go create mode 100644 database/schedule/list_active.go create mode 100644 database/schedule/list_active_test.go create mode 100644 database/schedule/list_repo.go create mode 100644 database/schedule/list_repo_test.go create mode 100644 database/schedule/list_test.go create mode 100644 database/schedule/opts.go create mode 100644 database/schedule/opts_test.go create mode 100644 database/schedule/schedule.go create mode 100644 database/schedule/schedule_test.go create mode 100644 database/schedule/table.go create mode 100644 database/schedule/table_test.go create mode 100644 database/schedule/update.go create mode 100644 database/schedule/update_test.go diff --git a/database/interface.go b/database/interface.go index b7d1b6fee..9a2177b14 100644 --- a/database/interface.go +++ b/database/interface.go @@ -9,6 +9,7 @@ import ( "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/service" "github.com/go-vela/server/database/step" @@ -93,6 +94,10 @@ type Interface interface { // related to repos stored in the database. repo.RepoInterface + // ScheduleInterface provides the interface for functionality + // related to schedules stored in the database. + schedule.ScheduleInterface + // SecretInterface provides the interface for functionality // related to secrets stored in the database. secret.SecretInterface diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 2adbfdd31..0c316531b 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -14,6 +14,7 @@ import ( "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/service" "github.com/go-vela/server/database/step" @@ -58,6 +59,8 @@ type ( pipeline.PipelineInterface // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface repo.RepoInterface + // https://pkg.go.dev/github.com/go-vela/server/database/schedule#ScheduleInterface + schedule.ScheduleInterface // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface secret.SecretInterface // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface @@ -176,6 +179,9 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the schedule queries + _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the secret queries _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -367,6 +373,18 @@ func createServices(c *client) error { return err } + // create the database agnostic engine for schedules + // + // https://pkg.go.dev/github.com/go-vela/server/database/schedule#New + c.ScheduleInterface, err = schedule.New( + schedule.WithClient(c.Postgres), + schedule.WithLogger(c.Logger), + schedule.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic engine for secrets // // https://pkg.go.dev/github.com/go-vela/server/database/secret#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 6074c65ca..d61f443fd 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/go-vela/server/database/schedule" + "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" @@ -102,6 +104,9 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the schedule queries + _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the secret queries _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -269,6 +274,9 @@ func TestPostgres_createServices(t *testing.T) { // ensure the mock expects the repo queries _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the schedule queries + _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the secret queries _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/database/schedule/count.go b/database/schedule/count.go new file mode 100644 index 000000000..c7ce5f3aa --- /dev/null +++ b/database/schedule/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" +) + +// CountSchedules gets the count of all schedules from the database. +func (e *engine) CountSchedules() (int64, error) { + e.logger.Tracef("getting count of all schedules from the database") + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSchedule). + Count(&s). + Error + + return s, err +} diff --git a/database/schedule/count_active.go b/database/schedule/count_active.go new file mode 100644 index 000000000..f3240f2f8 --- /dev/null +++ b/database/schedule/count_active.go @@ -0,0 +1,26 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" +) + +// CountActiveSchedules gets the count of all active schedules from the database. +func (e *engine) CountActiveSchedules() (int64, error) { + e.logger.Tracef("getting count of all active schedules from the database") + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSchedule). + Where("active = ?", true). + Count(&s). + Error + + return s, err +} diff --git a/database/schedule/count_active_test.go b/database/schedule/count_active_test.go new file mode 100644 index 000000000..aa417efaa --- /dev/null +++ b/database/schedule/count_active_test.go @@ -0,0 +1,102 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetActive(true) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetActive(false) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules" WHERE active = $1`).WithArgs(true).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountActiveSchedules() + + if test.failure { + if err == nil { + t.Errorf("CountActiveSchedules for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountActiveSchedules for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountActiveSchedules for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/count_repo.go b/database/schedule/count_repo.go new file mode 100644 index 000000000..1ec5177cb --- /dev/null +++ b/database/schedule/count_repo.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountSchedulesForRepo gets the count of schedules by repo ID from the database. +func (e *engine) CountSchedulesForRepo(r *library.Repo) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting count of schedules for repo %s from the database", r.GetFullName()) + + // variable to store query results + var s int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSchedule). + Where("repo_id = ?", r.GetID()). + Count(&s). + Error + + return s, err +} diff --git a/database/schedule/count_repo_test.go b/database/schedule/count_repo_test.go new file mode 100644 index 000000000..792c21b1d --- /dev/null +++ b/database/schedule/count_repo_test.go @@ -0,0 +1,106 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { + _repo := testRepo() + _repo.SetID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 1, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSchedulesForRepo(_repo) + + if test.failure { + if err == nil { + t.Errorf("CountSchedulesForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSchedulesForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSchedulesForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/count_test.go b/database/schedule/count_test.go new file mode 100644 index 000000000..01cfbbae4 --- /dev/null +++ b/database/schedule/count_test.go @@ -0,0 +1,100 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CountSchedules(t *testing.T) { + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountSchedules() + + if test.failure { + if err == nil { + t.Errorf("CountSchedules for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountSchedules for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountSchedules for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/create.go b/database/schedule/create.go new file mode 100644 index 000000000..a6e532e8c --- /dev/null +++ b/database/schedule/create.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with update.go +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateSchedule creates a new schedule in the database. +func (e *engine) CreateSchedule(s *library.Schedule) error { + e.logger.WithFields(logrus.Fields{ + "schedule": s.GetName(), + }).Tracef("creating schedule %s in the database", s.GetName()) + + // cast the library type to database type + schedule := database.ScheduleFromLibrary(s) + + // validate the necessary fields are populated + err := schedule.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableSchedule). + Create(schedule). + Error +} diff --git a/database/schedule/create_test.go b/database/schedule/create_test.go new file mode 100644 index 000000000..015654151 --- /dev/null +++ b/database/schedule/create_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CreateSchedule(t *testing.T) { + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "schedules" +("repo_id","active","name","entry","created_at","created_by","updated_at","updated_by","scheduled_at","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id"`). + WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateSchedule(_schedule) + + if test.failure { + if err == nil { + t.Errorf("CreateSchedule for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateSchedule for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/schedule/delete.go b/database/schedule/delete.go new file mode 100644 index 000000000..42ee4988d --- /dev/null +++ b/database/schedule/delete.go @@ -0,0 +1,28 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteSchedule deletes an existing schedule from the database. +func (e *engine) DeleteSchedule(s *library.Schedule) error { + e.logger.WithFields(logrus.Fields{ + "schedule": s.GetName(), + }).Tracef("deleting schedule %s in the database", s.GetName()) + + // cast the library type to database type + schedule := database.ScheduleFromLibrary(s) + + // send query to the database + return e.client. + Table(constants.TableSchedule). + Delete(schedule). + Error +} diff --git a/database/schedule/delete_test.go b/database/schedule/delete_test.go new file mode 100644 index 000000000..3d1a3cd48 --- /dev/null +++ b/database/schedule/delete_test.go @@ -0,0 +1,76 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_DeleteSchedule(t *testing.T) { + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "schedules" WHERE "schedules"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_schedule) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteSchedule(_schedule) + + if test.failure { + if err == nil { + t.Errorf("DeleteSchedule for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteSchedule for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/schedule/get.go b/database/schedule/get.go new file mode 100644 index 000000000..73fcc162e --- /dev/null +++ b/database/schedule/get.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// GetSchedule gets a schedule by ID from the database. +func (e *engine) GetSchedule(id int64) (*library.Schedule, error) { + e.logger.Tracef("getting schedule %d from the database", id) + + // variable to store query results + s := new(database.Schedule) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSchedule). + Where("id = ?", id). + Take(s). + Error + if err != nil { + return nil, err + } + + return s.ToLibrary(), nil +} diff --git a/database/schedule/get_repo.go b/database/schedule/get_repo.go new file mode 100644 index 000000000..ff5ab40e5 --- /dev/null +++ b/database/schedule/get_repo.go @@ -0,0 +1,37 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetScheduleForRepo gets a schedule by repo ID and name from the database. +func (e *engine) GetScheduleForRepo(r *library.Repo, name string) (*library.Schedule, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "schedule": name, + }).Tracef("getting schedule %s/%s from the database", r.GetFullName(), name) + + // variable to store query results + s := new(database.Schedule) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableSchedule). + Where("repo_id = ?", r.GetID()). + Where("name = ?", name). + Take(s). + Error + if err != nil { + return nil, err + } + + return s.ToLibrary(), nil +} diff --git a/database/schedule/get_repo_test.go b/database/schedule/get_repo_test.go new file mode 100644 index 000000000..fb29bea37 --- /dev/null +++ b/database/schedule/get_repo_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSchedule_Engine_GetScheduleForRepo(t *testing.T) { + _repo := testRepo() + _repo.SetID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}, + ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE repo_id = $1 AND name = $2 LIMIT 1`).WithArgs(1, "nightly").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_schedule) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Schedule + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _schedule, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _schedule, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetScheduleForRepo(_repo, "nightly") + + if test.failure { + if err == nil { + t.Errorf("GetScheduleForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetScheduleForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetScheduleForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/get_test.go b/database/schedule/get_test.go new file mode 100644 index 000000000..acea35b2a --- /dev/null +++ b/database/schedule/get_test.go @@ -0,0 +1,88 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSchedule_Engine_GetSchedule(t *testing.T) { + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}, + ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_schedule) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Schedule + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _schedule, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _schedule, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetSchedule(1) + + if test.failure { + if err == nil { + t.Errorf("GetSchedule for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetSchedule for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetSchedule for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/index.go b/database/schedule/index.go new file mode 100644 index 000000000..f14082cee --- /dev/null +++ b/database/schedule/index.go @@ -0,0 +1,24 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +const ( + // CreateRepoIDIndex represents a query to create an + // index on the schedules table for the repo_id column. + CreateRepoIDIndex = ` +CREATE INDEX +IF NOT EXISTS +schedules_repo_id +ON schedules (repo_id); +` +) + +// CreateScheduleIndexes creates the indexes for the schedules table in the database. +func (e *engine) CreateScheduleIndexes() error { + e.logger.Tracef("creating indexes for schedules table in the database") + + // create the repo_id column index for the schedules table + return e.client.Exec(CreateRepoIDIndex).Error +} diff --git a/database/schedule/index_test.go b/database/schedule/index_test.go new file mode 100644 index 000000000..b8d334366 --- /dev/null +++ b/database/schedule/index_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CreateScheduleIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateScheduleIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateScheduleIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateScheduleIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/schedule/interface.go b/database/schedule/interface.go new file mode 100644 index 000000000..8aa14efb5 --- /dev/null +++ b/database/schedule/interface.go @@ -0,0 +1,49 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/library" +) + +// ScheduleInterface represents the Vela interface for schedule +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type ScheduleInterface interface { + // Schedule Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateScheduleIndexes defines a function that creates the indexes for the schedules table. + CreateScheduleIndexes() error + // CreateScheduleTable defines a function that creates the schedules table. + CreateScheduleTable(string) error + + // Schedule Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountSchedules defines a function that gets the count of all schedules. + CountSchedules() (int64, error) + // CountSchedulesForRepo defines a function that gets the count of schedules by repo ID. + CountSchedulesForRepo(*library.Repo) (int64, error) + // CreateSchedule defines a function that creates a new schedule. + CreateSchedule(*library.Schedule) error + // DeleteSchedule defines a function that deletes an existing schedule. + DeleteSchedule(*library.Schedule) error + // GetSchedule defines a function that gets a schedule by ID. + GetSchedule(int64) (*library.Schedule, error) + // GetScheduleForRepo defines a function that gets a schedule by repo ID and name. + GetScheduleForRepo(*library.Repo, string) (*library.Schedule, error) + // ListActiveSchedules defines a function that gets a list of all active schedules. + ListActiveSchedules() ([]*library.Schedule, error) + // ListSchedules defines a function that gets a list of all schedules. + ListSchedules() ([]*library.Schedule, error) + // ListSchedulesForRepo defines a function that gets a list of schedules by repo ID. + ListSchedulesForRepo(*library.Repo, int, int) ([]*library.Schedule, int64, error) + // UpdateSchedule defines a function that updates an existing schedule. + UpdateSchedule(*library.Schedule) error +} diff --git a/database/schedule/list.go b/database/schedule/list.go new file mode 100644 index 000000000..f4c5aa5e7 --- /dev/null +++ b/database/schedule/list.go @@ -0,0 +1,52 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListSchedules gets a list of all schedules from the database. +func (e *engine) ListSchedules() ([]*library.Schedule, error) { + e.logger.Trace("listing all schedules from the database") + + // variables to store query results and return value + count := int64(0) + s := new([]database.Schedule) + schedules := []*library.Schedule{} + + // count the results + count, err := e.CountSchedules() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return schedules, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSchedule). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, schedule := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := schedule + + // convert query result to API type + schedules = append(schedules, tmp.ToLibrary()) + } + + return schedules, nil +} diff --git a/database/schedule/list_active.go b/database/schedule/list_active.go new file mode 100644 index 000000000..d0efa5dde --- /dev/null +++ b/database/schedule/list_active.go @@ -0,0 +1,53 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +// ListActiveSchedules gets a list of all active schedules from the database. +func (e *engine) ListActiveSchedules() ([]*library.Schedule, error) { + e.logger.Trace("listing all active schedules from the database") + + // variables to store query results and return value + count := int64(0) + s := new([]database.Schedule) + schedules := []*library.Schedule{} + + // count the results + count, err := e.CountActiveSchedules() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return schedules, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSchedule). + Where("active = ?", true). + Find(&s). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, schedule := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := schedule + + // convert query result to API type + schedules = append(schedules, tmp.ToLibrary()) + } + + return schedules, nil +} diff --git a/database/schedule/list_active_test.go b/database/schedule/list_active_test.go new file mode 100644 index 000000000..69c690def --- /dev/null +++ b/database/schedule/list_active_test.go @@ -0,0 +1,111 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetActive(true) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetActive(false) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules" WHERE active = $1`).WithArgs(true).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). + AddRow(1, 1, true, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE active = $1`).WithArgs(true).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Schedule + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Schedule{_scheduleOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Schedule{_scheduleOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListActiveSchedules() + + if test.failure { + if err == nil { + t.Errorf("ListActiveSchedules for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListActiveSchedules for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListActiveSchedules for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/list_repo.go b/database/schedule/list_repo.go new file mode 100644 index 000000000..1137e0c4b --- /dev/null +++ b/database/schedule/list_repo.go @@ -0,0 +1,63 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListSchedulesForRepo gets a list of schedules by repo ID from the database. +func (e *engine) ListSchedulesForRepo(r *library.Repo, page, perPage int) ([]*library.Schedule, int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("listing schedules for repo %s from the database", r.GetFullName()) + + // variables to store query results and return value + count := int64(0) + s := new([]database.Schedule) + schedules := []*library.Schedule{} + + // count the results + count, err := e.CountSchedulesForRepo(r) + if err != nil { + return nil, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return schedules, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableSchedule). + Where("repo_id = ?", r.GetID()). + Order("id DESC"). + Limit(perPage). + Offset(offset). + Find(&s). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, schedule := range *s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := schedule + + // convert query result to library type + schedules = append(schedules, tmp.ToLibrary()) + } + + return schedules, count, nil +} diff --git a/database/schedule/list_repo_test.go b/database/schedule/list_repo_test.go new file mode 100644 index 000000000..df56c0ee4 --- /dev/null +++ b/database/schedule/list_repo_test.go @@ -0,0 +1,115 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { + _repo := testRepo() + _repo.SetID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). + AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE repo_id = $1 ORDER BY id DESC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Schedule + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Schedule{_scheduleOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Schedule{_scheduleOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListSchedulesForRepo(_repo, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListSchedulesForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSchedulesForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSchedulesForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/list_test.go b/database/schedule/list_test.go new file mode 100644 index 000000000..b0c3bb417 --- /dev/null +++ b/database/schedule/list_test.go @@ -0,0 +1,110 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestSchedule_Engine_ListSchedules(t *testing.T) { + _scheduleOne := testSchedule() + _scheduleOne.SetID(1) + _scheduleOne.SetRepoID(1) + _scheduleOne.SetName("nightly") + _scheduleOne.SetEntry("0 0 * * *") + _scheduleOne.SetCreatedAt(1) + _scheduleOne.SetCreatedBy("user1") + _scheduleOne.SetUpdatedAt(1) + _scheduleOne.SetUpdatedBy("user2") + + _scheduleTwo := testSchedule() + _scheduleTwo.SetID(2) + _scheduleTwo.SetRepoID(2) + _scheduleTwo.SetName("hourly") + _scheduleTwo.SetEntry("0 * * * *") + _scheduleTwo.SetCreatedAt(1) + _scheduleTwo.SetCreatedBy("user1") + _scheduleTwo.SetUpdatedAt(1) + _scheduleTwo.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "schedules"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). + AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil). + AddRow(2, 2, false, "hourly", "0 * * * *", 1, "user1", 1, "user2", nil) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "schedules"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_scheduleOne) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + err = _sqlite.CreateSchedule(_scheduleTwo) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Schedule + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Schedule{_scheduleOne, _scheduleTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Schedule{_scheduleOne, _scheduleTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListSchedules() + + if test.failure { + if err == nil { + t.Errorf("ListSchedules for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListSchedules for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListSchedules for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/schedule/opts.go b/database/schedule/opts.go new file mode 100644 index 000000000..7ac87bea1 --- /dev/null +++ b/database/schedule/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Schedules. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Schedules. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the schedule engine + e.client = client + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Schedules. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the schedule engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Schedules. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the schedule engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/schedule/opts_test.go b/database/schedule/opts_test.go new file mode 100644 index 000000000..6159801e3 --- /dev/null +++ b/database/schedule/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestSchedule_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestSchedule_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestSchedule_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/schedule/schedule.go b/database/schedule/schedule.go new file mode 100644 index 000000000..0517dcae9 --- /dev/null +++ b/database/schedule/schedule.go @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the ScheduleInterface interface. + config struct { + // specifies to skip creating tables and indexes for the Schedule engine + SkipCreation bool + } + + // engine represents the schedule functionality that implements the ScheduleInterface interface. + engine struct { + // engine configuration settings used in schedule functions + config *config + + // gorm.io/gorm database client used in schedule functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in schedule functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with schedules in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Schedule engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating schedule database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of schedules table and indexes in the database") + + return e, nil + } + + // create the schedules table + err := e.CreateScheduleTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableSchedule, err) + } + + // create the indexes for the schedules table + err = e.CreateScheduleIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableSchedule, err) + } + + return e, nil +} diff --git a/database/schedule/schedule_test.go b/database/schedule/schedule_test.go new file mode 100644 index 000000000..c86f1f353 --- /dev/null +++ b/database/schedule/schedule_test.go @@ -0,0 +1,212 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestSchedule_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres schedule engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite schedule engine: %v", err) + } + + return _engine +} + +// testSchedule is a test helper function to create an API Schedule type with all fields set to their zero values. +func testSchedule() *library.Schedule { + return &library.Schedule{ + ID: new(int64), + RepoID: new(int64), + Active: new(bool), + Name: new(string), + Entry: new(string), + CreatedAt: new(int64), + CreatedBy: new(string), + UpdatedAt: new(int64), + UpdatedBy: new(string), + ScheduledAt: new(int64), + } +} + +// testRepo is a test helper function to create a library Repo type with all fields set to their zero values. +func testRepo() *library.Repo { + return &library.Repo{ + ID: new(int64), + UserID: 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), + AllowPull: new(bool), + AllowPush: new(bool), + AllowDeploy: new(bool), + AllowTag: new(bool), + AllowComment: new(bool), + } +} diff --git a/database/schedule/table.go b/database/schedule/table.go new file mode 100644 index 000000000..05ffe8bad --- /dev/null +++ b/database/schedule/table.go @@ -0,0 +1,66 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "github.com/go-vela/types/constants" +) + +const ( + // CreatePostgresTable represents a query to create the Postgres schedules table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +schedules ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + active BOOLEAN, + name VARCHAR(100), + entry VARCHAR(100), + created_at INTEGER, + created_by VARCHAR(250), + updated_at INTEGER, + updated_by VARCHAR(250), + scheduled_at INTEGER, + UNIQUE(repo_id, name) +); +` + + // CreateSqliteTable represents a query to create the Sqlite schedules table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +schedules ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + active BOOLEAN, + name TEXT, + entry TEXT, + created_at INTEGER, + created_by TEXT, + updated_at INTEGER, + updated_by TEXT, + scheduled_at INTEGER, + UNIQUE(repo_id, name) +); +` +) + +// CreateScheduleTable creates the schedules table in the database. +func (e *engine) CreateScheduleTable(driver string) error { + e.logger.Tracef("creating schedules table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the schedules table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the schedules table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/schedule/table_test.go b/database/schedule/table_test.go new file mode 100644 index 000000000..c4dbf4e40 --- /dev/null +++ b/database/schedule/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_CreateScheduleTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateScheduleTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateScheduleTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateScheduleTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/schedule/update.go b/database/schedule/update.go new file mode 100644 index 000000000..b69f8eff0 --- /dev/null +++ b/database/schedule/update.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create.go +package schedule + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateSchedule updates an existing schedule in the database. +func (e *engine) UpdateSchedule(s *library.Schedule) error { + e.logger.WithFields(logrus.Fields{ + "schedule": s.GetName(), + }).Tracef("updating schedule %s in the database", s.GetName()) + + // cast the library type to database type + schedule := database.ScheduleFromLibrary(s) + + // validate the necessary fields are populated + err := schedule.Validate() + if err != nil { + return err + } + + // send query to the database + return e.client. + Table(constants.TableSchedule). + Save(schedule). + Error +} diff --git a/database/schedule/update_test.go b/database/schedule/update_test.go new file mode 100644 index 000000000..05fff4286 --- /dev/null +++ b/database/schedule/update_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestSchedule_Engine_UpdateSchedule(t *testing.T) { + _repo := testRepo() + _repo.SetID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "schedules" +SET "repo_id"=$1,"active"=$2,"name"=$3,"entry"=$4,"created_at"=$5,"created_by"=$6,"updated_at"=$7,"updated_by"=$8,"scheduled_at"=$9 +WHERE "id" = $10`). + WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", time.Now().UTC().Unix(), "user2", nil, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_schedule) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateSchedule(_schedule) + + if test.failure { + if err == nil { + t.Errorf("UpdateSchedule for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateSchedule for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index d16f7cf09..3faa555ba 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -12,6 +12,7 @@ import ( "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/service" "github.com/go-vela/server/database/sqlite/ddl" @@ -57,6 +58,8 @@ type ( pipeline.PipelineInterface // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface repo.RepoInterface + // https://pkg.go.dev/github.com/go-vela/server/database/schedule#ScheduleInterface + schedule.ScheduleInterface // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface secret.SecretInterface // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface @@ -338,6 +341,18 @@ func createServices(c *client) error { return err } + // create the database agnostic engine for schedules + // + // https://pkg.go.dev/github.com/go-vela/server/database/schedule#New + c.ScheduleInterface, err = schedule.New( + schedule.WithClient(c.Sqlite), + schedule.WithLogger(c.Logger), + schedule.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic engine for secrets // // https://pkg.go.dev/github.com/go-vela/server/database/secret#New diff --git a/go.mod b/go.mod index 7e26a5732..95e264713 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.2 + github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 @@ -45,6 +45,7 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/adhocore/gronx v1.6.2 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -102,6 +103,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect diff --git a/go.sum b/go.sum index 478dcc750..e0f559ca4 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/adhocore/gronx v1.6.2 h1:/Pg6cuHFJmUGRIYWhRFjb6iL9fdzNmoMPj+/r6L01KU= +github.com/adhocore/gronx v1.6.2/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= @@ -136,8 +138,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.2 h1:xU61CX2jdMuBCtLOg8a7Z2aEWYM1zZt37Ygx1oHGbjM= -github.com/go-vela/types v0.19.2/go.mod h1:ZvDjYCKU36yJS3sLxPLCny/HLF1U6YtlOienzv/cXB4= +github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6 h1:WVmgeHuPN2WHTf/tJtseEMPxPoKdit2rD4nCZyPIias= +github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -347,7 +349,8 @@ github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= From 5092d22e6df70ded2b2609e3bf18c577bf3e3f65 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Thu, 18 May 2023 15:45:08 -0500 Subject: [PATCH 233/298] fix: allow setting worker.active to false (#850) * fix: allow setting worker.active to false * fix: whitespace --- api/worker/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/worker/update.go b/api/worker/update.go index 0c2f9c4fb..16d34f686 100644 --- a/api/worker/update.go +++ b/api/worker/update.go @@ -93,7 +93,7 @@ func UpdateWorker(c *gin.Context) { w.SetRoutes(input.GetRoutes()) } - if input.GetActive() { + if input.Active != nil { // update active if set w.SetActive(input.GetActive()) } From ca211753a9a03de39adfc837298d2c43fd71116c Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 19 May 2023 08:45:24 -0600 Subject: [PATCH 234/298] refactor(api): move service logic to separate package (#849) * refactor(api): move service logic to separate package * add doc.go * fix imports --- api/build.go | 56 ++++ api/service.go | 593 ------------------------------------------ api/service/create.go | 128 +++++++++ api/service/delete.go | 97 +++++++ api/service/doc.go | 10 + api/service/get.go | 86 ++++++ api/service/list.go | 146 +++++++++++ api/service/update.go | 149 +++++++++++ api/step.go | 4 - router/service.go | 20 +- 10 files changed, 682 insertions(+), 607 deletions(-) delete mode 100644 api/service.go create mode 100644 api/service/create.go create mode 100644 api/service/delete.go create mode 100644 api/service/doc.go create mode 100644 api/service/get.go create mode 100644 api/service/list.go create mode 100644 api/service/update.go diff --git a/api/build.go b/api/build.go index 60f7f8eb1..8519a8e53 100644 --- a/api/build.go +++ b/api/build.go @@ -1621,6 +1621,62 @@ func planBuild(database database.Interface, p *pipeline.Build, b *library.Build, return nil } +// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { + // variable to store planned services + services := []*library.Service{} + + // iterate through all pipeline services + for _, service := range p.Services { + // create the service object + s := new(library.Service) + s.SetBuildID(b.GetID()) + s.SetRepoID(b.GetRepoID()) + s.SetName(service.Name) + s.SetImage(service.Image) + s.SetNumber(service.Number) + s.SetStatus(constants.StatusPending) + s.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the service + err := database.CreateService(s) + if err != nil { + return services, fmt.Errorf("unable to create service %s: %w", s.GetName(), err) + } + + // send API call to capture the created service + s, err = database.GetServiceForBuild(b, s.GetNumber()) + if err != nil { + return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) + } + + // populate environment variables from service library + // + // https://pkg.go.dev/github.com/go-vela/types/library#Service.Environment + err = service.MergeEnv(s.Environment()) + if err != nil { + return services, err + } + + // create the log object + l := new(library.Log) + l.SetServiceID(s.GetID()) + l.SetBuildID(b.GetID()) + l.SetRepoID(b.GetRepoID()) + l.SetData([]byte{}) + + // send API call to create the service logs + err = database.CreateLog(l) + if err != nil { + return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) + } + } + + return services, nil +} + // cleanBuild is a helper function to kill the build // without execution. This will kill all resources, // like steps and services, for the build in the diff --git a/api/service.go b/api/service.go deleted file mode 100644 index 66b81b080..000000000 --- a/api/service.go +++ /dev/null @@ -1,593 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - "time" - - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/user" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/build" - "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/service" - "github.com/go-vela/server/util" - - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/go-vela/types/pipeline" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/services services CreateService -// -// Create a service for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the service to create -// required: true -// schema: -// "$ref": "#/definitions/Service" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the service -// schema: -// "$ref": "#/definitions/Service" -// '400': -// description: Unable to create the service -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the service -// schema: -// "$ref": "#/definitions/Error" - -// CreateService represents the API handler to create -// a service for a build in the configured backend. -// -//nolint:dupl // ignore similar code with step -func CreateService(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("creating new service for build %s", entry) - - // capture body from API request - input := new(library.Service) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new service for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in service object - input.SetRepoID(r.GetID()) - input.SetBuildID(b.GetID()) - - if len(input.GetStatus()) == 0 { - input.SetStatus(constants.StatusPending) - } - - if input.GetCreated() == 0 { - input.SetCreated(time.Now().UTC().Unix()) - } - - // send API call to create the service - err = database.FromContext(c).CreateService(input) - if err != nil { - retErr := fmt.Errorf("unable to create service for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created service - s, _ := database.FromContext(c).GetServiceForBuild(b, input.GetNumber()) - - c.JSON(http.StatusCreated, s) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services services GetServices -// -// Get a list of all services for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the list of services -// schema: -// type: array -// items: -// "$ref": "#/definitions/Service" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of services -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of services -// schema: -// "$ref": "#/definitions/Error" - -// GetServices represents the API handler to capture a list -// of services for a build from the configured backend. -func GetServices(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading services for build %s", entry) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of services for the build - s, t, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get services for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, s) -} - -// -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services GetService -// -// Get a service for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: Name of the service -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the service -// schema: -// "$ref": "#/definitions/Service" -// '400': -// description: Unable to retrieve the service -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the service -// schema: -// "$ref": "#/definitions/Error" - -// GetService represents the API handler to capture a -// service for a build from the configured backend. -func GetService(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("reading service %s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - c.JSON(http.StatusOK, s) -} - -// -// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services UpdateService -// -// Update a service for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: Service number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the service to update -// required: true -// schema: -// "$ref": "#/definitions/Service" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the service -// schema: -// "$ref": "#/definitions/Service" -// '400': -// description: Unable to update the service -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the service -// schema: -// "$ref": "#/definitions/Error" - -// UpdateService represents the API handler to update -// a service for a build in the configured backend. -func UpdateService(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("updating service %s", entry) - - // capture body from API request - input := new(library.Service) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update service fields if provided - if len(input.GetStatus()) > 0 { - // update status if set - s.SetStatus(input.GetStatus()) - } - - if len(input.GetError()) > 0 { - // update error if set - s.SetError(input.GetError()) - } - - if input.GetExitCode() > 0 { - // update exit_code if set - s.SetExitCode(input.GetExitCode()) - } - - if input.GetStarted() > 0 { - // update started if set - s.SetStarted(input.GetStarted()) - } - - if input.GetFinished() > 0 { - // update finished if set - s.SetFinished(input.GetFinished()) - } - - // send API call to update the service - err = database.FromContext(c).UpdateService(s) - if err != nil { - retErr := fmt.Errorf("unable to update service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated service - s, _ = database.FromContext(c).GetServiceForBuild(b, s.GetNumber()) - - c.JSON(http.StatusOK, s) -} - -// -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services DeleteService -// -// Delete a service for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: Service Number -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the service -// schema: -// type: string -// '500': -// description: Unable to delete the service -// schema: -// "$ref": "#/definitions/Error" - -// DeleteService represents the API handler to remove -// a service for a build from the configured backend. -// -//nolint:dupl // ignore similar code with step -func DeleteService(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("deleting service %s", entry) - - // send API call to remove the service - err := database.FromContext(c).DeleteService(s) - if err != nil { - retErr := fmt.Errorf("unable to delete service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("service %s deleted", entry)) -} - -// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { - // variable to store planned services - services := []*library.Service{} - - // iterate through all pipeline services - for _, service := range p.Services { - // create the service object - s := new(library.Service) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetName(service.Name) - s.SetImage(service.Image) - s.SetNumber(service.Number) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the service - err := database.CreateService(s) - if err != nil { - return services, fmt.Errorf("unable to create service %s: %w", s.GetName(), err) - } - - // send API call to capture the created service - s, err = database.GetServiceForBuild(b, s.GetNumber()) - if err != nil { - return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) - } - - // populate environment variables from service library - // - // https://pkg.go.dev/github.com/go-vela/types/library#Service.Environment - err = service.MergeEnv(s.Environment()) - if err != nil { - return services, err - } - - // create the log object - l := new(library.Log) - l.SetServiceID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the service logs - err = database.CreateLog(l) - if err != nil { - return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) - } - } - - return services, nil -} diff --git a/api/service/create.go b/api/service/create.go new file mode 100644 index 000000000..426f13760 --- /dev/null +++ b/api/service/create.go @@ -0,0 +1,128 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/services services CreateService +// +// Create a service for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the service to create +// required: true +// schema: +// "$ref": "#/definitions/Service" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the service +// schema: +// "$ref": "#/definitions/Service" +// '400': +// description: Unable to create the service +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the service +// schema: +// "$ref": "#/definitions/Error" + +// CreateService represents the API handler to create +// a service for a build in the configured backend. +func CreateService(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("creating new service for build %s", entry) + + // capture body from API request + input := new(library.Service) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new service for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in service object + input.SetRepoID(r.GetID()) + input.SetBuildID(b.GetID()) + + if len(input.GetStatus()) == 0 { + input.SetStatus(constants.StatusPending) + } + + if input.GetCreated() == 0 { + input.SetCreated(time.Now().UTC().Unix()) + } + + // send API call to create the service + err = database.FromContext(c).CreateService(input) + if err != nil { + retErr := fmt.Errorf("unable to create service for build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created service + s, _ := database.FromContext(c).GetServiceForBuild(b, input.GetNumber()) + + c.JSON(http.StatusCreated, s) +} diff --git a/api/service/delete.go b/api/service/delete.go new file mode 100644 index 000000000..d85aa0fe8 --- /dev/null +++ b/api/service/delete.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services DeleteService +// +// Delete a service for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service Number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the service +// schema: +// type: string +// '500': +// description: Unable to delete the service +// schema: +// "$ref": "#/definitions/Error" + +// DeleteService represents the API handler to remove +// a service for a build from the configured backend. +func DeleteService(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("deleting service %s", entry) + + // send API call to remove the service + err := database.FromContext(c).DeleteService(s) + if err != nil { + retErr := fmt.Errorf("unable to delete service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("service %s deleted", entry)) +} diff --git a/api/service/doc.go b/api/service/doc.go new file mode 100644 index 000000000..53dc07284 --- /dev/null +++ b/api/service/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package service provides the service handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/service" +package service diff --git a/api/service/get.go b/api/service/get.go new file mode 100644 index 000000000..b2165a69f --- /dev/null +++ b/api/service/get.go @@ -0,0 +1,86 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services GetService +// +// Get a service for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Name of the service +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the service +// schema: +// "$ref": "#/definitions/Service" +// '400': +// description: Unable to retrieve the service +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the service +// schema: +// "$ref": "#/definitions/Error" + +// GetService represents the API handler to capture a +// service for a build from the configured backend. +func GetService(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("reading service %s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + c.JSON(http.StatusOK, s) +} diff --git a/api/service/list.go b/api/service/list.go new file mode 100644 index 000000000..22a7b8be7 --- /dev/null +++ b/api/service/list.go @@ -0,0 +1,146 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services services ListServices +// +// Get a list of all services for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the list of services +// schema: +// type: array +// items: +// "$ref": "#/definitions/Service" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of services +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of services +// schema: +// "$ref": "#/definitions/Error" + +// ListServices represents the API handler to capture a list +// of services for a build from the configured backend. +func ListServices(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading services for build %s", entry) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of services for the build + s, t, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get services for build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, s) +} diff --git a/api/service/update.go b/api/service/update.go new file mode 100644 index 000000000..bed781f88 --- /dev/null +++ b/api/service/update.go @@ -0,0 +1,149 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service} services UpdateService +// +// Update a service for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the service to update +// required: true +// schema: +// "$ref": "#/definitions/Service" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the service +// schema: +// "$ref": "#/definitions/Service" +// '400': +// description: Unable to update the service +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the service +// schema: +// "$ref": "#/definitions/Error" + +// UpdateService represents the API handler to update +// a service for a build in the configured backend. +func UpdateService(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("updating service %s", entry) + + // capture body from API request + input := new(library.Service) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update service fields if provided + if len(input.GetStatus()) > 0 { + // update status if set + s.SetStatus(input.GetStatus()) + } + + if len(input.GetError()) > 0 { + // update error if set + s.SetError(input.GetError()) + } + + if input.GetExitCode() > 0 { + // update exit_code if set + s.SetExitCode(input.GetExitCode()) + } + + if input.GetStarted() > 0 { + // update started if set + s.SetStarted(input.GetStarted()) + } + + if input.GetFinished() > 0 { + // update finished if set + s.SetFinished(input.GetFinished()) + } + + // send API call to update the service + err = database.FromContext(c).UpdateService(s) + if err != nil { + retErr := fmt.Errorf("unable to update service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated service + s, _ = database.FromContext(c).GetServiceForBuild(b, s.GetNumber()) + + c.JSON(http.StatusOK, s) +} diff --git a/api/step.go b/api/step.go index 23d72fac4..aab74067b 100644 --- a/api/step.go +++ b/api/step.go @@ -71,8 +71,6 @@ import ( // CreateStep represents the API handler to create // a step for a build in the configured backend. -// -//nolint:dupl // ignore similar code with service func CreateStep(c *gin.Context) { // capture middleware values b := build.Retrieve(c) @@ -501,8 +499,6 @@ func UpdateStep(c *gin.Context) { // DeleteStep represents the API handler to remove // a step for a build from the configured backend. -// -//nolint:dupl // ignore similar code with service func DeleteStep(c *gin.Context) { // capture middleware values b := build.Retrieve(c) diff --git a/router/service.go b/router/service.go index f344e03eb..7b81e7af7 100644 --- a/router/service.go +++ b/router/service.go @@ -7,10 +7,10 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/service" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/perm" - "github.com/go-vela/server/router/middleware/service" + smiddleware "github.com/go-vela/server/router/middleware/service" ) // ServiceHandlers is a function that extends the provided base router group @@ -24,23 +24,23 @@ import ( // POST /api/v1/repos/:org/:repo/builds/:build/services/:service/logs // GET /api/v1/repos/:org/:repo/builds/:build/services/:service/logs // PUT /api/v1/repos/:org/:repo/builds/:build/services/:service/logs -// DELETE /api/v1/repos/:org/:repo/builds/:build/services/:service/logs +// DELETE /api/v1/repos/:org/:repo/builds/:build/services/:service/logs . func ServiceHandlers(base *gin.RouterGroup) { // Services endpoints services := base.Group("/services") { - services.POST("", perm.MustPlatformAdmin(), middleware.Payload(), api.CreateService) - services.GET("", perm.MustRead(), api.GetServices) + services.POST("", perm.MustPlatformAdmin(), middleware.Payload(), service.CreateService) + services.GET("", perm.MustRead(), service.ListServices) // Service endpoints - service := services.Group("/:service", service.Establish()) + s := services.Group("/:service", smiddleware.Establish()) { - service.GET("", perm.MustRead(), api.GetService) - service.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateService) - service.DELETE("", perm.MustPlatformAdmin(), api.DeleteService) + s.GET("", perm.MustRead(), service.GetService) + s.PUT("", perm.MustBuildAccess(), middleware.Payload(), service.UpdateService) + s.DELETE("", perm.MustPlatformAdmin(), service.DeleteService) // Log endpoints - LogServiceHandlers(service) + LogServiceHandlers(s) } // end of service endpoints } // end of services endpoints } From 3919d6cd3c6e74ffbeae8489beef088e814a62d5 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 19 May 2023 12:07:15 -0500 Subject: [PATCH 235/298] chore: vscode gitignore from toptal (#845) --- .gitignore | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4ac8d000b..58613c5d3 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,29 @@ secrets.env .env.test # Files to be excluded. -.DS_Store \ No newline at end of file +.DS_Store + +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix +__debug_bin + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode \ No newline at end of file From f276feeb42b72f5b31447792819d6c4b2ac21403 Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Fri, 19 May 2023 16:07:40 -0500 Subject: [PATCH 236/298] feat(api): add support for schedules (#836) * feat(api/types): add support for schedules * feat(database/types): add support for schedules * feat(database): add support for schedules * chore: update go dependencies * feat(database): add schedule engine * feat(api): add support for schedules * add routes * fix: parse entry for schedules * more wip code * add schedule allowlist * fix tests * add validation for entry * add mocks w/o updated payloads * fix issues with create * update mock responses * use schedule mocks * make linter happy * use proper func * couple more updates * fix mock pathing * enhance: switch to adhocore/gronx * chore: update go deps * goimports * yet another goimports * sigh * wildcard goimport * chore: address linter feedback * chore: remove new types * chore: updates for removed types * chore: update go dependencies * chore: address review feedback * chore: remove new types * update go.mod * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * Update api/schedule/create.go Co-authored-by: Jordan Brockopp * address feedback * goimports * address feedback * updated logic for updating inactive schedules * clarify error message --------- Co-authored-by: JordanBrockopp Co-authored-by: Jordan Brockopp --- .gitignore | 3 +- api/repo/create.go | 29 +-- api/schedule/create.go | 230 +++++++++++++++++++ api/schedule/create_test.go | 62 +++++ api/schedule/delete.go | 88 +++++++ api/schedule/get.go | 69 ++++++ api/schedule/list.go | 131 +++++++++++ api/schedule/update.go | 140 +++++++++++ cmd/vela-server/main.go | 13 ++ cmd/vela-server/server.go | 2 + docker-compose.yml | 1 + go.mod | 2 +- mock/server/schedule.go | 213 +++++++++++++++++ mock/server/server.go | 7 + router/middleware/allowlist_schedule.go | 18 ++ router/middleware/allowlist_schedule_test.go | 46 ++++ router/middleware/schedule/context.go | 39 ++++ router/middleware/schedule/context_test.go | 89 +++++++ router/middleware/schedule/schedule.go | 59 +++++ router/middleware/schedule_frequency.go | 20 ++ router/middleware/schedule_frequency_test.go | 47 ++++ router/router.go | 4 + router/schedule.go | 39 ++++ util/util.go | 29 +++ 24 files changed, 1350 insertions(+), 30 deletions(-) create mode 100644 api/schedule/create.go create mode 100644 api/schedule/create_test.go create mode 100644 api/schedule/delete.go create mode 100644 api/schedule/get.go create mode 100644 api/schedule/list.go create mode 100644 api/schedule/update.go create mode 100644 mock/server/schedule.go create mode 100644 router/middleware/allowlist_schedule.go create mode 100644 router/middleware/allowlist_schedule_test.go create mode 100644 router/middleware/schedule/context.go create mode 100644 router/middleware/schedule/context_test.go create mode 100644 router/middleware/schedule/schedule.go create mode 100644 router/middleware/schedule_frequency.go create mode 100644 router/middleware/schedule_frequency_test.go create mode 100644 router/schedule.go diff --git a/.gitignore b/.gitignore index 58613c5d3..f3be5762d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ secrets.env # Files to be excluded. .DS_Store +api-spec.json # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode @@ -66,4 +67,4 @@ __debug_bin .history .ionide -# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode diff --git a/api/repo/create.go b/api/repo/create.go index d196c2a48..91d42064e 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -214,7 +214,7 @@ func CreateRepo(c *gin.Context) { ) // ensure repo is allowed to be activated - if !checkAllowlist(r, allowlist) { + if !util.CheckAllowlist(r, allowlist) { retErr := fmt.Errorf("unable to activate repo: %s is not on allowlist", r.GetFullName()) util.HandleError(c, http.StatusForbidden, retErr) @@ -328,30 +328,3 @@ func CreateRepo(c *gin.Context) { c.JSON(http.StatusCreated, r) } - -// checkAllowlist is a helper function to ensure only repos in the -// allowlist are allowed to enable repos. -// -// a single entry of '*' allows any repo to be enabled. -func checkAllowlist(r *library.Repo, allowlist []string) bool { - // check if all repos are allowed to be enabled - if len(allowlist) == 1 && allowlist[0] == "*" { - return true - } - - for _, repo := range allowlist { - // allow all repos in org - if strings.Contains(repo, "/*") { - if strings.HasPrefix(repo, r.GetOrg()) { - return true - } - } - - // allow specific repo within org - if repo == r.GetFullName() { - return true - } - } - - return false -} diff --git a/api/schedule/create.go b/api/schedule/create.go new file mode 100644 index 000000000..127c04909 --- /dev/null +++ b/api/schedule/create.go @@ -0,0 +1,230 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + "net/http" + "time" + + "github.com/adhocore/gronx" + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/schedules/{org}/{repo} schedules CreateSchedule +// +// Create a schedule in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the schedule to create +// required: true +// schema: +// "$ref": "#/definitions/Schedule" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the schedule +// schema: +// "$ref": "#/definitions/Schedule" +// '400': +// description: Unable to create the schedule +// schema: +// "$ref": "#/definitions/Error" +// '403': +// description: Unable to create the schedule +// schema: +// "$ref": "#/definitions/Error" +// '409': +// description: Unable to create the schedule +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the schedule +// schema: +// "$ref": "#/definitions/Error" +// '503': +// description: Unable to create the schedule +// schema: +// "$ref": "#/definitions/Error" + +// CreateSchedule represents the API handler to +// create a schedule in the configured backend. +func CreateSchedule(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + r := repo.Retrieve(c) + allowlist := c.Value("allowlistschedule").([]string) + minimumFrequency := c.Value("scheduleminimumfrequency").(time.Duration) + + // capture body from API request + input := new(library.Schedule) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new schedule: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure the entry is valid + err = validateEntry(minimumFrequency, input.GetEntry()) + if err != nil { + retErr := fmt.Errorf("schedule of %s with entry %s is invalid: %w", input.GetName(), input.GetEntry(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure schedule name is defined + if input.GetName() == "" { + util.HandleError(c, http.StatusBadRequest, fmt.Errorf("schedule name must be set")) + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("creating new schedule %s", input.GetName()) + + // ensure repo is allowed to create new schedules + if !util.CheckAllowlist(r, allowlist) { + retErr := fmt.Errorf("unable to create schedule %s: %s is not on allowlist", input.GetName(), r.GetFullName()) + + util.HandleError(c, http.StatusForbidden, retErr) + + return + } + + s := new(library.Schedule) + + // update fields in schedule object + s.SetCreatedBy(u.GetName()) + s.SetRepoID(r.GetID()) + s.SetName(input.GetName()) + s.SetEntry(input.GetEntry()) + s.SetCreatedAt(time.Now().UTC().Unix()) + s.SetUpdatedAt(time.Now().UTC().Unix()) + s.SetUpdatedBy(u.GetName()) + + // set the active field based off the input provided + if input.Active == nil { + // default active field to true + s.SetActive(true) + } else { + s.SetActive(input.GetActive()) + } + + // send API call to capture the schedule from the database + dbSchedule, err := database.FromContext(c).GetScheduleForRepo(r, input.GetName()) + if err == nil && dbSchedule.GetActive() { + retErr := fmt.Errorf("unable to create schedule: %s is already active", input.GetName()) + + util.HandleError(c, http.StatusConflict, retErr) + + return + } + + if !r.GetActive() { + retErr := fmt.Errorf("unable to create schedule: %s repo %s is disabled", input.GetName(), r.GetFullName()) + + util.HandleError(c, http.StatusConflict, retErr) + + return + } + + // if the schedule exists but is inactive + if dbSchedule.GetID() != 0 && !dbSchedule.GetActive() && input.GetActive() { + // update the user who created the schedule + dbSchedule.SetUpdatedBy(u.GetName()) + // activate the schedule + dbSchedule.SetActive(true) + + // send API call to update the schedule + err = database.FromContext(c).UpdateSchedule(dbSchedule) + if err != nil { + retErr := fmt.Errorf("unable to set schedule %s to active: %w", dbSchedule.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated schedule + s, _ = database.FromContext(c).GetScheduleForRepo(r, dbSchedule.GetName()) + } else { + // send API call to create the schedule + err = database.FromContext(c).CreateSchedule(s) + if err != nil { + retErr := fmt.Errorf("unable to create new schedule %s: %w", r.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created schedule + s, _ = database.FromContext(c).GetScheduleForRepo(r, input.GetName()) + } + + c.JSON(http.StatusCreated, s) +} + +// validateEntry validates the entry for a minimum frequency. +func validateEntry(minimum time.Duration, entry string) error { + gron := gronx.New() + + // check if expr is even valid + valid := gron.IsValid(entry) + if !valid { + return fmt.Errorf("invalid entry of %s", entry) + } + + // check the previous occurrence of the entry + prevTime, err := gronx.PrevTick(entry, true) + if err != nil { + return err + } + + // check the next occurrence of the entry + nextTime, err := gronx.NextTick(entry, true) + if err != nil { + return err + } + + // ensure the time between previous and next schedule exceeds the minimum duration + if nextTime.Sub(prevTime) < minimum { + return fmt.Errorf("entry needs to occur less frequently than every %s", minimum) + } + + return nil +} diff --git a/api/schedule/create_test.go b/api/schedule/create_test.go new file mode 100644 index 000000000..0ca425e32 --- /dev/null +++ b/api/schedule/create_test.go @@ -0,0 +1,62 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + "time" +) + +func Test_validateEntry(t *testing.T) { + type args struct { + minimum time.Duration + entry string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "exceeds minimum frequency", + args: args{ + minimum: 30 * time.Minute, + entry: "* * * * *", + }, + wantErr: true, + }, + { + name: "exceeds minimum frequency with tag", + args: args{ + minimum: 30 * time.Minute, + entry: "@15minutes", + }, + wantErr: true, + }, + { + name: "meets minimum frequency", + args: args{ + minimum: 30 * time.Second, + entry: "* * * * *", + }, + wantErr: false, + }, + { + name: "meets minimum frequency with tag", + args: args{ + minimum: 30 * time.Second, + entry: "@hourly", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := validateEntry(tt.args.minimum, tt.args.entry); (err != nil) != tt.wantErr { + t.Errorf("validateEntry() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/api/schedule/delete.go b/api/schedule/delete.go new file mode 100644 index 000000000..fd7c0715f --- /dev/null +++ b/api/schedule/delete.go @@ -0,0 +1,88 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "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/schedule" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/{schedule} schedules DeleteSchedule +// +// Delete a schedule in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: schedule +// description: Name of the schedule +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the schedule +// schema: +// type: string +// '500': +// description: Unable to delete the schedule +// schema: +// "$ref": "#/definitions/Error" +// '510': +// description: Unable to delete the schedule +// schema: +// "$ref": "#/definitions/Error" + +// DeleteSchedule represents the API handler to remove +// a schedule from the configured backend. +func DeleteSchedule(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + s := schedule.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("deleting schedule %s", s.GetName()) + + err := database.FromContext(c).DeleteSchedule(s) + if err != nil { + retErr := fmt.Errorf("unable to delete schedule %s: %w", s.GetName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("schedule %s deleted", s.GetName())) +} diff --git a/api/schedule/get.go b/api/schedule/get.go new file mode 100644 index 000000000..51a436bbe --- /dev/null +++ b/api/schedule/get.go @@ -0,0 +1,69 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/schedule" + "github.com/go-vela/server/router/middleware/user" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/schedules/{org}/{repo}/{schedule} schedules GetSchedule +// +// Get a schedule in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: schedule +// description: Name of the schedule +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the schedule +// schema: +// "$ref": "#/definitions/Schedule" + +// GetSchedule represents the API handler to +// capture a schedule from the configured backend. +func GetSchedule(c *gin.Context) { + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + s := schedule.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + "schedule": s.GetName(), + }).Infof("reading schedule %s", s.GetName()) + + c.JSON(http.StatusOK, s) +} diff --git a/api/schedule/list.go b/api/schedule/list.go new file mode 100644 index 000000000..c43188d86 --- /dev/null +++ b/api/schedule/list.go @@ -0,0 +1,131 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/schedules/{org}/{repo} schedules ListSchedules +// +// Get all schedules in the configured backend +// +// --- +// produces: +// - application/json +// security: +// - ApiKeyAuth: [] +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// responses: +// '200': +// description: Successfully retrieved the schedules +// schema: +// type: array +// items: +// "$ref": "#/definitions/Schedule" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the schedules +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the schedules +// schema: +// "$ref": "#/definitions/Error" + +// ListSchedules represents the API handler to capture a list +// of schedules for a repo from the configured backend. +func ListSchedules(c *gin.Context) { + // capture middleware values + r := repo.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "repo": r.GetName(), + "org": r.GetOrg(), + }).Infof("listing schedules for repo %s", r.GetFullName()) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of schedules for the repo + s, t, err := database.FromContext(c).ListSchedulesForRepo(r, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to get schedules for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, s) +} diff --git a/api/schedule/update.go b/api/schedule/update.go new file mode 100644 index 000000000..bdadbdd2d --- /dev/null +++ b/api/schedule/update.go @@ -0,0 +1,140 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + "net/http" + "time" + + "github.com/go-vela/server/router/middleware/schedule" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/schedules/{org}/{repo}/{schedule} schedules UpdateSchedule +// +// Update a schedule for the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: schedule +// description: Name of the schedule +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the schedule to update +// required: true +// schema: +// "$ref": "#/definitions/Schedule" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the schedule +// schema: +// "$ref": "#/definitions/Schedule" +// '400': +// description: Unable to update the schedule +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to update the schedule +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the schedule +// schema: +// "$ref": "#/definitions/Error" + +// UpdateSchedule represents the API handler to update +// a schedule in the configured backend. +func UpdateSchedule(c *gin.Context) { + // capture middleware values + r := repo.Retrieve(c) + s := schedule.Retrieve(c) + scheduleName := util.PathParameter(c, "schedule") + minimumFrequency := c.Value("scheduleminimumfrequency").(time.Duration) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "schedule": scheduleName, + "repo": r.GetName(), + "org": r.GetOrg(), + }).Infof("updating schedule %s", scheduleName) + + // capture body from API request + input := new(library.Schedule) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for schedule %s: %w", scheduleName, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update schedule fields if provided + if input.Active != nil { + // update active if set to true + s.SetActive(input.GetActive()) + } + + if input.GetName() != "" { + // update name if defined + s.SetName(input.GetName()) + } + + if input.GetEntry() != "" { + err = validateEntry(minimumFrequency, input.GetEntry()) + if err != nil { + retErr := fmt.Errorf("schedule entry of %s is invalid: %w", input.GetEntry(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update entry if defined + s.SetEntry(input.GetEntry()) + } + + // update the schedule within the database + err = database.FromContext(c).UpdateSchedule(s) + if err != nil { + retErr := fmt.Errorf("unable to update scheduled %s: %w", scheduleName, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // capture the updated scheduled + s, _ = database.FromContext(c).GetScheduleForRepo(r, scheduleName) + + c.JSON(http.StatusOK, s) +} diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 0dff41473..48b67af59 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -203,6 +203,19 @@ func main() { Usage: "interval at which workers will show as active within the /metrics endpoint", Value: 5 * time.Minute, }, + // schedule flags + &cli.DurationFlag{ + EnvVars: []string{"VELA_SCHEDULE_MINIMUM_FREQUENCY", "SCHEDULE_MINIMUM_FREQUENCY"}, + Name: "schedule-minimum-frequency", + Usage: "minimum time between each schedule entry", + Value: 1 * time.Hour, + }, + &cli.StringSliceFlag{ + EnvVars: []string{"VELA_SCHEDULE_ALLOWLIST"}, + Name: "vela-schedule-allowlist", + Usage: "limit which repos can be utilize the schedule feature within the system", + Value: &cli.StringSlice{}, + }, } // Add Database Flags app.Flags = append(app.Flags, database.Flags...) diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 8ecb006e4..1f8bdbd9c 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -102,6 +102,8 @@ func server(c *cli.Context) error { middleware.SecureCookie(c.Bool("vela-enable-secure-cookie")), middleware.Worker(c.Duration("worker-active-interval")), middleware.DefaultRepoEvents(c.StringSlice("default-repo-events")), + middleware.AllowlistSchedule(c.StringSlice("vela-schedule-allowlist")), + middleware.ScheduleFrequency(c.Duration("schedule-minimum-frequency")), ) addr, err := url.Parse(c.String("server-addr")) diff --git a/docker-compose.yml b/docker-compose.yml index cb4ef0684..1394c317b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,6 +43,7 @@ services: VELA_DISABLE_WEBHOOK_VALIDATION: 'true' VELA_ENABLE_SECURE_COOKIE: 'false' VELA_REPO_ALLOWLIST: '*' + VELA_SCHEDULE_ALLOWLIST: '*' env_file: - .env restart: always diff --git a/go.mod b/go.mod index 95e264713..b2ab8d4c0 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 + github.com/adhocore/gronx v1.6.2 github.com/alicebob/miniredis/v2 v2.30.2 github.com/aws/aws-sdk-go v1.44.248 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 @@ -45,7 +46,6 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/adhocore/gronx v1.6.2 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect diff --git a/mock/server/schedule.go b/mock/server/schedule.go new file mode 100644 index 000000000..a1acc54f7 --- /dev/null +++ b/mock/server/schedule.go @@ -0,0 +1,213 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types" + "github.com/go-vela/types/library" +) + +const ( + // ScheduleResp represents a JSON return for a single schedule. + ScheduleResp = `{ + "id": 2, + "active": true, + "name": "foo", + "entry": "@weekly", + "created_at": 1683154980, + "created_by": "octocat", + "updated_at": 1683154980, + "updated_by": "octocat", + "scheduled_at": 0, + "repo": { + "id": 1, + "user_id": 1, + "org": "github", + "name": "octocat", + "full_name": "github/octocat", + "link": "https://github.com/github/octocat", + "clone": "https://github.com/github/octocat.git", + "branch": "main", + "topics": [], + "build_limit": 10, + "timeout": 30, + "counter": 0, + "visibility": "public", + "private": false, + "trusted": false, + "active": true, + "allow_pull": false, + "allow_push": true, + "allow_deploy": false, + "allow_tag": false, + "allow_comment": false, + "pipeline_type": "yaml", + "previous_name": "" + } +}` + SchedulesResp = `[ + { + "id": 2, + "active": true, + "name": "foo", + "entry": "@weekly", + "created_at": 1683154980, + "created_by": "octocat", + "updated_at": 1683154980, + "updated_by": "octocat", + "scheduled_at": 0, + "repo": { + "id": 1, + "user_id": 1, + "org": "github", + "name": "octokitty", + "full_name": "github/octokitty", + "link": "https://github.com/github/octokitty", + "clone": "https://github.com/github/octokitty.git", + "branch": "main", + "topics": [], + "build_limit": 10, + "timeout": 30, + "counter": 0, + "visibility": "public", + "private": false, + "trusted": false, + "active": true, + "allow_pull": false, + "allow_push": true, + "allow_deploy": false, + "allow_tag": false, + "allow_comment": false, + "pipeline_type": "yaml", + "previous_name": "" + } + }, + { + "id": 1, + "active": true, + "name": "bar", + "entry": "@weekly", + "created_at": 1683154974, + "created_by": "octocat", + "updated_at": 1683154974, + "updated_by": "octocat", + "scheduled_at": 0, + "repo": { + "id": 1, + "user_id": 1, + "org": "github", + "name": "octokitty", + "full_name": "github/octokitty", + "link": "https://github.com/github/octokitty", + "clone": "https://github.com/github/octokitty.git", + "branch": "main", + "topics": [], + "build_limit": 10, + "timeout": 30, + "counter": 0, + "visibility": "public", + "private": false, + "trusted": false, + "active": true, + "allow_pull": false, + "allow_push": true, + "allow_deploy": false, + "allow_tag": false, + "allow_comment": false, + "pipeline_type": "yaml", + "previous_name": "" + } + } +]` +) + +// getSchedules returns mock JSON for a http GET. +func getSchedules(c *gin.Context) { + data := []byte(SchedulesResp) + + var body []library.Schedule + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// getSchedule has a param :schedule returns mock JSON for a http GET. +// +// Pass "not-found" to :schedule to test receiving a http 404 response. +func getSchedule(c *gin.Context) { + s := c.Param("schedule") + + if strings.Contains(s, "not-found") { + msg := fmt.Sprintf("Schedule %s does not exist", s) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + data := []byte(ScheduleResp) + + var body library.Schedule + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// addSchedule returns mock JSON for a http POST. +func addSchedule(c *gin.Context) { + data := []byte(ScheduleResp) + + var body library.Schedule + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusCreated, body) +} + +// updateSchedule has a param :schedule returns mock JSON for a http PUT. +// +// Pass "not-found" to :schedule to test receiving a http 404 response. +func updateSchedule(c *gin.Context) { + if !strings.Contains(c.FullPath(), "admin") { + s := c.Param("schedule") + + if strings.Contains(s, "not-found") { + msg := fmt.Sprintf("Schedule %s does not exist", s) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + } + + data := []byte(ScheduleResp) + + var body library.Schedule + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + +// removeSchedule has a param :schedule returns mock JSON for a http DELETE. +// +// Pass "not-found" to :schedule to test receiving a http 404 response. +func removeSchedule(c *gin.Context) { + s := c.Param("schedule") + + if strings.Contains(s, "not-found") { + msg := fmt.Sprintf("Schedule %s does not exist", s) + + c.AbortWithStatusJSON(http.StatusNotFound, types.Error{Message: &msg}) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("schedule %s deleted", s)) +} diff --git a/mock/server/server.go b/mock/server/server.go index 0eb70188d..8fb6b1061 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -122,6 +122,13 @@ func FakeHandler() http.Handler { e.POST("/api/v1/workers/:worker/refresh", refreshWorkerAuth) e.DELETE("/api/v1/workers/:worker", removeWorker) + // mock endpoints for schedule calls + e.GET("/api/v1/schedules/:org/:repo", getSchedules) + e.GET("/api/v1/schedules/:org/:repo/:schedule", getSchedule) + e.POST("/api/v1/schedules/:org/:repo", addSchedule) + e.PUT("/api/v1/schedules/:org/:repo/:schedule", updateSchedule) + e.DELETE("/api/v1/schedules/:org/:repo/:schedule", removeSchedule) + // mock endpoints for authentication calls e.GET("/token-refresh", getTokenRefresh) e.GET("/authenticate", getAuthenticate) diff --git a/router/middleware/allowlist_schedule.go b/router/middleware/allowlist_schedule.go new file mode 100644 index 000000000..8872d0361 --- /dev/null +++ b/router/middleware/allowlist_schedule.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +// AllowlistSchedule is a middleware function that attaches the allowlistschedule used +// to limit which repos can utilize the schedule feature within the system. +func AllowlistSchedule(allowlistschedule []string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("allowlistschedule", allowlistschedule) + c.Next() + } +} diff --git a/router/middleware/allowlist_schedule_test.go b/router/middleware/allowlist_schedule_test.go new file mode 100644 index 000000000..a9b03ae28 --- /dev/null +++ b/router/middleware/allowlist_schedule_test.go @@ -0,0 +1,46 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/gin-gonic/gin" +) + +func TestMiddleware_AllowlistSchedule(t *testing.T) { + // setup types + got := []string{""} + want := []string{"foobar"} + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil) + + // setup mock server + engine.Use(AllowlistSchedule(want)) + engine.GET("/health", func(c *gin.Context) { + got = c.Value("allowlistschedule").([]string) + + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("AllowlistSchedule returned %v, want %v", resp.Code, http.StatusOK) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("AllowlistSchedule is %v, want %v", got, want) + } +} diff --git a/router/middleware/schedule/context.go b/router/middleware/schedule/context.go new file mode 100644 index 000000000..7ce62871c --- /dev/null +++ b/router/middleware/schedule/context.go @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "context" + + "github.com/go-vela/types/library" +) + +const key = "schedule" + +// Setter defines a context that enables setting values. +type Setter interface { + Set(string, interface{}) +} + +// FromContext returns the Schedule associated with this context. +func FromContext(c context.Context) *library.Schedule { + value := c.Value(key) + if value == nil { + return nil + } + + s, ok := value.(*library.Schedule) + if !ok { + return nil + } + + return s +} + +// ToContext adds the Schedule to this context if it supports +// the Setter interface. +func ToContext(c Setter, s *library.Schedule) { + c.Set(key, s) +} diff --git a/router/middleware/schedule/context_test.go b/router/middleware/schedule/context_test.go new file mode 100644 index 000000000..fb73d0b32 --- /dev/null +++ b/router/middleware/schedule/context_test.go @@ -0,0 +1,89 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "testing" + + "github.com/gin-gonic/gin" + "github.com/go-vela/types/library" +) + +func TestSchedule_FromContext(t *testing.T) { + // setup types + num := int64(1) + want := &library.Schedule{ID: &num} + + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, want) + + // run test + got := FromContext(context) + + if got != want { + t.Errorf("FromContext is %v, want %v", got, want) + } +} + +func TestSchedule_FromContext_Bad(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, nil) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestSchedule_FromContext_WrongType(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + context.Set(key, 1) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestSchedule_FromContext_Empty(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + + // run test + got := FromContext(context) + + if got != nil { + t.Errorf("FromContext is %v, want nil", got) + } +} + +func TestSchedule_ToContext(t *testing.T) { + // setup types + num := int64(1) + want := &library.Schedule{ID: &num} + + // setup context + gin.SetMode(gin.TestMode) + context, _ := gin.CreateTestContext(nil) + ToContext(context, want) + + // run test + got := context.Value(key) + + if got != want { + t.Errorf("ToContext is %v, want %v", got, want) + } +} diff --git a/router/middleware/schedule/schedule.go b/router/middleware/schedule/schedule.go new file mode 100644 index 000000000..de06e0651 --- /dev/null +++ b/router/middleware/schedule/schedule.go @@ -0,0 +1,59 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package schedule + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "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" + "github.com/sirupsen/logrus" +) + +// Retrieve gets the schedule in the given context. +func Retrieve(c *gin.Context) *library.Schedule { + return FromContext(c) +} + +// Establish sets the schedule in the given context. +func Establish() gin.HandlerFunc { + return func(c *gin.Context) { + r := repo.Retrieve(c) + u := user.Retrieve(c) + + sParam := util.PathParameter(c, "schedule") + if len(sParam) == 0 { + retErr := fmt.Errorf("no schedule parameter provided") + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "user": u.GetName(), + }).Debugf("reading schedule %s for repo %s", sParam, r.GetFullName()) + + s, err := database.FromContext(c).GetScheduleForRepo(r, sParam) + if err != nil { + retErr := fmt.Errorf("unable to read schedule %s for repo %s: %w", sParam, r.GetFullName(), err) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + ToContext(c, s) + c.Next() + } +} diff --git a/router/middleware/schedule_frequency.go b/router/middleware/schedule_frequency.go new file mode 100644 index 000000000..243c2ad06 --- /dev/null +++ b/router/middleware/schedule_frequency.go @@ -0,0 +1,20 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "time" + + "github.com/gin-gonic/gin" +) + +// ScheduleFrequency is a middleware function that attaches the scheduleminimumfrequency used +// to limit the frequency which schedules can be run within the system. +func ScheduleFrequency(scheduleFrequency time.Duration) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("scheduleminimumfrequency", scheduleFrequency) + c.Next() + } +} diff --git a/router/middleware/schedule_frequency_test.go b/router/middleware/schedule_frequency_test.go new file mode 100644 index 000000000..171f96ad3 --- /dev/null +++ b/router/middleware/schedule_frequency_test.go @@ -0,0 +1,47 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/gin-gonic/gin" +) + +func TestMiddleware_ScheduleFrequency(t *testing.T) { + // setup types + var got time.Duration + want := 30 * time.Minute + + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + context, engine := gin.CreateTestContext(resp) + context.Request, _ = http.NewRequest(http.MethodGet, "/health", nil) + + // setup mock server + engine.Use(ScheduleFrequency(want)) + engine.GET("/health", func(c *gin.Context) { + got = c.Value("scheduleminimumfrequency").(time.Duration) + + c.Status(http.StatusOK) + }) + + // run test + engine.ServeHTTP(context.Writer, context.Request) + + if resp.Code != http.StatusOK { + t.Errorf("ScheduleFrequency returned %v, want %v", resp.Code, http.StatusOK) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("ScheduleFrequency is %v, want %v", got, want) + } +} diff --git a/router/router.go b/router/router.go index f9d1f7b24..d1e88273a 100644 --- a/router/router.go +++ b/router/router.go @@ -115,6 +115,9 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // * Log endpoints RepoHandlers(baseAPI) + // Schedule endpoints + ScheduleHandler(baseAPI) + // Source code management endpoints ScmHandlers(baseAPI) @@ -132,6 +135,7 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // Pipeline endpoints PipelineHandlers(baseAPI) + } // end of api return r diff --git a/router/schedule.go b/router/schedule.go new file mode 100644 index 000000000..7c73e30c2 --- /dev/null +++ b/router/schedule.go @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package router + +import ( + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api/schedule" + "github.com/go-vela/server/router/middleware" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/perm" + "github.com/go-vela/server/router/middleware/repo" + sMiddleware "github.com/go-vela/server/router/middleware/schedule" +) + +// ScheduleHandler is a function that extends the provided base router group +// with the API handlers for schedule functionality. +// +// POST /api/v1/schedules/:org/:repo +// GET /api/v1/schedules/:org/:repo +// GET /api/v1/schedules/:org/:repo/:schedule +// PUT /api/v1/schedules/:org/:repo/:schedule +// DELETE /api/v1/schedules/:org/:repo/:schedule . +func ScheduleHandler(base *gin.RouterGroup) { + // Schedules endpoints + _schedules := base.Group("/schedules/:org/:repo", org.Establish(), repo.Establish()) + { + _schedules.POST("", perm.MustAdmin(), middleware.Payload(), schedule.CreateSchedule) + _schedules.GET("", perm.MustRead(), schedule.ListSchedules) + + s := _schedules.Group("/:schedule", sMiddleware.Establish()) + { + s.GET("", perm.MustRead(), schedule.GetSchedule) + s.PUT("", perm.MustAdmin(), middleware.Payload(), schedule.UpdateSchedule) + s.DELETE("", perm.MustAdmin(), schedule.DeleteSchedule) + } + } // end of schedules endpoints +} diff --git a/util/util.go b/util/util.go index 59b08121f..849ffdd95 100644 --- a/util/util.go +++ b/util/util.go @@ -8,6 +8,8 @@ import ( "html" "strings" + "github.com/go-vela/types/library" + "github.com/gin-gonic/gin" "github.com/go-vela/types" ) @@ -70,3 +72,30 @@ func EscapeValue(value string) string { // HTML escape the new line escaped value return html.EscapeString(escaped) } + +// CheckAllowlist is a helper function to ensure only repos in the +// allowlist are specified. +// +// a single entry of '*' allows any repo to be enabled. +func CheckAllowlist(r *library.Repo, allowlist []string) bool { + // check if all repos are allowed to be enabled + if len(allowlist) == 1 && allowlist[0] == "*" { + return true + } + + for _, repo := range allowlist { + // allow all repos in org + if strings.Contains(repo, "/*") { + if strings.HasPrefix(repo, r.GetOrg()) { + return true + } + } + + // allow specific repo within org + if repo == r.GetFullName() { + return true + } + } + + return false +} From a374e2b83bcac2f350f44e0308a8ba116ccb71d6 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 19 May 2023 15:51:34 -0600 Subject: [PATCH 237/298] refactor(api): move step logic to separate package (#851) * refactor(api): move step logic to separate package * get -> list --- api/build.go | 110 ++++++++ api/step.go | 644 --------------------------------------------- api/step/create.go | 128 +++++++++ api/step/delete.go | 96 +++++++ api/step/doc.go | 10 + api/step/get.go | 77 ++++++ api/step/list.go | 146 ++++++++++ api/step/update.go | 163 ++++++++++++ router/step.go | 20 +- 9 files changed, 740 insertions(+), 654 deletions(-) delete mode 100644 api/step.go create mode 100644 api/step/create.go create mode 100644 api/step/delete.go create mode 100644 api/step/doc.go create mode 100644 api/step/get.go create mode 100644 api/step/list.go create mode 100644 api/step/update.go diff --git a/api/build.go b/api/build.go index 8519a8e53..ce755027a 100644 --- a/api/build.go +++ b/api/build.go @@ -1677,6 +1677,116 @@ func planServices(database database.Interface, p *pipeline.Build, b *library.Bui return services, nil } +// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { + // variable to store planned steps + steps := []*library.Step{} + + // iterate through all pipeline stages + for _, stage := range p.Stages { + // iterate through all steps for each pipeline stage + for _, step := range stage.Steps { + // create the step object + s := new(library.Step) + s.SetBuildID(b.GetID()) + s.SetRepoID(b.GetRepoID()) + s.SetNumber(step.Number) + s.SetName(step.Name) + s.SetImage(step.Image) + s.SetStage(stage.Name) + s.SetStatus(constants.StatusPending) + s.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the step + err := database.CreateStep(s) + if err != nil { + return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) + } + + // send API call to capture the created step + s, err = database.GetStepForBuild(b, s.GetNumber()) + if err != nil { + return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) + } + + // populate environment variables from step library + // + // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment + err = step.MergeEnv(s.Environment()) + if err != nil { + return steps, err + } + + // create the log object + l := new(library.Log) + l.SetStepID(s.GetID()) + l.SetBuildID(b.GetID()) + l.SetRepoID(b.GetRepoID()) + l.SetData([]byte{}) + + // send API call to create the step logs + err = database.CreateLog(l) + if err != nil { + return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) + } + + steps = append(steps, s) + } + } + + // iterate through all pipeline steps + for _, step := range p.Steps { + // create the step object + s := new(library.Step) + s.SetBuildID(b.GetID()) + s.SetRepoID(b.GetRepoID()) + s.SetNumber(step.Number) + s.SetName(step.Name) + s.SetImage(step.Image) + s.SetStatus(constants.StatusPending) + s.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the step + err := database.CreateStep(s) + if err != nil { + return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) + } + + // send API call to capture the created step + s, err = database.GetStepForBuild(b, s.GetNumber()) + if err != nil { + return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) + } + + // populate environment variables from step library + // + // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment + err = step.MergeEnv(s.Environment()) + if err != nil { + return steps, err + } + + // create the log object + l := new(library.Log) + l.SetStepID(s.GetID()) + l.SetBuildID(b.GetID()) + l.SetRepoID(b.GetRepoID()) + l.SetData([]byte{}) + + // send API call to create the step logs + err = database.CreateLog(l) + if err != nil { + return steps, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) + } + + steps = append(steps, s) + } + + return steps, nil +} + // cleanBuild is a helper function to kill the build // without execution. This will kill all resources, // like steps and services, for the build in the diff --git a/api/step.go b/api/step.go deleted file mode 100644 index aab74067b..000000000 --- a/api/step.go +++ /dev/null @@ -1,644 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/build" - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/step" - "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" - "github.com/go-vela/types/pipeline" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps steps CreateStep -// -// Create a step for a build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the step to create -// required: true -// schema: -// "$ref": "#/definitions/Step" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the step -// schema: -// "$ref": "#/definitions/Step" -// '400': -// description: Unable to create the step -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the step -// schema: -// "$ref": "#/definitions/Error" - -// CreateStep represents the API handler to create -// a step for a build in the configured backend. -func CreateStep(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("creating new step for build %s", entry) - - // capture body from API request - input := new(library.Step) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new step for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in step object - input.SetRepoID(r.GetID()) - input.SetBuildID(b.GetID()) - - if len(input.GetStatus()) == 0 { - input.SetStatus(constants.StatusPending) - } - - if input.GetCreated() == 0 { - input.SetCreated(time.Now().UTC().Unix()) - } - - // send API call to create the step - err = database.FromContext(c).CreateStep(input) - if err != nil { - retErr := fmt.Errorf("unable to create step for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created step - s, _ := database.FromContext(c).GetStepForBuild(b, input.GetNumber()) - - c.JSON(http.StatusCreated, s) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps steps GetSteps -// -// Retrieve a list of steps for a build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the list of steps -// schema: -// type: array -// items: -// "$ref": "#/definitions/Step" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of steps -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of steps -// schema: -// "$ref": "#/definitions/Error" - -// GetSteps represents the API handler to capture a list -// of steps for a build from the configured backend. -func GetSteps(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading steps for build %s", entry) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of steps for the build - s, t, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get steps for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, s) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps GetStep -// -// Retrieve a step for a build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the step -// schema: -// "$ref": "#/definitions/Step" - -// GetStep represents the API handler to capture a -// step for a build from the configured backend. -func GetStep(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("reading step %s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - c.JSON(http.StatusOK, s) -} - -// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps UpdateStep -// -// Update a step for a build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the step to update -// required: true -// schema: -// "$ref": "#/definitions/Step" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the step -// schema: -// "$ref": "#/definitions/Step" -// '400': -// description: Unable to update the step -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the step -// schema: -// "$ref": "#/definitions/Error" - -// UpdateStep represents the API handler to update -// a step for a build in the configured backend. -func UpdateStep(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("updating step %s", entry) - - // capture body from API request - input := new(library.Step) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update step fields if provided - if len(input.GetStatus()) > 0 { - // update status if set - s.SetStatus(input.GetStatus()) - } - - if len(input.GetError()) > 0 { - // update error if set - s.SetError(input.GetError()) - } - - if input.GetExitCode() > 0 { - // update exit_code if set - s.SetExitCode(input.GetExitCode()) - } - - if input.GetStarted() > 0 { - // update started if set - s.SetStarted(input.GetStarted()) - } - - if input.GetFinished() > 0 { - // update finished if set - s.SetFinished(input.GetFinished()) - } - - if len(input.GetHost()) > 0 { - // update host if set - s.SetHost(input.GetHost()) - } - - if len(input.GetRuntime()) > 0 { - // update runtime if set - s.SetRuntime(input.GetRuntime()) - } - - if len(input.GetDistribution()) > 0 { - // update distribution if set - s.SetDistribution(input.GetDistribution()) - } - - // send API call to update the step - err = database.FromContext(c).UpdateStep(s) - if err != nil { - retErr := fmt.Errorf("unable to update step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated step - s, _ = database.FromContext(c).GetStepForBuild(b, s.GetNumber()) - - c.JSON(http.StatusOK, s) -} - -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps DeleteStep -// -// Delete a step for a build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the step -// schema: -// type: string -// '500': -// description: Successfully deleted the step -// schema: -// "$ref": "#/definitions/Error" - -// DeleteStep represents the API handler to remove -// a step for a build from the configured backend. -func DeleteStep(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("deleting step %s", entry) - - // send API call to remove the step - err := database.FromContext(c).DeleteStep(s) - if err != nil { - retErr := fmt.Errorf("unable to delete step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("step %s deleted", entry)) -} - -// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { - // variable to store planned steps - steps := []*library.Step{} - - // iterate through all pipeline stages - for _, stage := range p.Stages { - // iterate through all steps for each pipeline stage - for _, step := range stage.Steps { - // create the step object - s := new(library.Step) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetNumber(step.Number) - s.SetName(step.Name) - s.SetImage(step.Image) - s.SetStage(stage.Name) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the step - err := database.CreateStep(s) - if err != nil { - return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) - } - - // send API call to capture the created step - s, err = database.GetStepForBuild(b, s.GetNumber()) - if err != nil { - return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) - } - - // populate environment variables from step library - // - // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment - err = step.MergeEnv(s.Environment()) - if err != nil { - return steps, err - } - - // create the log object - l := new(library.Log) - l.SetStepID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the step logs - err = database.CreateLog(l) - if err != nil { - return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) - } - - steps = append(steps, s) - } - } - - // iterate through all pipeline steps - for _, step := range p.Steps { - // create the step object - s := new(library.Step) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetNumber(step.Number) - s.SetName(step.Name) - s.SetImage(step.Image) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the step - err := database.CreateStep(s) - if err != nil { - return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) - } - - // send API call to capture the created step - s, err = database.GetStepForBuild(b, s.GetNumber()) - if err != nil { - return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) - } - - // populate environment variables from step library - // - // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment - err = step.MergeEnv(s.Environment()) - if err != nil { - return steps, err - } - - // create the log object - l := new(library.Log) - l.SetStepID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the step logs - err = database.CreateLog(l) - if err != nil { - return steps, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) - } - - steps = append(steps, s) - } - - return steps, nil -} diff --git a/api/step/create.go b/api/step/create.go new file mode 100644 index 000000000..d87bfaae0 --- /dev/null +++ b/api/step/create.go @@ -0,0 +1,128 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps steps CreateStep +// +// Create a step for a build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the step to create +// required: true +// schema: +// "$ref": "#/definitions/Step" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the step +// schema: +// "$ref": "#/definitions/Step" +// '400': +// description: Unable to create the step +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the step +// schema: +// "$ref": "#/definitions/Error" + +// CreateStep represents the API handler to create +// a step for a build in the configured backend. +func CreateStep(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("creating new step for build %s", entry) + + // capture body from API request + input := new(library.Step) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new step for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in step object + input.SetRepoID(r.GetID()) + input.SetBuildID(b.GetID()) + + if len(input.GetStatus()) == 0 { + input.SetStatus(constants.StatusPending) + } + + if input.GetCreated() == 0 { + input.SetCreated(time.Now().UTC().Unix()) + } + + // send API call to create the step + err = database.FromContext(c).CreateStep(input) + if err != nil { + retErr := fmt.Errorf("unable to create step for build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created step + s, _ := database.FromContext(c).GetStepForBuild(b, input.GetNumber()) + + c.JSON(http.StatusCreated, s) +} diff --git a/api/step/delete.go b/api/step/delete.go new file mode 100644 index 000000000..1a43c30b3 --- /dev/null +++ b/api/step/delete.go @@ -0,0 +1,96 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps DeleteStep +// +// Delete a step for a build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the step +// schema: +// type: string +// '500': +// description: Successfully deleted the step +// schema: +// "$ref": "#/definitions/Error" + +// DeleteStep represents the API handler to remove +// a step for a build from the configured backend. +func DeleteStep(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("deleting step %s", entry) + + // send API call to remove the step + err := database.FromContext(c).DeleteStep(s) + if err != nil { + retErr := fmt.Errorf("unable to delete step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("step %s deleted", entry)) +} diff --git a/api/step/doc.go b/api/step/doc.go new file mode 100644 index 000000000..fad7dce79 --- /dev/null +++ b/api/step/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package step provides the step handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/step" +package step diff --git a/api/step/get.go b/api/step/get.go new file mode 100644 index 000000000..cf55c1bb5 --- /dev/null +++ b/api/step/get.go @@ -0,0 +1,77 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps GetStep +// +// Retrieve a step for a build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the step +// schema: +// "$ref": "#/definitions/Step" + +// GetStep represents the API handler to capture a +// step for a build from the configured backend. +func GetStep(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("reading step %s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + c.JSON(http.StatusOK, s) +} diff --git a/api/step/list.go b/api/step/list.go new file mode 100644 index 000000000..5d76fb33c --- /dev/null +++ b/api/step/list.go @@ -0,0 +1,146 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps steps ListSteps +// +// Retrieve a list of steps for a build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the list of steps +// schema: +// type: array +// items: +// "$ref": "#/definitions/Step" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of steps +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of steps +// schema: +// "$ref": "#/definitions/Error" + +// ListSteps represents the API handler to capture a list +// of steps for a build from the configured backend. +func ListSteps(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("listing steps for build %s", entry) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of steps for the build + s, t, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to list steps for build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, s) +} diff --git a/api/step/update.go b/api/step/update.go new file mode 100644 index 000000000..8a64fbb12 --- /dev/null +++ b/api/step/update.go @@ -0,0 +1,163 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step} steps UpdateStep +// +// Update a step for a build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the step to update +// required: true +// schema: +// "$ref": "#/definitions/Step" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the step +// schema: +// "$ref": "#/definitions/Step" +// '400': +// description: Unable to update the step +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the step +// schema: +// "$ref": "#/definitions/Error" + +// UpdateStep represents the API handler to update +// a step for a build in the configured backend. +func UpdateStep(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("updating step %s", entry) + + // capture body from API request + input := new(library.Step) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update step fields if provided + if len(input.GetStatus()) > 0 { + // update status if set + s.SetStatus(input.GetStatus()) + } + + if len(input.GetError()) > 0 { + // update error if set + s.SetError(input.GetError()) + } + + if input.GetExitCode() > 0 { + // update exit_code if set + s.SetExitCode(input.GetExitCode()) + } + + if input.GetStarted() > 0 { + // update started if set + s.SetStarted(input.GetStarted()) + } + + if input.GetFinished() > 0 { + // update finished if set + s.SetFinished(input.GetFinished()) + } + + if len(input.GetHost()) > 0 { + // update host if set + s.SetHost(input.GetHost()) + } + + if len(input.GetRuntime()) > 0 { + // update runtime if set + s.SetRuntime(input.GetRuntime()) + } + + if len(input.GetDistribution()) > 0 { + // update distribution if set + s.SetDistribution(input.GetDistribution()) + } + + // send API call to update the step + err = database.FromContext(c).UpdateStep(s) + if err != nil { + retErr := fmt.Errorf("unable to update step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated step + s, _ = database.FromContext(c).GetStepForBuild(b, s.GetNumber()) + + c.JSON(http.StatusOK, s) +} diff --git a/router/step.go b/router/step.go index 82719ddf7..9a53e4e97 100644 --- a/router/step.go +++ b/router/step.go @@ -7,10 +7,10 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/step" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/perm" - "github.com/go-vela/server/router/middleware/step" + smiddleware "github.com/go-vela/server/router/middleware/step" ) // StepHandlers is a function that extends the provided base router group @@ -24,23 +24,23 @@ import ( // POST /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs // GET /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs // PUT /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs -// DELETE /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs +// DELETE /api/v1/repos/:org/:repo/builds/:build/steps/:step/logs . func StepHandlers(base *gin.RouterGroup) { // Steps endpoints steps := base.Group("/steps") { - steps.POST("", perm.MustPlatformAdmin(), middleware.Payload(), api.CreateStep) - steps.GET("", perm.MustRead(), api.GetSteps) + steps.POST("", perm.MustPlatformAdmin(), middleware.Payload(), step.CreateStep) + steps.GET("", perm.MustRead(), step.ListSteps) // Step endpoints - step := steps.Group("/:step", step.Establish()) + s := steps.Group("/:step", smiddleware.Establish()) { - step.GET("", perm.MustRead(), api.GetStep) - step.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateStep) - step.DELETE("", perm.MustPlatformAdmin(), api.DeleteStep) + s.GET("", perm.MustRead(), step.GetStep) + s.PUT("", perm.MustBuildAccess(), middleware.Payload(), step.UpdateStep) + s.DELETE("", perm.MustPlatformAdmin(), step.DeleteStep) // Log endpoints - LogStepHandlers(step) + LogStepHandlers(s) } // end of step endpoints } // end of steps endpoints } From 1884ca00af1c52452991d33f0aab467690fabbc1 Mon Sep 17 00:00:00 2001 From: Jacob Floyd Date: Mon, 22 May 2023 09:48:13 -0500 Subject: [PATCH 238/298] refactor(api): move auth logic to separate package (#853) * add api/auth package * move api/login.go -> api/auth/login.go * move api/logout.go -> api/auth/logout.go * move api/token.go -> api/auth/token.go * move api/authenticate.go -> api/auth/authenticate.go * move api/auth/get * minimize * move api/auth/redirect * minimize * move api/auth/post_token * minimize * move api/auth/refresh * minimize * move api/auth/validate * minimize * update copyright * rename some auth/api funcs for clarity * Update api/auth/validate.go Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- api/auth/doc.go | 10 + api/auth/get_token.go | 168 +++++++++++++++ api/{ => auth}/login.go | 4 +- api/{ => auth}/logout.go | 4 +- api/auth/post_token.go | 92 +++++++++ api/auth/redirect.go | 102 +++++++++ api/{token.go => auth/refresh.go} | 45 +--- api/auth/validate.go | 50 +++++ api/authenticate.go | 332 ------------------------------ router/router.go | 20 +- 10 files changed, 439 insertions(+), 388 deletions(-) create mode 100644 api/auth/doc.go create mode 100644 api/auth/get_token.go rename api/{ => auth}/login.go (96%) rename api/{ => auth}/logout.go (96%) create mode 100644 api/auth/post_token.go create mode 100644 api/auth/redirect.go rename api/{token.go => auth/refresh.go} (62%) create mode 100644 api/auth/validate.go delete mode 100644 api/authenticate.go diff --git a/api/auth/doc.go b/api/auth/doc.go new file mode 100644 index 000000000..c200b5faf --- /dev/null +++ b/api/auth/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package auth provides the auth handlers (authenticate, login, ...) for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/auth" +package auth diff --git a/api/auth/get_token.go b/api/auth/get_token.go new file mode 100644 index 000000000..29829f072 --- /dev/null +++ b/api/auth/get_token.go @@ -0,0 +1,168 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" +) + +// swagger:operation GET /authenticate authenticate GetAuthToken +// +// Start OAuth flow or exchange tokens +// +// --- +// produces: +// - application/json +// parameters: +// - in: query +// name: code +// description: the code received after identity confirmation +// type: string +// - in: query +// name: state +// description: a random string +// type: string +// - in: query +// name: redirect_uri +// description: the url where the user will be sent after authorization +// type: string +// responses: +// '200': +// description: Successfully authenticated +// headers: +// Set-Cookie: +// type: string +// schema: +// "$ref": "#/definitions/Token" +// '307': +// description: Redirected for authentication +// '401': +// description: Unable to authenticate +// schema: +// "$ref": "#/definitions/Error" +// '503': +// description: Service unavailable +// schema: +// "$ref": "#/definitions/Error" + +// GetAuthToken represents the API handler to +// process a user logging in to Vela from +// the API or UI. +func GetAuthToken(c *gin.Context) { + var err error + + tm := c.MustGet("token-manager").(*token.Manager) + + // capture the OAuth state if present + oAuthState := c.Request.FormValue("state") + + // capture the OAuth code if present + code := c.Request.FormValue("code") + if len(code) == 0 { + // start the initial OAuth workflow + oAuthState, err = scm.FromContext(c).Login(c.Writer, c.Request) + if err != nil { + retErr := fmt.Errorf("unable to login user: %w", err) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + } + + // complete the OAuth workflow and authenticates the user + newUser, err := scm.FromContext(c).Authenticate(c.Writer, c.Request, oAuthState) + if err != nil { + retErr := fmt.Errorf("unable to authenticate user: %w", err) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + // this will happen if the user is redirected by the + // source provider as part of the authorization workflow. + if newUser == nil { + return + } + + // send API call to capture the user logging in + u, err := database.FromContext(c).GetUserForName(newUser.GetName()) + // create a new user account + if len(u.GetName()) == 0 || err != nil { + // create the user account + u := new(library.User) + u.SetName(newUser.GetName()) + u.SetToken(newUser.GetToken()) + u.SetActive(true) + u.SetAdmin(false) + + // compose jwt tokens for user + rt, at, err := tm.Compose(c, u) + if err != nil { + retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + // store the refresh token with the user object + u.SetRefreshToken(rt) + + // send API call to create the user in the database + err = database.FromContext(c).CreateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to create user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + // return the jwt access token + c.JSON(http.StatusOK, library.Token{Token: &at}) + + return + } + + // update the user account + u.SetToken(newUser.GetToken()) + u.SetActive(true) + + // compose jwt tokens for user + rt, at, err := tm.Compose(c, u) + if err != nil { + retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + // store the refresh token with the user object + u.SetRefreshToken(rt) + + // send API call to update the user in the database + err = database.FromContext(c).UpdateUser(u) + if err != nil { + retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + + return + } + + // return the user with their jwt access token + c.JSON(http.StatusOK, library.Token{Token: &at}) +} diff --git a/api/login.go b/api/auth/login.go similarity index 96% rename from api/login.go rename to api/auth/login.go index 74ac91226..36b977009 100644 --- a/api/login.go +++ b/api/auth/login.go @@ -1,8 +1,8 @@ -// 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. -package api +package auth import ( "fmt" diff --git a/api/logout.go b/api/auth/logout.go similarity index 96% rename from api/logout.go rename to api/auth/logout.go index 5d5d39556..8accdf42e 100644 --- a/api/logout.go +++ b/api/auth/logout.go @@ -1,8 +1,8 @@ -// 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. -package api +package auth import ( "fmt" diff --git a/api/auth/post_token.go b/api/auth/post_token.go new file mode 100644 index 000000000..8b386bfcf --- /dev/null +++ b/api/auth/post_token.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "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 POST /authenticate/token authenticate PostAuthToken +// +// Authenticate to Vela via personal access token +// +// --- +// produces: +// - application/json +// parameters: +// - in: header +// name: Token +// type: string +// required: true +// description: > +// scopes: repo, repo:status, user:email, read:user, and read:org +// responses: +// '200': +// description: Successfully authenticated +// schema: +// "$ref": "#/definitions/Token" +// '401': +// description: Unable to authenticate +// schema: +// "$ref": "#/definitions/Error" +// '503': +// description: Service unavailable +// schema: +// "$ref": "#/definitions/Error" + +// PostAuthToken represents the API handler to +// process a user logging in using PAT to Vela from +// the API. +func PostAuthToken(c *gin.Context) { + // attempt to get user from source + u, err := scm.FromContext(c).AuthenticateToken(c.Request) + if err != nil { + retErr := fmt.Errorf("unable to authenticate user: %w", err) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + // check if the user exists + u, err = database.FromContext(c).GetUserForName(u.GetName()) + if err != nil { + retErr := fmt.Errorf("user %s not found", u.GetName()) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + // We don't need refresh token for this scenario + // We only need access token and are configured based on the config defined + tm := c.MustGet("token-manager").(*token.Manager) + + // mint token options for access token + amto := &token.MintTokenOpts{ + User: u, + TokenType: constants.UserAccessTokenType, + TokenDuration: tm.UserAccessTokenDuration, + } + at, err := tm.MintToken(amto) + + if err != nil { + retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) + + util.HandleError(c, http.StatusServiceUnavailable, retErr) + } + + // return the user with their jwt access token + c.JSON(http.StatusOK, library.Token{Token: &at}) +} diff --git a/api/auth/redirect.go b/api/auth/redirect.go new file mode 100644 index 000000000..32b486393 --- /dev/null +++ b/api/auth/redirect.go @@ -0,0 +1,102 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/util" + "github.com/go-vela/types" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /authenticate/web authenticate GetAuthenticateTypeWeb +// +// Authentication entrypoint that builds the right post-auth +// redirect URL for web authentication requests +// and redirects to /authenticate after +// +// --- +// produces: +// - application/json +// parameters: +// - in: query +// name: code +// description: the code received after identity confirmation +// type: string +// - in: query +// name: state +// description: a random string +// type: string +// responses: +// '307': +// description: Redirected for authentication + +// swagger:operation GET /authenticate/cli/{port} authenticate GetAuthenticateTypeCLI +// +// Authentication entrypoint that builds the right post-auth +// redirect URL for CLI authentication requests +// and redirects to /authenticate after +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: port +// required: true +// description: the port number +// type: integer +// - in: query +// name: code +// description: the code received after identity confirmation +// type: string +// - in: query +// name: state +// description: a random string +// type: string +// responses: +// '307': +// description: Redirected for authentication + +// GetAuthRedirect handles cases where the OAuth callback was +// overridden by supplying a redirect_uri in the login process. +// It will send the user to the destination to handle the last leg +// in the auth flow - exchanging "code" and "state" for a token. +// This will only handle non-headless flows (ie. web or cli). +func GetAuthRedirect(c *gin.Context) { + // load the metadata + m := c.MustGet("metadata").(*types.Metadata) + + logrus.Info("redirecting for final auth flow destination") + + // capture the path elements + t := util.PathParameter(c, "type") + p := util.PathParameter(c, "port") + + // capture the current query parameters - + // they should contain the "code" and "state" values + q := c.Request.URL.Query() + + // default redirect location if a user ended up here + // by providing an unsupported type + r := fmt.Sprintf("%s/authenticate", m.Vela.Address) + + switch t { + // cli auth flow + case "cli": + r = fmt.Sprintf("http://127.0.0.1:%s", p) + // web auth flow + case "web": + r = fmt.Sprintf("%s%s", m.Vela.WebAddress, m.Vela.WebOauthCallbackPath) + } + + // append the code and state values + r = fmt.Sprintf("%s?%s", r, q.Encode()) + + c.Redirect(http.StatusTemporaryRedirect, r) +} diff --git a/api/token.go b/api/auth/refresh.go similarity index 62% rename from api/token.go rename to api/auth/refresh.go index 6c76439ec..0c12425cc 100644 --- a/api/token.go +++ b/api/auth/refresh.go @@ -1,22 +1,18 @@ -// 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. -package api +package auth import ( "fmt" "net/http" - "strings" + "github.com/gin-gonic/gin" "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/auth" - "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" ) // swagger:operation GET /token-refresh authenticate GetRefreshAccessToken @@ -67,38 +63,3 @@ func RefreshAccessToken(c *gin.Context) { c.JSON(http.StatusOK, library.Token{Token: &newAccessToken}) } - -// swagger:operation GET /validate-token authenticate ValidateServerToken -// -// Validate a server token -// -// --- -// produces: -// - application/json -// security: -// - CookieAuth: [] -// responses: -// '200': -// description: Successfully validated a token -// schema: -// type: string -// '401': -// description: Unauthorized -// schema: -// "$ref": "#/definitions/Error" - -// ValidateServerToken will return the claims of a valid server token -// if it is provided in the auth header. -func ValidateServerToken(c *gin.Context) { - cl := claims.Retrieve(c) - - if !strings.EqualFold(cl.Subject, "vela-server") { - retErr := fmt.Errorf("token is not a valid server token") - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - c.JSON(http.StatusOK, "valid server token") -} diff --git a/api/auth/validate.go b/api/auth/validate.go new file mode 100644 index 000000000..d78057193 --- /dev/null +++ b/api/auth/validate.go @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package auth + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/util" +) + +// swagger:operation GET /validate-token authenticate ValidateServerToken +// +// Validate a server token +// +// --- +// produces: +// - application/json +// security: +// - CookieAuth: [] +// responses: +// '200': +// description: Successfully validated a token +// schema: +// type: string +// '401': +// description: Unauthorized +// schema: +// "$ref": "#/definitions/Error" + +// ValidateServerToken will validate if a token was issued by the server +// if it is provided in the auth header. +func ValidateServerToken(c *gin.Context) { + cl := claims.Retrieve(c) + + if !strings.EqualFold(cl.Subject, "vela-server") { + retErr := fmt.Errorf("token is not a valid server token") + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + c.JSON(http.StatusOK, "valid server token") +} diff --git a/api/authenticate.go b/api/authenticate.go deleted file mode 100644 index 6d89d7611..000000000 --- a/api/authenticate.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/server/internal/token" - "github.com/go-vela/server/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// swagger:operation GET /authenticate authenticate GetAuthenticate -// -// Start OAuth flow or exchange tokens -// -// --- -// produces: -// - application/json -// parameters: -// - in: query -// name: code -// description: the code received after identity confirmation -// type: string -// - in: query -// name: state -// description: a random string -// type: string -// - in: query -// name: redirect_uri -// description: the url where the user will be sent after authorization -// type: string -// responses: -// '200': -// description: Successfully authenticated -// headers: -// Set-Cookie: -// type: string -// schema: -// "$ref": "#/definitions/Token" -// '307': -// description: Redirected for authentication -// '401': -// description: Unable to authenticate -// schema: -// "$ref": "#/definitions/Error" -// '503': -// description: Service unavailable -// schema: -// "$ref": "#/definitions/Error" - -// Authenticate represents the API handler to -// process a user logging in to Vela from -// the API or UI. -func Authenticate(c *gin.Context) { - var err error - - tm := c.MustGet("token-manager").(*token.Manager) - - // capture the OAuth state if present - oAuthState := c.Request.FormValue("state") - - // capture the OAuth code if present - code := c.Request.FormValue("code") - if len(code) == 0 { - // start the initial OAuth workflow - oAuthState, err = scm.FromContext(c).Login(c.Writer, c.Request) - if err != nil { - retErr := fmt.Errorf("unable to login user: %w", err) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - } - - // complete the OAuth workflow and authenticates the user - newUser, err := scm.FromContext(c).Authenticate(c.Writer, c.Request, oAuthState) - if err != nil { - retErr := fmt.Errorf("unable to authenticate user: %w", err) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - // this will happen if the user is redirected by the - // source provider as part of the authorization workflow. - if newUser == nil { - return - } - - // send API call to capture the user logging in - u, err := database.FromContext(c).GetUserForName(newUser.GetName()) - // create a new user account - if len(u.GetName()) == 0 || err != nil { - // create the user account - u := new(library.User) - u.SetName(newUser.GetName()) - u.SetToken(newUser.GetToken()) - u.SetActive(true) - u.SetAdmin(false) - - // compose jwt tokens for user - rt, at, err := tm.Compose(c, u) - if err != nil { - retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - // store the refresh token with the user object - u.SetRefreshToken(rt) - - // send API call to create the user in the database - err = database.FromContext(c).CreateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to create user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - // return the jwt access token - c.JSON(http.StatusOK, library.Token{Token: &at}) - - return - } - - // update the user account - u.SetToken(newUser.GetToken()) - u.SetActive(true) - - // compose jwt tokens for user - rt, at, err := tm.Compose(c, u) - if err != nil { - retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - // store the refresh token with the user object - u.SetRefreshToken(rt) - - // send API call to update the user in the database - err = database.FromContext(c).UpdateUser(u) - if err != nil { - retErr := fmt.Errorf("unable to update user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - - return - } - - // return the user with their jwt access token - c.JSON(http.StatusOK, library.Token{Token: &at}) -} - -// swagger:operation GET /authenticate/web authenticate GetAuthenticateTypeWeb -// -// Authentication entrypoint that builds the right post-auth -// redirect URL for web authentication requests -// and redirects to /authenticate after -// -// --- -// produces: -// - application/json -// parameters: -// - in: query -// name: code -// description: the code received after identity confirmation -// type: string -// - in: query -// name: state -// description: a random string -// type: string -// responses: -// '307': -// description: Redirected for authentication - -// swagger:operation GET /authenticate/cli/{port} authenticate GetAuthenticateTypeCLI -// -// Authentication entrypoint that builds the right post-auth -// redirect URL for CLI authentication requests -// and redirects to /authenticate after -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: port -// required: true -// description: the port number -// type: integer -// - in: query -// name: code -// description: the code received after identity confirmation -// type: string -// - in: query -// name: state -// description: a random string -// type: string -// responses: -// '307': -// description: Redirected for authentication - -// AuthenticateType handles cases where the OAuth callback was -// overridden by supplying a redirect_uri in the login process. -// It will send the user to the destination to handle the last leg -// in the auth flow - exchanging "code" and "state" for a token. -// This will only handle non-headless flows (ie. web or cli). -func AuthenticateType(c *gin.Context) { - // load the metadata - m := c.MustGet("metadata").(*types.Metadata) - - logrus.Info("redirecting for final auth flow destination") - - // capture the path elements - t := util.PathParameter(c, "type") - p := util.PathParameter(c, "port") - - // capture the current query parameters - - // they should contain the "code" and "state" values - q := c.Request.URL.Query() - - // default redirect location if a user ended up here - // by providing an unsupported type - r := fmt.Sprintf("%s/authenticate", m.Vela.Address) - - switch t { - // cli auth flow - case "cli": - r = fmt.Sprintf("http://127.0.0.1:%s", p) - // web auth flow - case "web": - r = fmt.Sprintf("%s%s", m.Vela.WebAddress, m.Vela.WebOauthCallbackPath) - } - - // append the code and state values - r = fmt.Sprintf("%s?%s", r, q.Encode()) - - c.Redirect(http.StatusTemporaryRedirect, r) -} - -// swagger:operation POST /authenticate/token authenticate PostAuthenticateToken -// -// Authenticate to Vela via personal access token -// -// --- -// produces: -// - application/json -// parameters: -// - in: header -// name: Token -// type: string -// required: true -// description: > -// scopes: repo, repo:status, user:email, read:user, and read:org -// responses: -// '200': -// description: Successfully authenticated -// schema: -// "$ref": "#/definitions/Token" -// '401': -// description: Unable to authenticate -// schema: -// "$ref": "#/definitions/Error" -// '503': -// description: Service unavailable -// schema: -// "$ref": "#/definitions/Error" - -// AuthenticateToken represents the API handler to -// process a user logging in using PAT to Vela from -// the API. -func AuthenticateToken(c *gin.Context) { - // attempt to get user from source - u, err := scm.FromContext(c).AuthenticateToken(c.Request) - if err != nil { - retErr := fmt.Errorf("unable to authenticate user: %w", err) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - // check if the user exists - u, err = database.FromContext(c).GetUserForName(u.GetName()) - if err != nil { - retErr := fmt.Errorf("user %s not found", u.GetName()) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - // We don't need refresh token for this scenario - // We only need access token and are configured based on the config defined - tm := c.MustGet("token-manager").(*token.Manager) - - // mint token options for access token - amto := &token.MintTokenOpts{ - User: u, - TokenType: constants.UserAccessTokenType, - TokenDuration: tm.UserAccessTokenDuration, - } - at, err := tm.MintToken(amto) - - if err != nil { - retErr := fmt.Errorf("unable to compose token for user %s: %w", u.GetName(), err) - - util.HandleError(c, http.StatusServiceUnavailable, retErr) - } - - // return the user with their jwt access token - c.JSON(http.StatusOK, library.Token{Token: &at}) -} diff --git a/router/router.go b/router/router.go index d1e88273a..f756f9f4e 100644 --- a/router/router.go +++ b/router/router.go @@ -32,14 +32,14 @@ package router import ( + "github.com/gin-gonic/gin" "github.com/go-vela/server/api" + "github.com/go-vela/server/api/auth" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/claims" "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/gin-gonic/gin" ) const ( @@ -66,19 +66,19 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { r.GET("/health", api.Health) // Login endpoint - r.GET("/login", api.Login) + r.GET("/login", auth.Login) // Logout endpoint - r.GET("/logout", user.Establish(), api.Logout) + r.GET("/logout", user.Establish(), auth.Logout) // Refresh Access Token endpoint - r.GET("/token-refresh", api.RefreshAccessToken) + r.GET("/token-refresh", auth.RefreshAccessToken) // Metric endpoint r.GET("/metrics", api.CustomMetrics, gin.WrapH(api.BaseMetrics())) // Validate Server Token endpoint - r.GET("/validate-token", claims.Establish(), api.ValidateServerToken) + r.GET("/validate-token", claims.Establish(), auth.ValidateServerToken) // Version endpoint r.GET("/version", api.Version) @@ -89,10 +89,10 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { // Authentication endpoints authenticate := r.Group("/authenticate") { - authenticate.GET("", api.Authenticate) - authenticate.GET("/:type", api.AuthenticateType) - authenticate.GET("/:type/:port", api.AuthenticateType) - authenticate.POST("/token", api.AuthenticateToken) + authenticate.GET("", auth.GetAuthToken) + authenticate.GET("/:type", auth.GetAuthRedirect) + authenticate.GET("/:type/:port", auth.GetAuthRedirect) + authenticate.POST("/token", auth.PostAuthToken) } // API endpoints From c1a661a626a20cd420b7166d47c638d8ca948dea Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 22 May 2023 09:07:31 -0600 Subject: [PATCH 239/298] refactor(api): move log logic into separate package (#855) * refactor(api): move log logic into separate package * service number, import alpha, listing over reading --- api/log.go | 925 -------------------------------------- api/log/create_service.go | 129 ++++++ api/log/create_step.go | 129 ++++++ api/log/delete_service.go | 107 +++++ api/log/delete_step.go | 107 +++++ api/log/doc.go | 10 + api/log/get_service.go | 97 ++++ api/log/get_step.go | 98 ++++ api/log/list_build.go | 134 ++++++ api/log/update_service.go | 140 ++++++ api/log/update_step.go | 140 ++++++ router/build.go | 3 +- router/log.go | 18 +- 13 files changed, 1102 insertions(+), 935 deletions(-) delete mode 100644 api/log.go create mode 100644 api/log/create_service.go create mode 100644 api/log/create_step.go create mode 100644 api/log/delete_service.go create mode 100644 api/log/delete_step.go create mode 100644 api/log/doc.go create mode 100644 api/log/get_service.go create mode 100644 api/log/get_step.go create mode 100644 api/log/list_build.go create mode 100644 api/log/update_service.go create mode 100644 api/log/update_step.go diff --git a/api/log.go b/api/log.go deleted file mode 100644 index 9cb02b0d9..000000000 --- a/api/log.go +++ /dev/null @@ -1,925 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - - "github.com/go-vela/server/database" - "github.com/go-vela/server/router/middleware/build" - "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/server/router/middleware/service" - "github.com/go-vela/server/router/middleware/step" - "github.com/go-vela/server/router/middleware/user" - "github.com/go-vela/server/util" - - "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/logs builds GetBuildLogs -// -// Get logs for a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved logs for the build -// schema: -// type: array -// items: -// "$ref": "#/definitions/Log" -// '500': -// description: Unable to retrieve logs for the build -// schema: -// "$ref": "#/definitions/Error" - -// GetBuildLogs represents the API handler to capture a -// list of logs for a build from the configured backend. -func GetBuildLogs(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading logs for build %s", entry) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of logs for the build - l, t, err := database.FromContext(c).ListLogsForBuild(b, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get logs for build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, l) -} - -// -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services CreateServiceLogs -// -// Create the logs for a service -// -// --- -// deprecated: true -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: ID of the service -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the log to create -// required: true -// schema: -// "$ref": "#/definitions/Log" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the service logs -// schema: -// "$ref": "#/definitions/Log" -// '400': -// description: Unable to create the service logs -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the service logs -// schema: -// "$ref": "#/definitions/Error" - -// CreateServiceLog represents the API handler to create -// the logs for a service in the configured backend. -// -//nolint:dupl // ignore similar code with step -func CreateServiceLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("creating logs for service %s", entry) - - // capture body from API request - input := new(library.Log) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in log object - input.SetServiceID(s.GetID()) - input.SetBuildID(b.GetID()) - input.SetRepoID(r.GetID()) - - // send API call to create the logs - err = database.FromContext(c).CreateLog(input) - if err != nil { - retErr := fmt.Errorf("unable to create logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created log - l, _ := database.FromContext(c).GetLogForService(s) - - c.JSON(http.StatusCreated, l) -} - -// -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services GetServiceLogs -// -// Retrieve the logs for a service -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: ID of the service -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the service logs -// schema: -// "$ref": "#/definitions/Log" -// '500': -// description: Unable to retrieve the service logs -// schema: -// "$ref": "#/definitions/Error" - -// GetServiceLog represents the API handler to capture -// the logs for a service from the configured backend. -func GetServiceLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("reading logs for service %s", entry) - - // send API call to capture the service logs - l, err := database.FromContext(c).GetLogForService(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, l) -} - -// -// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services UpdateServiceLog -// -// Update the logs for a service -// -// --- -// deprecated: true -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: ID of the service -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the log to update -// required: true -// schema: -// "$ref": "#/definitions/Log" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the service logs -// schema: -// "$ref": "#/definitions/Log" -// '400': -// description: Unable to updated the service logs -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to updates the service logs -// schema: -// "$ref": "#/definitions/Error" - -// UpdateServiceLog represents the API handler to update -// the logs for a service in the configured backend. -func UpdateServiceLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("updating logs for service %s", entry) - - // send API call to capture the service logs - l, err := database.FromContext(c).GetLogForService(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // capture body from API request - input := new(library.Log) - - err = c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update log fields if provided - if len(input.GetData()) > 0 { - // update data if set - l.SetData(input.GetData()) - } - - // send API call to update the log - err = database.FromContext(c).UpdateLog(l) - if err != nil { - retErr := fmt.Errorf("unable to update logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated log - l, _ = database.FromContext(c).GetLogForService(s) - - c.JSON(http.StatusOK, l) -} - -// -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services DeleteServiceLogs -// -// Delete the logs for a service -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: service -// description: ID of the service -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the service logs -// schema: -// type: string -// '500': -// description: Unable to delete the service logs -// schema: -// "$ref": "#/definitions/Error" - -// DeleteServiceLog represents the API handler to remove -// the logs for a service from the configured backend. -func DeleteServiceLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := service.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "service": s.GetNumber(), - "user": u.GetName(), - }).Infof("deleting logs for service %s", entry) - - // send API call to capture the service logs - l, err := database.FromContext(c).GetLogForService(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to remove the log - err = database.FromContext(c).DeleteLog(l) - if err != nil { - retErr := fmt.Errorf("unable to delete logs for service %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("logs deleted for service %s", entry)) -} - -// -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps CreateStepLog -// -// Create the logs for a step -// -// --- -// deprecated: true -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the log to create -// required: true -// schema: -// "$ref": "#/definitions/Log" -// security: -// - ApiKeyAuth: [] -// responses: -// '201': -// description: Successfully created the logs for step -// schema: -// "$ref": "#/definitions/Log" -// '400': -// description: Unable to create the logs for a step -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the logs for a step -// schema: -// "$ref": "#/definitions/Error" - -// CreateStepLog represents the API handler to create -// the logs for a step in the configured backend. -// -//nolint:dupl // ignore similar code with service -func CreateStepLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("creating logs for step %s", entry) - - // capture body from API request - input := new(library.Log) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in log object - input.SetStepID(s.GetID()) - input.SetBuildID(b.GetID()) - input.SetRepoID(r.GetID()) - - // send API call to create the logs - err = database.FromContext(c).CreateLog(input) - if err != nil { - retErr := fmt.Errorf("unable to create logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the created log - l, _ := database.FromContext(c).GetLogForStep(s) - - c.JSON(http.StatusCreated, l) -} - -// -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps GetStepLog -// -// Retrieve the logs for a step -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the logs for step -// type: json -// schema: -// "$ref": "#/definitions/Log" -// '500': -// description: Unable to retrieve the logs for a step -// schema: -// "$ref": "#/definitions/Error" - -// GetStepLog represents the API handler to capture -// the logs for a step from the configured backend. -func GetStepLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("reading logs for step %s", entry) - - // send API call to capture the step logs - l, err := database.FromContext(c).GetLogForStep(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, l) -} - -// -// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps UpdateStepLog -// -// Update the logs for a step -// -// --- -// deprecated: true -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the log to update -// required: true -// schema: -// "$ref": "#/definitions/Log" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the logs for step -// schema: -// "$ref": "#/definitions/Log" -// '400': -// description: Unable to update the logs for a step -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the logs for a step -// schema: -// "$ref": "#/definitions/Error" - -// UpdateStepLog represents the API handler to update -// the logs for a step in the configured backend. -func UpdateStepLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("updating logs for step %s", entry) - - // send API call to capture the step logs - l, err := database.FromContext(c).GetLogForStep(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // capture body from API request - input := new(library.Log) - - err = c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update log fields if provided - if len(input.GetData()) > 0 { - // update data if set - l.SetData(input.GetData()) - } - - // send API call to update the log - err = database.FromContext(c).UpdateLog(l) - if err != nil { - retErr := fmt.Errorf("unable to update logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated log - l, _ = database.FromContext(c).GetLogForStep(s) - - c.JSON(http.StatusOK, l) -} - -// -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps DeleteStepLog -// -// Delete the logs for a step -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// - in: path -// name: step -// description: Step number -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the logs for the step -// schema: -// type: string -// '500': -// description: Unable to delete the logs for the step -// schema: -// "$ref": "#/definitions/Error" - -// DeleteStepLog represents the API handler to remove -// the logs for a step from the configured backend. -func DeleteStepLog(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - s := step.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "step": s.GetNumber(), - "user": u.GetName(), - }).Infof("deleting logs for step %s", entry) - - // send API call to capture the step logs - l, err := database.FromContext(c).GetLogForStep(s) - if err != nil { - retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to remove the log - err = database.FromContext(c).DeleteLog(l) - if err != nil { - retErr := fmt.Errorf("unable to delete logs for step %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("logs deleted for step %s", entry)) -} diff --git a/api/log/create_service.go b/api/log/create_service.go new file mode 100644 index 000000000..dd559073c --- /dev/null +++ b/api/log/create_service.go @@ -0,0 +1,129 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code to step +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services CreateServiceLog +// +// Create the logs for a service +// +// --- +// deprecated: true +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the log to create +// required: true +// schema: +// "$ref": "#/definitions/Log" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the service logs +// schema: +// "$ref": "#/definitions/Log" +// '400': +// description: Unable to create the service logs +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the service logs +// schema: +// "$ref": "#/definitions/Error" + +// CreateServiceLog represents the API handler to create +// the logs for a service in the configured backend. +func CreateServiceLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("creating logs for service %s", entry) + + // capture body from API request + input := new(library.Log) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in log object + input.SetServiceID(s.GetID()) + input.SetBuildID(b.GetID()) + input.SetRepoID(r.GetID()) + + // send API call to create the logs + err = database.FromContext(c).CreateLog(input) + if err != nil { + retErr := fmt.Errorf("unable to create logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created log + l, _ := database.FromContext(c).GetLogForService(s) + + c.JSON(http.StatusCreated, l) +} diff --git a/api/log/create_step.go b/api/log/create_step.go new file mode 100644 index 000000000..0f8a1ca5a --- /dev/null +++ b/api/log/create_step.go @@ -0,0 +1,129 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code to service +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps CreateStepLog +// +// Create the logs for a step +// +// --- +// deprecated: true +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the log to create +// required: true +// schema: +// "$ref": "#/definitions/Log" +// security: +// - ApiKeyAuth: [] +// responses: +// '201': +// description: Successfully created the logs for step +// schema: +// "$ref": "#/definitions/Log" +// '400': +// description: Unable to create the logs for a step +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the logs for a step +// schema: +// "$ref": "#/definitions/Error" + +// CreateStepLog represents the API handler to create +// the logs for a step in the configured backend. +func CreateStepLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("creating logs for step %s", entry) + + // capture body from API request + input := new(library.Log) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in log object + input.SetStepID(s.GetID()) + input.SetBuildID(b.GetID()) + input.SetRepoID(r.GetID()) + + // send API call to create the logs + err = database.FromContext(c).CreateLog(input) + if err != nil { + retErr := fmt.Errorf("unable to create logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the created log + l, _ := database.FromContext(c).GetLogForStep(s) + + c.JSON(http.StatusCreated, l) +} diff --git a/api/log/delete_service.go b/api/log/delete_service.go new file mode 100644 index 000000000..c87d87b1b --- /dev/null +++ b/api/log/delete_service.go @@ -0,0 +1,107 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with step +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services DeleteServiceLog +// +// Delete the logs for a service +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the service logs +// schema: +// type: string +// '500': +// description: Unable to delete the service logs +// schema: +// "$ref": "#/definitions/Error" + +// DeleteServiceLog represents the API handler to remove +// the logs for a service from the configured backend. +func DeleteServiceLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("deleting logs for service %s", entry) + + // send API call to capture the service logs + l, err := database.FromContext(c).GetLogForService(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to remove the log + err = database.FromContext(c).DeleteLog(l) + if err != nil { + retErr := fmt.Errorf("unable to delete logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("logs deleted for service %s", entry)) +} diff --git a/api/log/delete_step.go b/api/log/delete_step.go new file mode 100644 index 000000000..90e7fc7ac --- /dev/null +++ b/api/log/delete_step.go @@ -0,0 +1,107 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with service +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps DeleteStepLog +// +// Delete the logs for a step +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the logs for the step +// schema: +// type: string +// '500': +// description: Unable to delete the logs for the step +// schema: +// "$ref": "#/definitions/Error" + +// DeleteStepLog represents the API handler to remove +// the logs for a step from the configured backend. +func DeleteStepLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("deleting logs for step %s", entry) + + // send API call to capture the step logs + l, err := database.FromContext(c).GetLogForStep(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to remove the log + err = database.FromContext(c).DeleteLog(l) + if err != nil { + retErr := fmt.Errorf("unable to delete logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("logs deleted for step %s", entry)) +} diff --git a/api/log/doc.go b/api/log/doc.go new file mode 100644 index 000000000..9f619b01c --- /dev/null +++ b/api/log/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package log provides the log handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/log" +package log diff --git a/api/log/get_service.go b/api/log/get_service.go new file mode 100644 index 000000000..2a15ad7e5 --- /dev/null +++ b/api/log/get_service.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with step +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services GetServiceLog +// +// Retrieve the logs for a service +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the service logs +// schema: +// "$ref": "#/definitions/Log" +// '500': +// description: Unable to retrieve the service logs +// schema: +// "$ref": "#/definitions/Error" + +// GetServiceLog represents the API handler to capture +// the logs for a service from the configured backend. +func GetServiceLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("reading logs for service %s", entry) + + // send API call to capture the service logs + l, err := database.FromContext(c).GetLogForService(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, l) +} diff --git a/api/log/get_step.go b/api/log/get_step.go new file mode 100644 index 000000000..39859f1dd --- /dev/null +++ b/api/log/get_step.go @@ -0,0 +1,98 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with service +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps GetStepLog +// +// Retrieve the logs for a step +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the logs for step +// type: json +// schema: +// "$ref": "#/definitions/Log" +// '500': +// description: Unable to retrieve the logs for a step +// schema: +// "$ref": "#/definitions/Error" + +// GetStepLog represents the API handler to capture +// the logs for a step from the configured backend. +func GetStepLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("reading logs for step %s", entry) + + // send API call to capture the step logs + l, err := database.FromContext(c).GetLogForStep(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, l) +} diff --git a/api/log/list_build.go b/api/log/list_build.go new file mode 100644 index 000000000..fe93947d0 --- /dev/null +++ b/api/log/list_build.go @@ -0,0 +1,134 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package log + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/logs builds ListLogsForBuild +// +// List logs for a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved logs for the build +// schema: +// type: array +// items: +// "$ref": "#/definitions/Log" +// '500': +// description: Unable to retrieve logs for the build +// schema: +// "$ref": "#/definitions/Error" + +// ListLogsForBuild represents the API handler to capture a +// list of logs for a build from the configured backend. +func ListLogsForBuild(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("listing logs for build %s", entry) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + //nolint:lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to convert page query parameter for build %s: %w", entry, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for build %s: %w", entry, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of logs for the build + l, t, err := database.FromContext(c).ListLogsForBuild(b, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to list logs for build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, l) +} diff --git a/api/log/update_service.go b/api/log/update_service.go new file mode 100644 index 000000000..746fd63e5 --- /dev/null +++ b/api/log/update_service.go @@ -0,0 +1,140 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with step +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/service" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/services/{service}/logs services UpdateServiceLog +// +// Update the logs for a service +// +// --- +// deprecated: true +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: service +// description: Service number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the log to update +// required: true +// schema: +// "$ref": "#/definitions/Log" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the service logs +// schema: +// "$ref": "#/definitions/Log" +// '400': +// description: Unable to updated the service logs +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to updates the service logs +// schema: +// "$ref": "#/definitions/Error" + +// UpdateServiceLog represents the API handler to update +// the logs for a service in the configured backend. +func UpdateServiceLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := service.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "service": s.GetNumber(), + "user": u.GetName(), + }).Infof("updating logs for service %s", entry) + + // send API call to capture the service logs + l, err := database.FromContext(c).GetLogForService(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // capture body from API request + input := new(library.Log) + + err = c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for service %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update log fields if provided + if len(input.GetData()) > 0 { + // update data if set + l.SetData(input.GetData()) + } + + // send API call to update the log + err = database.FromContext(c).UpdateLog(l) + if err != nil { + retErr := fmt.Errorf("unable to update logs for service %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated log + l, _ = database.FromContext(c).GetLogForService(s) + + c.JSON(http.StatusOK, l) +} diff --git a/api/log/update_step.go b/api/log/update_step.go new file mode 100644 index 000000000..a86a74113 --- /dev/null +++ b/api/log/update_step.go @@ -0,0 +1,140 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with service +package log + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/step" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/util" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build}/steps/{step}/logs steps UpdateStepLog +// +// Update the logs for a step +// +// --- +// deprecated: true +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// - in: path +// name: step +// description: Step number +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the log to update +// required: true +// schema: +// "$ref": "#/definitions/Log" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the logs for step +// schema: +// "$ref": "#/definitions/Log" +// '400': +// description: Unable to update the logs for a step +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the logs for a step +// schema: +// "$ref": "#/definitions/Error" + +// UpdateStepLog represents the API handler to update +// the logs for a step in the configured backend. +func UpdateStepLog(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + s := step.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d/%d", r.GetFullName(), b.GetNumber(), s.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "step": s.GetNumber(), + "user": u.GetName(), + }).Infof("updating logs for step %s", entry) + + // send API call to capture the step logs + l, err := database.FromContext(c).GetLogForStep(s) + if err != nil { + retErr := fmt.Errorf("unable to get logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // capture body from API request + input := new(library.Log) + + err = c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for step %s: %w", entry, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update log fields if provided + if len(input.GetData()) > 0 { + // update data if set + l.SetData(input.GetData()) + } + + // send API call to update the log + err = database.FromContext(c).UpdateLog(l) + if err != nil { + retErr := fmt.Errorf("unable to update logs for step %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated log + l, _ = database.FromContext(c).GetLogForStep(s) + + c.JSON(http.StatusOK, l) +} diff --git a/router/build.go b/router/build.go index 4c922bcb0..4aab6a9c7 100644 --- a/router/build.go +++ b/router/build.go @@ -7,6 +7,7 @@ package router import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/api" + "github.com/go-vela/server/api/log" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/router/middleware/executors" @@ -58,7 +59,7 @@ func BuildHandlers(base *gin.RouterGroup) { build.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateBuild) build.DELETE("", perm.MustPlatformAdmin(), api.DeleteBuild) build.DELETE("/cancel", executors.Establish(), perm.MustWrite(), api.CancelBuild) - build.GET("/logs", perm.MustRead(), api.GetBuildLogs) + build.GET("/logs", perm.MustRead(), log.ListLogsForBuild) build.GET("/token", perm.MustWorkerAuthToken(), api.GetBuildToken) // Service endpoints diff --git a/router/log.go b/router/log.go index fc7498b48..71c6674c8 100644 --- a/router/log.go +++ b/router/log.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/log" "github.com/go-vela/server/router/middleware/perm" ) @@ -21,10 +21,10 @@ func LogServiceHandlers(base *gin.RouterGroup) { // Logs endpoints logs := base.Group("/logs") { - logs.POST("", perm.MustAdmin(), api.CreateServiceLog) - logs.GET("", perm.MustRead(), api.GetServiceLog) - logs.PUT("", perm.MustBuildAccess(), api.UpdateServiceLog) - logs.DELETE("", perm.MustPlatformAdmin(), api.DeleteServiceLog) + logs.POST("", perm.MustAdmin(), log.CreateServiceLog) + logs.GET("", perm.MustRead(), log.GetServiceLog) + logs.PUT("", perm.MustBuildAccess(), log.UpdateServiceLog) + logs.DELETE("", perm.MustPlatformAdmin(), log.DeleteServiceLog) } // end of logs endpoints } @@ -39,9 +39,9 @@ func LogStepHandlers(base *gin.RouterGroup) { // Logs endpoints logs := base.Group("/logs") { - logs.POST("", perm.MustAdmin(), api.CreateStepLog) - logs.GET("", perm.MustRead(), api.GetStepLog) - logs.PUT("", perm.MustBuildAccess(), api.UpdateStepLog) - logs.DELETE("", perm.MustPlatformAdmin(), api.DeleteStepLog) + logs.POST("", perm.MustAdmin(), log.CreateStepLog) + logs.GET("", perm.MustRead(), log.GetStepLog) + logs.PUT("", perm.MustBuildAccess(), log.UpdateStepLog) + logs.DELETE("", perm.MustPlatformAdmin(), log.DeleteStepLog) } // end of logs endpoints } From 4ffd2f1b7ea7bfe99dd6c1c6fb87985701aa2503 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 22 May 2023 10:16:02 -0600 Subject: [PATCH 240/298] fix(router): establish claims before user on logout (#857) * fix(router): establish claims before user on logout * add a basic nil check in user establish --- router/middleware/user/user.go | 4 ++-- router/router.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/router/middleware/user/user.go b/router/middleware/user/user.go index 1dd894a10..ad94a5e0d 100644 --- a/router/middleware/user/user.go +++ b/router/middleware/user/user.go @@ -29,8 +29,8 @@ func Establish() gin.HandlerFunc { return func(c *gin.Context) { cl := claims.Retrieve(c) - // if token is not a user token, establish empty user to better handle nil checks - if !strings.EqualFold(cl.TokenType, constants.UserAccessTokenType) { + // if token is not a user token or claims were not retrieved, establish empty user to better handle nil checks + if cl == nil || !strings.EqualFold(cl.TokenType, constants.UserAccessTokenType) { u := new(library.User) ToContext(c, u) diff --git a/router/router.go b/router/router.go index f756f9f4e..2ed598034 100644 --- a/router/router.go +++ b/router/router.go @@ -69,7 +69,7 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { r.GET("/login", auth.Login) // Logout endpoint - r.GET("/logout", user.Establish(), auth.Logout) + r.GET("/logout", claims.Establish(), user.Establish(), auth.Logout) // Refresh Access Token endpoint r.GET("/token-refresh", auth.RefreshAccessToken) From afd00ce206085f6e03ae86722061fc85c573cbb8 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 22 May 2023 12:55:22 -0600 Subject: [PATCH 241/298] refactor(api): move secret logic to separate package (#856) * refactor(api): move secret logic to separate package * Update api/secret/list.go --------- Co-authored-by: Jacob Floyd --- api/secret.go | 822 ------------------------------------------- api/secret/create.go | 244 +++++++++++++ api/secret/delete.go | 121 +++++++ api/secret/doc.go | 10 + api/secret/get.go | 130 +++++++ api/secret/list.go | 210 +++++++++++ api/secret/update.go | 177 ++++++++++ router/secret.go | 12 +- util/util.go | 17 + 9 files changed, 915 insertions(+), 828 deletions(-) delete mode 100644 api/secret.go create mode 100644 api/secret/create.go create mode 100644 api/secret/delete.go create mode 100644 api/secret/doc.go create mode 100644 api/secret/get.go create mode 100644 api/secret/list.go create mode 100644 api/secret/update.go diff --git a/api/secret.go b/api/secret.go deleted file mode 100644 index 6e1534d01..000000000 --- a/api/secret.go +++ /dev/null @@ -1,822 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/router/middleware/claims" - "github.com/go-vela/server/router/middleware/user" - "github.com/go-vela/server/scm" - "github.com/go-vela/server/secret" - "github.com/go-vela/server/util" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// -// swagger:operation POST /api/v1/secrets/{engine}/{type}/{org}/{name} secrets CreateSecret -// -// Create a secret -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: engine -// description: Secret engine to create a secret in, eg. "native" -// required: true -// type: string -// - in: path -// name: type -// description: Secret type to create -// enum: -// - org -// - repo -// - shared -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: name -// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret -// required: true -// type: string -// - in: body -// name: body -// description: Payload containing the secret to create -// required: true -// schema: -// "$ref": "#/definitions/Secret" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully created the secret -// schema: -// "$ref": "#/definitions/Secret" -// '400': -// description: Unable to create the secret -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the secret -// schema: -// "$ref": "#/definitions/Error" - -// CreateSecret represents the API handler to -// create a secret in the configured backend. -// -//nolint:funlen // suppress long function error -func CreateSecret(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - e := util.PathParameter(c, "engine") - t := util.PathParameter(c, "type") - o := util.PathParameter(c, "org") - n := util.PathParameter(c, "name") - - entry := fmt.Sprintf("%s/%s/%s", t, o, n) - - // create log fields from API metadata - fields := logrus.Fields{ - "engine": e, - "org": o, - "repo": n, - "type": t, - "user": u.GetName(), - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from API metadata - fields = logrus.Fields{ - "engine": e, - "org": o, - "team": n, - "type": t, - "user": u.GetName(), - } - } - - if strings.EqualFold(t, constants.SecretOrg) { - // retrieve org name from SCM - // - // SCM can be case insensitive, causing access retrieval to work - // but Org/Repo != org/repo in Vela. So this check ensures that - // what a user inputs matches the casing we expect in Vela since - // the SCM will have the source of truth for casing. - org, err := scm.FromContext(c).GetOrgName(u, o) - if err != nil { - retErr := fmt.Errorf("unable to retrieve organization %s", o) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // check if casing is accurate - if org != o { - retErr := fmt.Errorf("unable to retrieve organization %s. Did you mean %s?", o, org) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } - - if strings.EqualFold(t, constants.SecretRepo) { - // retrieve org and repo name from SCM - // - // same story as org secret. SCM has accurate casing. - scmOrg, scmRepo, err := scm.FromContext(c).GetOrgAndRepoName(u, o, n) - if err != nil { - retErr := fmt.Errorf("unable to retrieve repository %s/%s", o, n) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // check if casing is accurate for org entry - if scmOrg != o { - retErr := fmt.Errorf("unable to retrieve org %s. Did you mean %s?", o, scmOrg) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // check if casing is accurate for repo entry - if scmRepo != n { - retErr := fmt.Errorf("unable to retrieve repository %s. Did you mean %s?", n, scmRepo) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(fields).Infof("creating new secret %s for %s service", entry, e) - - // capture body from API request - input := new(library.Secret) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // reject secrets with solely whitespace characters as its value - trimmed := strings.TrimSpace(input.GetValue()) - if len(trimmed) == 0 { - retErr := fmt.Errorf("secret value must contain non-whitespace characters") - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in secret object - input.SetOrg(o) - input.SetRepo(n) - input.SetType(t) - input.SetCreatedAt(time.Now().UTC().Unix()) - input.SetCreatedBy(u.GetName()) - input.SetUpdatedAt(time.Now().UTC().Unix()) - input.SetUpdatedBy(u.GetName()) - - if len(input.GetImages()) > 0 { - input.SetImages(unique(input.GetImages())) - } - - if len(input.GetEvents()) > 0 { - input.SetEvents(unique(input.GetEvents())) - } - - if len(input.GetEvents()) == 0 { - // set default events to enable for the secret - input.SetEvents([]string{constants.EventPush, constants.EventTag, constants.EventDeploy}) - } - - if input.AllowCommand == nil { - input.SetAllowCommand(true) - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update the team instead of repo - input.SetTeam(n) - input.Repo = nil - } - - // send API call to create the secret - err = secret.FromContext(c, e).Create(t, o, n, input) - if err != nil { - retErr := fmt.Errorf("unable to create secret %s for %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - s, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) - - c.JSON(http.StatusOK, s.Sanitize()) -} - -// -// swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name} secrets GetSecrets -// -// Retrieve a list of secrets from the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: engine -// description: Secret engine to create a secret in, eg. "native" -// required: true -// type: string -// - in: path -// name: type -// description: Secret type to create -// enum: -// - org -// - repo -// - shared -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: name -// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret -// required: true -// type: string -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the list of secrets -// schema: -// type: array -// items: -// "$ref": "#/definitions/Secret" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of secrets -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of secrets -// schema: -// "$ref": "#/definitions/Error" - -// GetSecrets represents the API handler to capture -// a list of secrets from the configured backend. -func GetSecrets(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - e := util.PathParameter(c, "engine") - t := util.PathParameter(c, "type") - o := util.PathParameter(c, "org") - n := util.PathParameter(c, "name") - - var teams []string - // get list of user's teams if type is shared secret and team is '*' - if t == constants.SecretShared && n == "*" { - var err error - - teams, err = scm.FromContext(c).ListUsersTeamsForOrg(u, o) - if err != nil { - retErr := fmt.Errorf("unable to get users %s teams for org %s: %w", u.GetName(), o, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - } - - entry := fmt.Sprintf("%s/%s/%s", t, o, n) - - // create log fields from API metadata - fields := logrus.Fields{ - "engine": e, - "org": o, - "repo": n, - "type": t, - "user": u.GetName(), - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from API metadata - fields = logrus.Fields{ - "engine": e, - "org": o, - "team": n, - "type": t, - "user": u.GetName(), - } - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(fields).Infof("reading secrets %s from %s service", entry, e) - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the total number of secrets - total, err := secret.FromContext(c, e).Count(t, o, n, teams) - if err != nil { - retErr := fmt.Errorf("unable to get secret count for %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // send API call to capture the list of secrets - s, err := secret.FromContext(c, e).List(t, o, n, page, perPage, teams) - if err != nil { - retErr := fmt.Errorf("unable to get secrets for %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: total, - } - // set pagination headers - pagination.SetHeaderLink(c) - - // variable we want to return - secrets := []*library.Secret{} - // iterate through all secrets - for _, secret := range s { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := secret - - // sanitize secret to ensure no value is provided - secrets = append(secrets, tmp.Sanitize()) - } - - c.JSON(http.StatusOK, secrets) -} - -// -// swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets GetSecret -// -// Retrieve a secret from the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: engine -// description: Secret engine to create a secret in, eg. "native" -// required: true -// type: string -// - in: path -// name: type -// description: Secret type to create -// enum: -// - org -// - repo -// - shared -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: name -// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret -// required: true -// type: string -// - in: path -// name: secret -// description: Name of the secret -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the secret -// schema: -// "$ref": "#/definitions/Secret" -// '500': -// description: Unable to retrieve the secret -// schema: -// "$ref": "#/definitions/Error" - -// GetSecret gets a secret from the provided secrets service. -func GetSecret(c *gin.Context) { - // capture middleware values - cl := claims.Retrieve(c) - u := user.Retrieve(c) - e := util.PathParameter(c, "engine") - t := util.PathParameter(c, "type") - o := util.PathParameter(c, "org") - n := util.PathParameter(c, "name") - s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") - - entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) - - // create log fields from API metadata - fields := logrus.Fields{ - "engine": e, - "org": o, - "repo": n, - "secret": s, - "type": t, - "user": u.GetName(), - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from API metadata - fields = logrus.Fields{ - "engine": e, - "org": o, - "secret": s, - "team": n, - "type": t, - "user": u.GetName(), - } - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(fields).Infof("reading secret %s from %s service", entry, e) - - // send API call to capture the secret - secret, err := secret.FromContext(c, e).Get(t, o, n, s) - if err != nil { - retErr := fmt.Errorf("unable to get secret %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // only allow workers to access the full secret with the value - if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { - c.JSON(http.StatusOK, secret) - - return - } - - c.JSON(http.StatusOK, secret.Sanitize()) -} - -// -// swagger:operation PUT /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets UpdateSecrets -// -// Update a secret on the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: engine -// description: Secret engine to update the secret in, eg. "native" -// required: true -// type: string -// - in: path -// name: type -// description: Secret type to update -// enum: -// - org -// - repo -// - shared -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: name -// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret -// required: true -// type: string -// - in: path -// name: secret -// description: Name of the secret -// required: true -// type: string -// - in: body -// name: body -// description: Payload containing the secret to create -// required: true -// schema: -// "$ref": "#/definitions/Secret" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the secret -// schema: -// "$ref": "#/definitions/Secret" -// '400': -// description: Unable to update the secret -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the secret -// schema: -// "$ref": "#/definitions/Error" - -// UpdateSecret updates a secret for the provided secrets service. -func UpdateSecret(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - e := util.PathParameter(c, "engine") - t := util.PathParameter(c, "type") - o := util.PathParameter(c, "org") - n := util.PathParameter(c, "name") - s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") - - entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) - - // create log fields from API metadata - fields := logrus.Fields{ - "engine": e, - "org": o, - "repo": n, - "secret": s, - "type": t, - "user": u.GetName(), - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from API metadata - fields = logrus.Fields{ - "engine": e, - "org": o, - "secret": s, - "team": n, - "type": t, - "user": u.GetName(), - } - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(fields).Infof("updating secret %s for %s service", entry, e) - - // capture body from API request - input := new(library.Secret) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update secret fields if provided - input.SetName(s) - input.SetOrg(o) - input.SetRepo(n) - input.SetType(t) - input.SetUpdatedAt(time.Now().UTC().Unix()) - input.SetUpdatedBy(u.GetName()) - - if input.Images != nil { - // update images if set - input.SetImages(unique(input.GetImages())) - } - - if len(input.GetEvents()) > 0 { - input.SetEvents(unique(input.GetEvents())) - } - - if input.AllowCommand != nil { - // update allow_command if set - input.SetAllowCommand(input.GetAllowCommand()) - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update the team instead of repo - input.SetTeam(n) - input.Repo = nil - } - - // send API call to update the secret - err = secret.FromContext(c, e).Update(t, o, n, input) - if err != nil { - retErr := fmt.Errorf("unable to update secret %s for %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated secret - secret, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) - - c.JSON(http.StatusOK, secret.Sanitize()) -} - -// -// swagger:operation DELETE /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets DeleteSecret -// -// Delete a secret from the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: engine -// description: Secret engine to delete the secret from, eg. "native" -// required: true -// type: string -// - in: path -// name: type -// description: Secret type to delete -// enum: -// - org -// - repo -// - shared -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: name -// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret -// required: true -// type: string -// - in: path -// name: secret -// description: Name of the secret -// required: true -// type: string -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the secret -// schema: -// type: string -// '500': -// description: Unable to delete the secret -// schema: -// "$ref": "#/definitions/Error" - -// DeleteSecret deletes a secret from the provided secrets service. -func DeleteSecret(c *gin.Context) { - // capture middleware values - u := user.Retrieve(c) - e := util.PathParameter(c, "engine") - t := util.PathParameter(c, "type") - o := util.PathParameter(c, "org") - n := util.PathParameter(c, "name") - s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") - - entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) - - // create log fields from API metadata - fields := logrus.Fields{ - "engine": e, - "org": o, - "repo": n, - "secret": s, - "type": t, - "user": u.GetName(), - } - - // check if secret is a shared secret - if strings.EqualFold(t, constants.SecretShared) { - // update log fields from API metadata - fields = logrus.Fields{ - "engine": e, - "org": o, - "secret": s, - "team": n, - "type": t, - "user": u.GetName(), - } - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(fields).Infof("deleting secret %s from %s service", entry, e) - - // send API call to remove the secret - err := secret.FromContext(c, e).Delete(t, o, n, s) - if err != nil { - retErr := fmt.Errorf("unable to delete secret %s from %s service: %w", entry, e, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("secret %s deleted from %s service", entry, e)) -} - -// unique is a helper function that takes a slice and -// validates that there are no duplicate entries. -func unique(stringSlice []string) []string { - keys := make(map[string]bool) - list := []string{} - - for _, entry := range stringSlice { - if _, value := keys[entry]; !value { - keys[entry] = true - - list = append(list, entry) - } - } - - return list -} diff --git a/api/secret/create.go b/api/secret/create.go new file mode 100644 index 000000000..3ba5061f9 --- /dev/null +++ b/api/secret/create.go @@ -0,0 +1,244 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/scm" + "github.com/go-vela/server/secret" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation POST /api/v1/secrets/{engine}/{type}/{org}/{name} secrets CreateSecret +// +// Create a secret +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: engine +// description: Secret engine to create a secret in, eg. "native" +// required: true +// type: string +// - in: path +// name: type +// description: Secret type to create +// enum: +// - org +// - repo +// - shared +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: name +// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the secret to create +// required: true +// schema: +// "$ref": "#/definitions/Secret" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully created the secret +// schema: +// "$ref": "#/definitions/Secret" +// '400': +// description: Unable to create the secret +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the secret +// schema: +// "$ref": "#/definitions/Error" + +// CreateSecret represents the API handler to +// create a secret in the configured backend. +// +//nolint:funlen // suppress long function error +func CreateSecret(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + + entry := fmt.Sprintf("%s/%s/%s", t, o, n) + + // create log fields from API metadata + fields := logrus.Fields{ + "engine": e, + "org": o, + "repo": n, + "type": t, + "user": u.GetName(), + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update log fields from API metadata + fields = logrus.Fields{ + "engine": e, + "org": o, + "team": n, + "type": t, + "user": u.GetName(), + } + } + + if strings.EqualFold(t, constants.SecretOrg) { + // retrieve org name from SCM + // + // SCM can be case insensitive, causing access retrieval to work + // but Org/Repo != org/repo in Vela. So this check ensures that + // what a user inputs matches the casing we expect in Vela since + // the SCM will have the source of truth for casing. + org, err := scm.FromContext(c).GetOrgName(u, o) + if err != nil { + retErr := fmt.Errorf("unable to retrieve organization %s", o) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate + if org != o { + retErr := fmt.Errorf("unable to retrieve organization %s. Did you mean %s?", o, org) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + + if strings.EqualFold(t, constants.SecretRepo) { + // retrieve org and repo name from SCM + // + // same story as org secret. SCM has accurate casing. + scmOrg, scmRepo, err := scm.FromContext(c).GetOrgAndRepoName(u, o, n) + if err != nil { + retErr := fmt.Errorf("unable to retrieve repository %s/%s", o, n) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate for org entry + if scmOrg != o { + retErr := fmt.Errorf("unable to retrieve org %s. Did you mean %s?", o, scmOrg) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // check if casing is accurate for repo entry + if scmRepo != n { + retErr := fmt.Errorf("unable to retrieve repository %s. Did you mean %s?", n, scmRepo) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(fields).Infof("creating new secret %s for %s service", entry, e) + + // capture body from API request + input := new(library.Secret) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // reject secrets with solely whitespace characters as its value + trimmed := strings.TrimSpace(input.GetValue()) + if len(trimmed) == 0 { + retErr := fmt.Errorf("secret value must contain non-whitespace characters") + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in secret object + input.SetOrg(o) + input.SetRepo(n) + input.SetType(t) + input.SetCreatedAt(time.Now().UTC().Unix()) + input.SetCreatedBy(u.GetName()) + input.SetUpdatedAt(time.Now().UTC().Unix()) + input.SetUpdatedBy(u.GetName()) + + if len(input.GetImages()) > 0 { + input.SetImages(util.Unique(input.GetImages())) + } + + if len(input.GetEvents()) > 0 { + input.SetEvents(util.Unique(input.GetEvents())) + } + + if len(input.GetEvents()) == 0 { + // set default events to enable for the secret + input.SetEvents([]string{constants.EventPush, constants.EventTag, constants.EventDeploy}) + } + + if input.AllowCommand == nil { + input.SetAllowCommand(true) + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update the team instead of repo + input.SetTeam(n) + input.Repo = nil + } + + // send API call to create the secret + err = secret.FromContext(c, e).Create(t, o, n, input) + if err != nil { + retErr := fmt.Errorf("unable to create secret %s for %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + s, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) + + c.JSON(http.StatusOK, s.Sanitize()) +} diff --git a/api/secret/delete.go b/api/secret/delete.go new file mode 100644 index 000000000..f8134ba5f --- /dev/null +++ b/api/secret/delete.go @@ -0,0 +1,121 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/secret" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation DELETE /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets DeleteSecret +// +// Delete a secret from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: engine +// description: Secret engine to delete the secret from, eg. "native" +// required: true +// type: string +// - in: path +// name: type +// description: Secret type to delete +// enum: +// - org +// - repo +// - shared +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: name +// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret +// required: true +// type: string +// - in: path +// name: secret +// description: Name of the secret +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the secret +// schema: +// type: string +// '500': +// description: Unable to delete the secret +// schema: +// "$ref": "#/definitions/Error" + +// DeleteSecret deletes a secret from the provided secrets service. +func DeleteSecret(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") + + entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) + + // create log fields from API metadata + fields := logrus.Fields{ + "engine": e, + "org": o, + "repo": n, + "secret": s, + "type": t, + "user": u.GetName(), + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update log fields from API metadata + fields = logrus.Fields{ + "engine": e, + "org": o, + "secret": s, + "team": n, + "type": t, + "user": u.GetName(), + } + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(fields).Infof("deleting secret %s from %s service", entry, e) + + // send API call to remove the secret + err := secret.FromContext(c, e).Delete(t, o, n, s) + if err != nil { + retErr := fmt.Errorf("unable to delete secret %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("secret %s deleted from %s service", entry, e)) +} diff --git a/api/secret/doc.go b/api/secret/doc.go new file mode 100644 index 000000000..db89d7b55 --- /dev/null +++ b/api/secret/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package secret provides the secret handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/secret" +package secret diff --git a/api/secret/get.go b/api/secret/get.go new file mode 100644 index 000000000..0f24b95c0 --- /dev/null +++ b/api/secret/get.go @@ -0,0 +1,130 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/secret" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets GetSecret +// +// Retrieve a secret from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: engine +// description: Secret engine to create a secret in, eg. "native" +// required: true +// type: string +// - in: path +// name: type +// description: Secret type to create +// enum: +// - org +// - repo +// - shared +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: name +// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret +// required: true +// type: string +// - in: path +// name: secret +// description: Name of the secret +// required: true +// type: string +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the secret +// schema: +// "$ref": "#/definitions/Secret" +// '500': +// description: Unable to retrieve the secret +// schema: +// "$ref": "#/definitions/Error" + +// GetSecret gets a secret from the provided secrets service. +func GetSecret(c *gin.Context) { + // capture middleware values + cl := claims.Retrieve(c) + u := user.Retrieve(c) + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") + + entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) + + // create log fields from API metadata + fields := logrus.Fields{ + "engine": e, + "org": o, + "repo": n, + "secret": s, + "type": t, + "user": u.GetName(), + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update log fields from API metadata + fields = logrus.Fields{ + "engine": e, + "org": o, + "secret": s, + "team": n, + "type": t, + "user": u.GetName(), + } + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(fields).Infof("reading secret %s from %s service", entry, e) + + // send API call to capture the secret + secret, err := secret.FromContext(c, e).Get(t, o, n, s) + if err != nil { + retErr := fmt.Errorf("unable to get secret %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // only allow workers to access the full secret with the value + if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { + c.JSON(http.StatusOK, secret) + + return + } + + c.JSON(http.StatusOK, secret.Sanitize()) +} diff --git a/api/secret/list.go b/api/secret/list.go new file mode 100644 index 000000000..e603c473f --- /dev/null +++ b/api/secret/list.go @@ -0,0 +1,210 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/scm" + "github.com/go-vela/server/secret" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation GET /api/v1/secrets/{engine}/{type}/{org}/{name} secrets ListSecrets +// +// Retrieve a list of secrets from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: engine +// description: Secret engine to create a secret in, eg. "native" +// required: true +// type: string +// - in: path +// name: type +// description: Secret type to create +// enum: +// - org +// - repo +// - shared +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: name +// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the list of secrets +// schema: +// type: array +// items: +// "$ref": "#/definitions/Secret" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of secrets +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of secrets +// schema: +// "$ref": "#/definitions/Error" + +// ListSecrets represents the API handler to capture +// a list of secrets from the configured backend. +func ListSecrets(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + + var teams []string + // get list of user's teams if type is shared secret and team is '*' + if t == constants.SecretShared && n == "*" { + var err error + + teams, err = scm.FromContext(c).ListUsersTeamsForOrg(u, o) + if err != nil { + retErr := fmt.Errorf("unable to list users %s teams for org %s: %w", u.GetName(), o, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + } + + entry := fmt.Sprintf("%s/%s/%s", t, o, n) + + // create log fields from API metadata + fields := logrus.Fields{ + "engine": e, + "org": o, + "repo": n, + "type": t, + "user": u.GetName(), + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update log fields from API metadata + fields = logrus.Fields{ + "engine": e, + "org": o, + "team": n, + "type": t, + "user": u.GetName(), + } + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(fields).Infof("listing secrets %s from %s service", entry, e) + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the total number of secrets + total, err := secret.FromContext(c, e).Count(t, o, n, teams) + if err != nil { + retErr := fmt.Errorf("unable to get secret count for %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // send API call to capture the list of secrets + s, err := secret.FromContext(c, e).List(t, o, n, page, perPage, teams) + if err != nil { + retErr := fmt.Errorf("unable to list secrets for %s from %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: total, + } + // set pagination headers + pagination.SetHeaderLink(c) + + // variable we want to return + secrets := []*library.Secret{} + // iterate through all secrets + for _, secret := range s { + // https://golang.org/doc/faq#closures_and_goroutines + tmp := secret + + // sanitize secret to ensure no value is provided + secrets = append(secrets, tmp.Sanitize()) + } + + c.JSON(http.StatusOK, secrets) +} diff --git a/api/secret/update.go b/api/secret/update.go new file mode 100644 index 000000000..f71889701 --- /dev/null +++ b/api/secret/update.go @@ -0,0 +1,177 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package secret + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/user" + "github.com/go-vela/server/secret" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// +// swagger:operation PUT /api/v1/secrets/{engine}/{type}/{org}/{name}/{secret} secrets UpdateSecret +// +// Update a secret on the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: engine +// description: Secret engine to update the secret in, eg. "native" +// required: true +// type: string +// - in: path +// name: type +// description: Secret type to update +// enum: +// - org +// - repo +// - shared +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: name +// description: Name of the repo if a repo secret, team name if a shared secret, or '*' if an org secret +// required: true +// type: string +// - in: path +// name: secret +// description: Name of the secret +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the secret to create +// required: true +// schema: +// "$ref": "#/definitions/Secret" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the secret +// schema: +// "$ref": "#/definitions/Secret" +// '400': +// description: Unable to update the secret +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the secret +// schema: +// "$ref": "#/definitions/Error" + +// UpdateSecret updates a secret for the provided secrets service. +func UpdateSecret(c *gin.Context) { + // capture middleware values + u := user.Retrieve(c) + e := util.PathParameter(c, "engine") + t := util.PathParameter(c, "type") + o := util.PathParameter(c, "org") + n := util.PathParameter(c, "name") + s := strings.TrimPrefix(util.PathParameter(c, "secret"), "/") + + entry := fmt.Sprintf("%s/%s/%s/%s", t, o, n, s) + + // create log fields from API metadata + fields := logrus.Fields{ + "engine": e, + "org": o, + "repo": n, + "secret": s, + "type": t, + "user": u.GetName(), + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update log fields from API metadata + fields = logrus.Fields{ + "engine": e, + "org": o, + "secret": s, + "team": n, + "type": t, + "user": u.GetName(), + } + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(fields).Infof("updating secret %s for %s service", entry, e) + + // capture body from API request + input := new(library.Secret) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for secret %s for %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update secret fields if provided + input.SetName(s) + input.SetOrg(o) + input.SetRepo(n) + input.SetType(t) + input.SetUpdatedAt(time.Now().UTC().Unix()) + input.SetUpdatedBy(u.GetName()) + + if input.Images != nil { + // update images if set + input.SetImages(util.Unique(input.GetImages())) + } + + if len(input.GetEvents()) > 0 { + input.SetEvents(util.Unique(input.GetEvents())) + } + + if input.AllowCommand != nil { + // update allow_command if set + input.SetAllowCommand(input.GetAllowCommand()) + } + + // check if secret is a shared secret + if strings.EqualFold(t, constants.SecretShared) { + // update the team instead of repo + input.SetTeam(n) + input.Repo = nil + } + + // send API call to update the secret + err = secret.FromContext(c, e).Update(t, o, n, input) + if err != nil { + retErr := fmt.Errorf("unable to update secret %s for %s service: %w", entry, e, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated secret + secret, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) + + c.JSON(http.StatusOK, secret.Sanitize()) +} diff --git a/router/secret.go b/router/secret.go index dbc18e6b6..0ce94d982 100644 --- a/router/secret.go +++ b/router/secret.go @@ -5,7 +5,7 @@ package router import ( - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/secret" "github.com/go-vela/server/router/middleware/perm" "github.com/gin-gonic/gin" @@ -23,10 +23,10 @@ func SecretHandlers(base *gin.RouterGroup) { // Secrets endpoints secrets := base.Group("/secrets/:engine/:type/:org/:name", perm.MustSecretAdmin()) { - secrets.POST("", api.CreateSecret) - secrets.GET("", api.GetSecrets) - secrets.GET("/*secret", api.GetSecret) - secrets.PUT("/*secret", api.UpdateSecret) - secrets.DELETE("/*secret", api.DeleteSecret) + secrets.POST("", secret.CreateSecret) + secrets.GET("", secret.ListSecrets) + secrets.GET("/*secret", secret.GetSecret) + secrets.PUT("/*secret", secret.UpdateSecret) + secrets.DELETE("/*secret", secret.DeleteSecret) } // end of secrets endpoints } diff --git a/util/util.go b/util/util.go index 849ffdd95..667653fbe 100644 --- a/util/util.go +++ b/util/util.go @@ -73,6 +73,23 @@ func EscapeValue(value string) string { return html.EscapeString(escaped) } +// Unique is a helper function that takes a slice and +// validates that there are no duplicate entries. +func Unique(stringSlice []string) []string { + keys := make(map[string]bool) + list := []string{} + + for _, entry := range stringSlice { + if _, value := keys[entry]; !value { + keys[entry] = true + + list = append(list, entry) + } + } + + return list +} + // CheckAllowlist is a helper function to ensure only repos in the // allowlist are specified. // From ffac676b781bab77d57caccbc12edd33d26e66b4 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 23 May 2023 08:31:08 -0600 Subject: [PATCH 242/298] fix(compiler): add commit field to compiler engine to handle file type template lite compilation (#859) --- api/build.go | 2 ++ api/pipeline/compile.go | 2 +- api/pipeline/expand.go | 2 +- api/pipeline/template.go | 2 +- api/pipeline/validate.go | 2 +- api/webhook.go | 1 + compiler/engine.go | 3 +++ compiler/native/expand.go | 2 +- compiler/native/expand_test.go | 7 +------ compiler/native/native.go | 10 ++++++++++ router/middleware/pipeline/pipeline.go | 1 + 11 files changed, 23 insertions(+), 11 deletions(-) diff --git a/api/build.go b/api/build.go index ce755027a..fed9184da 100644 --- a/api/build.go +++ b/api/build.go @@ -271,6 +271,7 @@ func CreateBuild(c *gin.Context) { p, compiled, err = compiler.FromContext(c). Duplicate(). WithBuild(input). + WithCommit(input.GetCommit()). WithFiles(files). WithMetadata(m). WithRepo(r). @@ -1200,6 +1201,7 @@ func RestartBuild(c *gin.Context) { p, compiled, err = compiler.FromContext(c). Duplicate(). WithBuild(b). + WithCommit(b.GetCommit()). WithFiles(files). WithMetadata(m). WithRepo(r). diff --git a/api/pipeline/compile.go b/api/pipeline/compile.go index 6e05121bc..723bf2522 100644 --- a/api/pipeline/compile.go +++ b/api/pipeline/compile.go @@ -94,7 +94,7 @@ func CompilePipeline(c *gin.Context) { r.SetPipelineType(p.GetType()) // create the compiler object - compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // compile the pipeline pipeline, _, err := compiler.CompileLite(p.GetData(), true, true, nil) diff --git a/api/pipeline/expand.go b/api/pipeline/expand.go index 9e0c44466..05e5c7dd8 100644 --- a/api/pipeline/expand.go +++ b/api/pipeline/expand.go @@ -95,7 +95,7 @@ func ExpandPipeline(c *gin.Context) { r.SetPipelineType(p.GetType()) // create the compiler object - compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // expand the templates in the pipeline pipeline, _, err := compiler.CompileLite(p.GetData(), true, false, nil) diff --git a/api/pipeline/template.go b/api/pipeline/template.go index 4bb01cb19..54233b691 100644 --- a/api/pipeline/template.go +++ b/api/pipeline/template.go @@ -96,7 +96,7 @@ func GetTemplates(c *gin.Context) { }).Infof("reading templates from pipeline %s", entry) // create the compiler object - compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // parse the pipeline configuration pipeline, _, err := compiler.Parse(p.GetData(), p.GetType(), new(yaml.Template)) diff --git a/api/pipeline/validate.go b/api/pipeline/validate.go index 01fa574d3..42e49e2ae 100644 --- a/api/pipeline/validate.go +++ b/api/pipeline/validate.go @@ -94,7 +94,7 @@ func ValidatePipeline(c *gin.Context) { r.SetPipelineType(p.GetType()) // create the compiler object - compiler := compiler.FromContext(c).Duplicate().WithMetadata(m).WithRepo(r).WithUser(u) + compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // capture optional template query parameter template, err := strconv.ParseBool(c.DefaultQuery("template", "true")) diff --git a/api/webhook.go b/api/webhook.go index 501caffa6..0c8c5bd73 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -511,6 +511,7 @@ func PostWebhook(c *gin.Context) { Duplicate(). WithBuild(b). WithComment(webhook.Comment). + WithCommit(b.GetCommit()). WithFiles(files). WithMetadata(m). WithRepo(repo). diff --git a/compiler/engine.go b/compiler/engine.go index f2ff2a33e..dfe0716c4 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -121,6 +121,9 @@ type Engine interface { // WithComment defines a function that sets // the comment in the Engine. WithComment(string) Engine + // WithCommit defines a function that sets + // the commit in the Engine. + WithCommit(string) Engine // WithFiles defines a function that sets // the changeset files in the Engine. WithFiles([]string) Engine diff --git a/compiler/native/expand.go b/compiler/native/expand.go index 4256de7e8..102ae9774 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -235,7 +235,7 @@ func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) { Org: c.repo.GetOrg(), Repo: c.repo.GetName(), Name: tmpl.Source, - Ref: c.build.GetCommit(), + Ref: c.commit, } if !c.UsePrivateGithub { diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index a8c232a71..c89d23d50 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -192,11 +192,6 @@ func TestNative_ExpandSteps(t *testing.T) { set.String("github-token", "", "doc") c := cli.NewContext(nil, set, nil) - testBuild := new(library.Build) - - testBuild.SetID(1) - testBuild.SetCommit("123abc456def") - testRepo := new(library.Repo) testRepo.SetID(1) @@ -318,7 +313,7 @@ func TestNative_ExpandSteps(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - compiler.WithBuild(testBuild).WithRepo(testRepo) + compiler.WithCommit("123abc456def").WithRepo(testRepo) for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/compiler/native/native.go b/compiler/native/native.go index e7e549b58..61b411838 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -35,6 +35,7 @@ type client struct { build *library.Build comment string + commit string files []string local bool metadata *types.Metadata @@ -131,6 +132,15 @@ func (c *client) WithComment(cmt string) compiler.Engine { return c } +// WithCommit sets the comment in the Engine. +func (c *client) WithCommit(cmt string) compiler.Engine { + if cmt != "" { + c.commit = cmt + } + + return c +} + // WithFiles sets the changeset files in the Engine. func (c *client) WithFiles(f []string) compiler.Engine { if f != nil { diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go index ecf08767b..1910e2c0f 100644 --- a/router/middleware/pipeline/pipeline.go +++ b/router/middleware/pipeline/pipeline.go @@ -77,6 +77,7 @@ func Establish() gin.HandlerFunc { // parse and compile the pipeline configuration file _, pipeline, err = compiler.FromContext(c). Duplicate(). + WithCommit(p). WithMetadata(c.MustGet("metadata").(*types.Metadata)). WithRepo(r). WithUser(u). From 5a9a92d279e058b75b37e589e1eef2ec63f550a6 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 23 May 2023 14:10:14 -0500 Subject: [PATCH 243/298] feat: add support for processing schedules (#846) * feat(api/types): add support for schedules * feat(database/types): add support for schedules * feat(database): add support for schedules * chore: update go dependencies * feat(database): add schedule engine * feat(api): add support for schedules * add routes * fix: parse entry for schedules * more wip code * add schedule allowlist * fix tests * add validation for entry * add mocks w/o updated payloads * fix issues with create * update mock responses * use schedule mocks * make linter happy * use proper func * couple more updates * fix mock pathing * enhance: switch to adhocore/gronx * chore: update go deps * goimports * yet another goimports * sigh * wildcard goimport * chore: address linter feedback * chore: save work * chore: remove new types * chore: updates for removed types * chore: update go dependencies * chore: address review feedback * chore: remove new types * feat: initial code for scheduler * chore: misc updates * chore: update go dependencies * chore: updates for local testing * chore: save work * fix: introduce jitter * chore: address review feedback * chore: address review feedback * chore: update go dependencies * chore: address review feedback * fix(scheduler): use WithCommit in compiler * chore: address review feedback --------- Co-authored-by: Jordan Sussman Co-authored-by: JordanSussman --- .gitignore | 2 +- api/build.go | 31 ++- api/build_test.go | 8 +- api/schedule/create.go | 2 +- api/schedule/delete.go | 2 +- api/schedule/get.go | 2 +- api/schedule/list.go | 2 +- api/schedule/update.go | 3 +- api/webhook.go | 10 +- cmd/vela-server/schedule.go | 381 ++++++++++++++++++++++++++++++++ cmd/vela-server/server.go | 120 +++++++--- docker-compose.yml | 2 +- go.mod | 5 +- go.sum | 9 +- scm/github/repo.go | 19 ++ scm/github/repo_test.go | 49 ++++ scm/github/testdata/branch.json | 101 +++++++++ scm/service.go | 3 + 18 files changed, 675 insertions(+), 76 deletions(-) create mode 100644 cmd/vela-server/schedule.go create mode 100644 scm/github/testdata/branch.json diff --git a/.gitignore b/.gitignore index f3be5762d..c557bc18b 100644 --- a/.gitignore +++ b/.gitignore @@ -67,4 +67,4 @@ __debug_bin .history .ionide -# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode \ No newline at end of file diff --git a/api/build.go b/api/build.go index fed9184da..445d4cc8a 100644 --- a/api/build.go +++ b/api/build.go @@ -14,26 +14,23 @@ import ( "strings" "time" - "github.com/go-vela/server/internal/token" - "github.com/go-vela/server/router/middleware/claims" - "github.com/go-vela/server/router/middleware/org" - + "github.com/gin-gonic/gin" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" "github.com/go-vela/server/queue" "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/executors" + "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/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -293,7 +290,7 @@ func CreateBuild(c *gin.Context) { r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found - skip := skipEmptyBuild(p) + skip := SkipEmptyBuild(p) if skip != "" { // set build to successful status input.SetStatus(constants.StatusSuccess) @@ -343,7 +340,7 @@ func CreateBuild(c *gin.Context) { input.SetPipelineID(pipeline.GetID()) // create the objects from the pipeline in the database - err = planBuild(database.FromContext(c), p, input, r) + err = PlanBuild(database.FromContext(c), p, input, r) if err != nil { util.HandleError(c, http.StatusInternalServerError, err) @@ -372,7 +369,7 @@ func CreateBuild(c *gin.Context) { } // publish the build to the queue - go publishToQueue( + go PublishToQueue( queue.FromGinContext(c), database.FromContext(c), p, @@ -382,11 +379,11 @@ func CreateBuild(c *gin.Context) { ) } -// skipEmptyBuild checks if the build should be skipped due to it +// SkipEmptyBuild checks if the build should be skipped due to it // not containing any steps besides init or clone. // //nolint:goconst // ignore init and clone constants -func skipEmptyBuild(p *pipeline.Build) string { +func SkipEmptyBuild(p *pipeline.Build) string { if len(p.Stages) == 1 { if p.Stages[0].Name == "init" { return "skipping build since only init stage found" @@ -1223,7 +1220,7 @@ func RestartBuild(c *gin.Context) { r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found - skip := skipEmptyBuild(p) + skip := SkipEmptyBuild(p) if skip != "" { // set build to successful status b.SetStatus(constants.StatusSkipped) @@ -1273,7 +1270,7 @@ func RestartBuild(c *gin.Context) { b.SetPipelineID(pipeline.GetID()) // create the objects from the pipeline in the database - err = planBuild(database.FromContext(c), p, b, r) + err = PlanBuild(database.FromContext(c), p, b, r) if err != nil { util.HandleError(c, http.StatusInternalServerError, err) @@ -1301,7 +1298,7 @@ func RestartBuild(c *gin.Context) { } // publish the build to the queue - go publishToQueue( + go PublishToQueue( queue.FromGinContext(c), database.FromContext(c), p, @@ -1568,12 +1565,12 @@ func getPRNumberFromBuild(b *library.Build) (int, error) { return strconv.Atoi(parts[2]) } -// planBuild is a helper function to plan the build for +// PlanBuild is a helper function to plan the build for // execution. This creates all resources, like steps // and services, for the build in the configured backend. // TODO: // - return build and error. -func planBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { +func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) diff --git a/api/build_test.go b/api/build_test.go index b92802303..1fb395d7d 100644 --- a/api/build_test.go +++ b/api/build_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. @@ -10,7 +10,7 @@ import ( "github.com/go-vela/types/pipeline" ) -func Test_skipEmptyBuild(t *testing.T) { +func Test_SkipEmptyBuild(t *testing.T) { type args struct { p *pipeline.Build } @@ -72,8 +72,8 @@ func Test_skipEmptyBuild(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := skipEmptyBuild(tt.args.p); got != tt.want { - t.Errorf("skipEmptyBuild() = %v, want %v", got, tt.want) + if got := SkipEmptyBuild(tt.args.p); got != tt.want { + t.Errorf("SkipEmptyBuild() = %v, want %v", got, tt.want) } }) } diff --git a/api/schedule/create.go b/api/schedule/create.go index 127c04909..c8eb92741 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.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/api/schedule/delete.go b/api/schedule/delete.go index fd7c0715f..a697954d8 100644 --- a/api/schedule/delete.go +++ b/api/schedule/delete.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/api/schedule/get.go b/api/schedule/get.go index 51a436bbe..727de5b84 100644 --- a/api/schedule/get.go +++ b/api/schedule/get.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/api/schedule/list.go b/api/schedule/list.go index c43188d86..cb64ada74 100644 --- a/api/schedule/list.go +++ b/api/schedule/list.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/api/schedule/update.go b/api/schedule/update.go index bdadbdd2d..646e55fc2 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -9,11 +9,10 @@ import ( "net/http" "time" - "github.com/go-vela/server/router/middleware/schedule" - "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/router/middleware/schedule" "github.com/go-vela/server/util" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" diff --git a/api/webhook.go b/api/webhook.go index 0c8c5bd73..5f4ddc5bf 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -542,7 +542,7 @@ func PostWebhook(c *gin.Context) { repo.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found - skip := skipEmptyBuild(p) + skip := SkipEmptyBuild(p) if skip != "" { // set build to successful status b.SetStatus(constants.StatusSkipped) @@ -609,7 +609,7 @@ func PostWebhook(c *gin.Context) { // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = planBuild(database.FromContext(c), p, b, repo) + err = PlanBuild(database.FromContext(c), p, b, repo) if err != nil { retErr := fmt.Errorf("%s: %w", baseErr, err) @@ -696,7 +696,7 @@ func PostWebhook(c *gin.Context) { } // publish the build to the queue - go publishToQueue( + go PublishToQueue( queue.FromGinContext(c), database.FromContext(c), p, @@ -706,9 +706,9 @@ func PostWebhook(c *gin.Context) { ) } -// publishToQueue is a helper function that creates +// PublishToQueue is a helper function that creates // a build item and publishes it to the queue. -func publishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { +func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { item := types.ToItem(p, b, r, u) logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go new file mode 100644 index 000000000..172b5c251 --- /dev/null +++ b/cmd/vela-server/schedule.go @@ -0,0 +1,381 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "fmt" + "strings" + "time" + + "github.com/adhocore/gronx" + "github.com/go-vela/server/api" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/database" + "github.com/go-vela/server/queue" + "github.com/go-vela/server/scm" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" + "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/util/wait" +) + +const baseErr = "unable to schedule build" + +func processSchedules(compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { + logrus.Infof("processing active schedules to create builds") + + // send API call to capture the list of active schedules + schedules, err := database.ListActiveSchedules() + if err != nil { + return err + } + + // iterate through the list of active schedules + for _, s := range schedules { + // send API call to capture the schedule + // + // This is needed to ensure we are not dealing with a stale schedule since we fetch + // all schedules once and iterate through that list which can take a significant + // amount of time to get to the end of the list. + schedule, err := database.GetSchedule(s.GetID()) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + + continue + } + + // create a variable to track if a build should be triggered based off the schedule + trigger := false + + // check if a build has already been triggered for the schedule + if schedule.GetScheduledAt() == 0 { + // trigger a build for the schedule since one has not already been scheduled + trigger = true + } else { + // parse the previous occurrence of the entry for the schedule + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + + continue + } + + // parse the next occurrence of the entry for the schedule + nextTime, err := gronx.NextTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + + continue + } + + // parse the UNIX timestamp from when the last build was triggered for the schedule + t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + + // check if the time since the last triggered build is greater than the entry duration for the schedule + if time.Since(t) > nextTime.Sub(prevTime) { + // trigger a build for the schedule since it has not previously ran + trigger = true + } + } + + if trigger && schedule.GetActive() { + err = processSchedule(schedule, compiler, database, metadata, queue, scm) + if err != nil { + logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + + continue + } + } + } + + return nil +} + +//nolint:funlen // ignore function length and number of statements +func processSchedule(s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { + // sleep for 1s - 3s before processing the schedule + // + // This should prevent multiple servers from processing a schedule at the same time by + // leveraging a base duration along with a standard deviation of randomness a.k.a. + // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 3.0. + time.Sleep(wait.Jitter(time.Second, 3.0)) + + // send API call to capture the repo for the schedule + r, err := database.GetRepo(s.GetRepoID()) + if err != nil { + return fmt.Errorf("unable to fetch repo: %w", err) + } + + logrus.Tracef("processing schedule %s/%s", r.GetFullName(), s.GetName()) + + // check if the repo is active + if !r.GetActive() { + return fmt.Errorf("repo %s is not active", r.GetFullName()) + } + + // check if the repo has a valid owner + if r.GetUserID() == 0 { + return fmt.Errorf("repo %s does not have a valid owner", r.GetFullName()) + } + + // send API call to capture the owner for the repo + u, err := database.GetUser(r.GetUserID()) + if err != nil { + return fmt.Errorf("unable to get owner for repo %s: %w", r.GetFullName(), err) + } + + // send API call to confirm repo owner has at least write access to repo + _, err = scm.RepoAccess(u, u.GetToken(), r.GetOrg(), r.GetName()) + if err != nil { + return fmt.Errorf("%s does not have at least write access for repo %s", u.GetName(), r.GetFullName()) + } + + // create SQL filters for querying pending and running builds for repo + filters := map[string]interface{}{ + "status": []string{constants.StatusPending, constants.StatusRunning}, + } + + // send API call to capture the number of pending or running builds for the repo + builds, err := database.GetRepoBuildCount(r, filters) + if err != nil { + return fmt.Errorf("unable to get count of builds for repo %s: %w", r.GetFullName(), err) + } + + // check if the number of pending and running builds exceeds the limit for the repo + if builds >= r.GetBuildLimit() { + return fmt.Errorf("repo %s has excceded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) + } + + // send API call to capture the commit sha for the branch + _, commit, err := scm.GetBranch(u, r) + if err != nil { + return fmt.Errorf("failed to get commit for repo %s on %s branch: %w", r.GetFullName(), r.GetBranch(), err) + } + + url := strings.TrimSuffix(r.GetClone(), ".git") + + b := new(library.Build) + b.SetAuthor(s.GetCreatedBy()) + b.SetBranch(r.GetBranch()) + b.SetClone(r.GetClone()) + b.SetCommit(commit) + b.SetDeploy(s.GetName()) + 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.SetSender(s.GetUpdatedBy()) + b.SetSource(fmt.Sprintf("%s/tree/%s", url, b.GetBranch())) + b.SetStatus(constants.StatusPending) + b.SetTitle(fmt.Sprintf("%s received from %s", constants.EventSchedule, url)) + + // populate the build link if a web address is provided + if len(metadata.Vela.WebAddress) > 0 { + b.SetLink(fmt.Sprintf("%s/%s/%d", metadata.Vela.WebAddress, r.GetFullName(), b.GetNumber())) + } + + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to control number of times to retry processing pipeline + retryLimit = 5 + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) + + // implement a loop to process asynchronous operations with a retry limit + // + // Some operations taken during this workflow can lead to race conditions failing to successfully process + // the request. This logic ensures we attempt our best efforts to handle these cases gracefully. + for i := 0; i < retryLimit; i++ { + logrus.Debugf("compilation loop - attempt %d", i+1) + // check if we're on the first iteration of the loop + if i > 0 { + // incrementally sleep in between retries + time.Sleep(time.Duration(i) * time.Second) + } + + // send API call to attempt to capture the pipeline + pipeline, err = database.GetPipelineForRepo(b.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet + // send API call to capture the pipeline configuration file + config, err = scm.ConfigBackoff(u, r, b.GetCommit()) + if err != nil { + return fmt.Errorf("unable to get pipeline config for %s/%s: %w", r.GetFullName(), b.GetCommit(), err) + } + } else { + config = pipeline.GetData() + } + + // send API call to capture repo for the counter (grabbing repo again to ensure counter is correct) + r, err = database.GetRepoForOrg(r.GetOrg(), r.GetName()) + if err != nil { + err = fmt.Errorf("unable to get repo %s: %w", r.GetFullName(), err) + + // check if the retry limit has been exceeded + if i < retryLimit-1 { + logrus.WithError(err).Warningf("retrying #%d", i+1) + + // continue to the next iteration of the loop + continue + } + + return err + } + + // set the build numbers based off repo counter + r.SetCounter(r.GetCounter() + 1) + b.SetNumber(r.GetCounter() + 1) + // set the parent equal to the current repo counter + b.SetParent(r.GetCounter()) + // check if the parent is set to 0 + if b.GetParent() == 0 { + // parent should be "1" if it's the first build ran + b.SetParent(1) + } + + // set the build link if a web address is provided + if len(metadata.Vela.WebAddress) > 0 { + b.SetLink(fmt.Sprintf("%s/%s/%d", metadata.Vela.WebAddress, r.GetFullName(), b.GetNumber())) + } + + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) + } + + var compiled *library.Pipeline + // parse and compile the pipeline configuration file + p, compiled, err = compiler. + Duplicate(). + WithBuild(b). + WithCommit(b.GetCommit()). + WithMetadata(metadata). + WithRepo(r). + WithUser(u). + Compile(config) + if err != nil { + return fmt.Errorf("unable to compile pipeline config for %s/%s: %w", r.GetFullName(), b.GetCommit(), err) + } + + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) + + // skip the build if only the init or clone steps are found + skip := api.SkipEmptyBuild(p) + if skip != "" { + return nil + } + + // check if the pipeline did not already exist in the database + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(b.GetCommit()) + pipeline.SetRef(b.GetRef()) + + // send API call to create the pipeline + err = database.CreatePipeline(pipeline) + if err != nil { + err = fmt.Errorf("failed to create pipeline for %s: %w", r.GetFullName(), err) + + // check if the retry limit has been exceeded + if i < retryLimit-1 { + logrus.WithError(err).Warningf("retrying #%d", i+1) + + // continue to the next iteration of the loop + continue + } + + return err + } + + // send API call to capture the created pipeline + pipeline, err = database.GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + return fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) + } + } + + b.SetPipelineID(pipeline.GetID()) + + // create the objects from the pipeline in the database + // TODO: + // - if a build gets created and something else fails midway, + // the next loop will attempt to create the same build, + // using the same Number and thus create a constraint + // conflict; consider deleting the partially created + // build object in the database + err = api.PlanBuild(database, p, b, r) + if err != nil { + // check if the retry limit has been exceeded + if i < retryLimit-1 { + logrus.WithError(err).Warningf("retrying #%d", i+1) + + // reset fields set by cleanBuild for retry + b.SetError("") + b.SetStatus(constants.StatusPending) + b.SetFinished(0) + + // continue to the next iteration of the loop + continue + } + + return err + } + + s.SetScheduledAt(time.Now().UTC().Unix()) + + // break the loop because everything was successful + break + } // end of retry loop + + // send API call to update repo for ensuring counter is incremented + err = database.UpdateRepo(r) + if err != nil { + return fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) + } + + // send API call to update schedule for ensuring scheduled_at field is set + err = database.UpdateSchedule(s) + if err != nil { + return fmt.Errorf("unable to update schedule %s/%s: %w", r.GetFullName(), s.GetName(), err) + } + + // send API call to capture the triggered build + b, err = database.GetBuild(b.GetNumber(), r) + if err != nil { + return fmt.Errorf("unable to get new build %s/%d: %w", r.GetFullName(), b.GetNumber(), err) + } + + // publish the build to the queue + go api.PublishToQueue( + queue, + database, + p, + b, + r, + u, + ) + + return nil +} diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 1f8bdbd9c..80508e4b0 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -9,16 +9,19 @@ import ( "fmt" "net/http" "net/url" + "os" + "os/signal" + "syscall" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/server/router" "github.com/go-vela/server/router/middleware" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" - "gopkg.in/tomb.v2" + "golang.org/x/sync/errgroup" + + "k8s.io/apimachinery/pkg/util/wait" ) func server(c *cli.Context) error { @@ -111,47 +114,92 @@ func server(c *cli.Context) error { return err } - var tomb tomb.Tomb - // start http server - tomb.Go(func() error { - port := addr.Port() + port := addr.Port() + // check if a port is part of the address + if len(port) == 0 { + port = c.String("server-port") + } + + // gin expects the address to be ":" ie ":8080" + srv := &http.Server{ + Addr: fmt.Sprintf(":%s", port), + Handler: router, + ReadHeaderTimeout: 60 * time.Second, + } - // check if a port is part of the address - if len(port) == 0 { - port = c.String("server-port") + // create the context for controlling the worker subprocesses + ctx, done := context.WithCancel(context.Background()) + // create the errgroup for managing worker subprocesses + // + // https://pkg.go.dev/golang.org/x/sync/errgroup?tab=doc#Group + g, gctx := errgroup.WithContext(ctx) + + // spawn goroutine to check for signals to gracefully shutdown + g.Go(func() error { + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) + + select { + case sig := <-signalChannel: + logrus.Infof("received signal: %s", sig) + err := srv.Shutdown(ctx) + if err != nil { + logrus.Error(err) + } + done() + case <-gctx.Done(): + logrus.Info("closing signal goroutine") + err := srv.Shutdown(ctx) + if err != nil { + logrus.Error(err) + } + return gctx.Err() } - // gin expects the address to be ":" ie ":8080" - srv := &http.Server{ - Addr: fmt.Sprintf(":%s", port), - Handler: router, - ReadHeaderTimeout: 60 * time.Second, + return nil + }) + + // spawn goroutine for starting the server + g.Go(func() error { + logrus.Infof("starting server on %s", addr.Host) + err = srv.ListenAndServe() + if err != nil { + // log a message indicating the failure of the server + logrus.Errorf("failing server: %v", err) } - logrus.Infof("running server on %s", addr.Host) - go func() { - logrus.Info("Starting HTTP server...") - err := srv.ListenAndServe() - if err != nil { - tomb.Kill(err) - } - }() + return err + }) - //nolint:gosimple // ignore this for now + // spawn goroutine for starting the scheduler + g.Go(func() error { + logrus.Info("starting scheduler") for { - select { - case <-tomb.Dying(): - logrus.Info("Stopping HTTP server...") - return srv.Shutdown(context.Background()) + // cut the configured minimum frequency duration for schedules in half + // + // We need to sleep for some amount of time before we attempt to process schedules + // setup in the database. Since the minimum frequency is configurable, we cut it in + // half and use that as the base duration to determine how long to sleep for. + base := c.Duration("schedule-minimum-frequency") / 2 + logrus.Infof("sleeping for %v before scheduling builds", base) + + // sleep for a duration of time before processing schedules + // + // This should prevent multiple servers from processing schedules at the same time by + // leveraging a base duration along with a standard deviation of randomness a.k.a. + // "jitter". To create the jitter, we use the configured minimum frequency duration + // along with a scale factor of 0.1. + time.Sleep(wait.Jitter(base, 0.1)) + + err = processSchedules(compiler, database, metadata, queue, scm) + if err != nil { + logrus.WithError(err).Warn("unable to process schedules") + } else { + logrus.Trace("successfully processed schedules") } } }) - // Wait for stuff and watch for errors - err = tomb.Wait() - if err != nil { - return err - } - - return tomb.Err() + // wait for errors from server subprocesses + return g.Wait() } diff --git a/docker-compose.yml b/docker-compose.yml index 1394c317b..d030743e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -157,4 +157,4 @@ services: - IPC_LOCK networks: - vela: + vela: \ No newline at end of file diff --git a/go.mod b/go.mod index b2ab8d4c0..5ff15db7b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6 + github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 @@ -33,8 +33,8 @@ require ( github.com/urfave/cli/v2 v2.25.1 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 golang.org/x/oauth2 v0.7.0 + golang.org/x/sync v0.1.0 gopkg.in/square/go-jose.v2 v2.6.0 - gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gorm.io/driver/postgres v1.5.0 gorm.io/driver/sqlite v1.4.4 gorm.io/gorm v1.25.0 @@ -123,4 +123,5 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect ) diff --git a/go.sum b/go.sum index e0f559ca4..e988c342d 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6 h1:WVmgeHuPN2WHTf/tJtseEMPxPoKdit2rD4nCZyPIias= -github.com/go-vela/types v0.19.3-0.20230516131722-f538de06bbf6/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= +github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f h1:13H381Djx9iFC3BSj2f/ac57HlaI3mQL0el9vM7a3+k= +github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -510,6 +510,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -736,8 +737,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= -gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -765,6 +764,8 @@ k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= +k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/scm/github/repo.go b/scm/github/repo.go index d82c2aeac..b8fa31c3f 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -537,3 +537,22 @@ func (c *client) GetHTMLURL(u *library.User, org, repo, name, ref string) (strin return "", fmt.Errorf("no valid repository contents found") } + +// GetBranch defines a function that retrieves a branch for a repo. +func (c *client) GetBranch(u *library.User, r *library.Repo) (string, string, error) { + c.Logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + "user": u.GetName(), + }).Tracef("retrieving branch %s for repo %s", r.GetBranch(), r.GetFullName()) + + // create GitHub OAuth client with user's token + client := c.newClientToken(u.GetToken()) + + data, _, err := client.Repositories.GetBranch(ctx, r.GetOrg(), r.GetName(), r.GetBranch(), true) + if err != nil { + return "", "", err + } + + return data.GetName(), data.GetCommit().GetSHA(), nil +} diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 3dba1bac3..7482c71ce 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1302,3 +1302,52 @@ func TestGithub_GetPullRequest(t *testing.T) { t.Errorf("HeadRef is %v, want %v", gotHeadRef, wantHeadRef) } } + +func TestGithub_GetBranch(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:owner/:repo/branches/:branch", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/branch.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + u := new(library.User) + u.SetName("foo") + u.SetToken("bar") + + r := new(library.Repo) + r.SetOrg("octocat") + r.SetName("Hello-World") + r.SetFullName("octocat/Hello-World") + r.SetBranch("main") + + wantBranch := "main" + wantCommit := "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d" + + client, _ := NewTest(s.URL) + + // run test + gotBranch, gotCommit, err := client.GetBranch(u, r) + + if err != nil { + t.Errorf("Status returned err: %v", err) + } + + if !strings.EqualFold(gotBranch, wantBranch) { + t.Errorf("Branch is %v, want %v", gotBranch, wantBranch) + } + + if !strings.EqualFold(gotCommit, wantCommit) { + t.Errorf("Commit is %v, want %v", gotCommit, wantCommit) + } +} diff --git a/scm/github/testdata/branch.json b/scm/github/testdata/branch.json new file mode 100644 index 000000000..b133e7b38 --- /dev/null +++ b/scm/github/testdata/branch.json @@ -0,0 +1,101 @@ +{ + "name": "main", + "commit": { + "sha": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d", + "node_id": "MDY6Q29tbWl0MTI5NjI2OTo3ZmQxYTYwYjAxZjkxYjMxNGY1OTk1NWE0ZTRkNGU4MGQ4ZWRmMTFk", + "commit": { + "author": { + "name": "The Octocat", + "email": "octocat@nowhere.com", + "date": "2012-03-06T23:06:50Z" + }, + "committer": { + "name": "The Octocat", + "email": "octocat@nowhere.com", + "date": "2012-03-06T23:06:50Z" + }, + "message": "Merge pull request #6 from Spaceghost/patch-1\n\nNew line at end of file.", + "tree": { + "sha": "b4eecafa9be2f2006ce1b709d6857b07069b4608", + "url": "https://api.github.com/repos/octocat/Hello-World/git/trees/b4eecafa9be2f2006ce1b709d6857b07069b4608" + }, + "url": "https://api.github.com/repos/octocat/Hello-World/git/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d", + "comment_count": 77, + "verification": { + "verified": false, + "reason": "unsigned", + "signature": null, + "payload": null + } + }, + "url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d", + "html_url": "https://github.com/octocat/Hello-World/commit/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d", + "comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d/comments", + "author": { + "login": "octocat", + "id": 583231, + "node_id": "MDQ6VXNlcjU4MzIzMQ==", + "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "committer": { + "login": "octocat", + "id": 583231, + "node_id": "MDQ6VXNlcjU4MzIzMQ==", + "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "parents": [ + { + "sha": "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e", + "url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e", + "html_url": "https://github.com/octocat/Hello-World/commit/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e" + }, + { + "sha": "762941318ee16e59dabbacb1b4049eec22f0d303", + "url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303", + "html_url": "https://github.com/octocat/Hello-World/commit/762941318ee16e59dabbacb1b4049eec22f0d303" + } + ] + }, + "_links": { + "self": "https://api.github.com/repos/octocat/Hello-World/branches/main", + "html": "https://github.com/octocat/Hello-World/tree/main" + }, + "protected": false, + "protection": { + "enabled": false, + "required_status_checks": { + "enforcement_level": "off", + "contexts": [], + "checks": [] + } + }, + "protection_url": "https://api.github.com/repos/octocat/Hello-World/branches/main/protection" +} \ No newline at end of file diff --git a/scm/service.go b/scm/service.go index bb0c0e275..c92cbedbf 100644 --- a/scm/service.go +++ b/scm/service.go @@ -108,6 +108,9 @@ type Service interface { // ListUserRepos defines a function that retrieves // all repos with admin rights for the user. ListUserRepos(*library.User) ([]*library.Repo, error) + // GetBranch defines a function that retrieves + // a branch for a repo. + GetBranch(*library.User, *library.Repo) (string, string, error) // GetPullRequest defines a function that retrieves // a pull request for a repo. GetPullRequest(*library.User, *library.Repo, int) (string, string, string, string, error) From 5f5bfe395886077e5edd1996f3dd30f4196378eb Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 26 May 2023 10:45:32 -0500 Subject: [PATCH 244/298] refactor(database): move build logic into separate package (#858) * chore: save work * chore: save work * feat(database): add build engine * chore(database): remove old service logic * chore: updates for database build engine * chore: address review feedback * fix: updates for scheduler --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- api/admin/build.go | 2 +- api/badge.go | 2 +- api/build.go | 20 +- api/deployment/list.go | 2 +- api/metrics.go | 14 +- api/webhook.go | 12 +- cmd/vela-server/schedule.go | 4 +- database/build/build.go | 80 +++ database/build/build_test.go | 268 +++++++++ database/build/count.go | 25 + database/build/count_deployment.go | 32 + database/build/count_deployment_test.go | 102 ++++ database/build/count_org.go | 31 + database/build/count_org_test.go | 159 +++++ database/build/count_repo.go | 32 + database/build/count_repo_test.go | 104 ++++ database/build/count_status.go | 27 + database/build/count_status_test.go | 97 ++++ database/build/count_test.go | 93 +++ database/build/create.go | 39 ++ database/build/create_test.go | 73 +++ database/build/delete.go | 30 + database/build/delete_test.go | 73 +++ database/build/get.go | 31 + database/build/get_repo.go | 37 ++ database/build/get_repo_test.go | 94 +++ database/build/get_test.go | 85 +++ database/build/index.go | 69 +++ database/build/index_test.go | 62 ++ database/build/interface.go | 61 ++ database/build/last_repo.go | 47 ++ database/build/last_repo_test.go | 95 +++ database/build/list.go | 54 ++ database/build/list_deployment.go | 66 +++ database/build/list_deployment_test.go | 112 ++++ database/build/list_org.go | 69 +++ database/build/list_org_test.go | 204 +++++++ database/build/list_pending_running.go | 46 ++ database/build/list_pending_running_test.go | 131 +++++ database/build/list_repo.go | 69 +++ database/build/list_repo_test.go | 117 ++++ database/build/list_test.go | 103 ++++ database/build/opts.go | 44 ++ database/build/opts_test.go | 161 ++++++ database/build/table.go | 108 ++++ database/build/table_test.go | 59 ++ database/build/update.go | 39 ++ database/build/update_test.go | 75 +++ database/interface.go | 84 +-- database/postgres/build.go | 197 ------- database/postgres/build_count.go | 83 --- database/postgres/build_count_test.go | 345 ----------- database/postgres/build_list.go | 174 ------ database/postgres/build_list_test.go | 459 --------------- database/postgres/build_test.go | 591 ------------------- database/postgres/ddl/build.go | 85 --- database/postgres/ddl/doc.go | 12 - database/postgres/dml/build.go | 90 --- database/postgres/dml/doc.go | 12 - database/postgres/postgres.go | 82 +-- database/postgres/postgres_test.go | 155 +---- database/sqlite/build.go | 197 ------- database/sqlite/build_count.go | 83 --- database/sqlite/build_count_test.go | 439 -------------- database/sqlite/build_list.go | 176 ------ database/sqlite/build_list_test.go | 532 ----------------- database/sqlite/build_test.go | 611 -------------------- database/sqlite/ddl/build.go | 85 --- database/sqlite/ddl/doc.go | 12 - database/sqlite/dml/build.go | 89 --- database/sqlite/dml/doc.go | 12 - database/sqlite/sqlite.go | 82 +-- database/sqlite/sqlite_test.go | 109 ---- router/middleware/build/build.go | 2 +- 74 files changed, 3393 insertions(+), 4764 deletions(-) create mode 100644 database/build/build.go create mode 100644 database/build/build_test.go create mode 100644 database/build/count.go create mode 100644 database/build/count_deployment.go create mode 100644 database/build/count_deployment_test.go create mode 100644 database/build/count_org.go create mode 100644 database/build/count_org_test.go create mode 100644 database/build/count_repo.go create mode 100644 database/build/count_repo_test.go create mode 100644 database/build/count_status.go create mode 100644 database/build/count_status_test.go create mode 100644 database/build/count_test.go create mode 100644 database/build/create.go create mode 100644 database/build/create_test.go create mode 100644 database/build/delete.go create mode 100644 database/build/delete_test.go create mode 100644 database/build/get.go create mode 100644 database/build/get_repo.go create mode 100644 database/build/get_repo_test.go create mode 100644 database/build/get_test.go create mode 100644 database/build/index.go create mode 100644 database/build/index_test.go create mode 100644 database/build/interface.go create mode 100644 database/build/last_repo.go create mode 100644 database/build/last_repo_test.go create mode 100644 database/build/list.go create mode 100644 database/build/list_deployment.go create mode 100644 database/build/list_deployment_test.go create mode 100644 database/build/list_org.go create mode 100644 database/build/list_org_test.go create mode 100644 database/build/list_pending_running.go create mode 100644 database/build/list_pending_running_test.go create mode 100644 database/build/list_repo.go create mode 100644 database/build/list_repo_test.go create mode 100644 database/build/list_test.go create mode 100644 database/build/opts.go create mode 100644 database/build/opts_test.go create mode 100644 database/build/table.go create mode 100644 database/build/table_test.go create mode 100644 database/build/update.go create mode 100644 database/build/update_test.go delete mode 100644 database/postgres/build.go delete mode 100644 database/postgres/build_count.go delete mode 100644 database/postgres/build_count_test.go delete mode 100644 database/postgres/build_list.go delete mode 100644 database/postgres/build_list_test.go delete mode 100644 database/postgres/build_test.go delete mode 100644 database/postgres/ddl/build.go delete mode 100644 database/postgres/ddl/doc.go delete mode 100644 database/postgres/dml/build.go delete mode 100644 database/postgres/dml/doc.go delete mode 100644 database/sqlite/build.go delete mode 100644 database/sqlite/build_count.go delete mode 100644 database/sqlite/build_count_test.go delete mode 100644 database/sqlite/build_list.go delete mode 100644 database/sqlite/build_list_test.go delete mode 100644 database/sqlite/build_test.go delete mode 100644 database/sqlite/ddl/build.go delete mode 100644 database/sqlite/ddl/doc.go delete mode 100644 database/sqlite/dml/build.go delete mode 100644 database/sqlite/dml/doc.go diff --git a/api/admin/build.go b/api/admin/build.go index 28ca14ddf..71a343e88 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -56,7 +56,7 @@ func AllBuildsQueue(c *gin.Context) { after := c.DefaultQuery("after", strconv.FormatInt(time.Now().UTC().Add(-24*time.Hour).Unix(), 10)) // send API call to capture pending and running builds - b, err := database.FromContext(c).GetPendingAndRunningBuilds(after) + b, err := database.FromContext(c).ListPendingAndRunningBuilds(after) if err != nil { retErr := fmt.Errorf("unable to capture all running and pending builds: %w", err) diff --git a/api/badge.go b/api/badge.go index 799de69ab..cdc028e28 100644 --- a/api/badge.go +++ b/api/badge.go @@ -57,7 +57,7 @@ func GetBadge(c *gin.Context) { }).Infof("creating latest build badge for repo %s on branch %s", r.GetFullName(), branch) // send API call to capture the last build for the repo and branch - b, err := database.FromContext(c).GetLastBuildByBranch(r, branch) + b, err := database.FromContext(c).LastBuildForRepo(r, branch) if err != nil { c.String(http.StatusOK, constants.BadgeUnknown) return diff --git a/api/build.go b/api/build.go index 445d4cc8a..cd6c8b86f 100644 --- a/api/build.go +++ b/api/build.go @@ -144,7 +144,7 @@ func CreateBuild(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).GetRepoBuildCount(r, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) if err != nil { retErr := fmt.Errorf("unable to create new build: unable to get count of builds for repo %s", r.GetFullName()) @@ -358,7 +358,7 @@ func CreateBuild(c *gin.Context) { } // send API call to capture the created build - input, _ = database.FromContext(c).GetBuild(input.GetNumber(), r) + input, _ = database.FromContext(c).GetBuildForRepo(r, input.GetNumber()) c.JSON(http.StatusCreated, input) @@ -472,7 +472,7 @@ func GetBuildByID(c *gin.Context) { }).Infof("reading build %d", id) // Get build from database - b, err = database.FromContext(c).GetBuildByID(id) + b, err = database.FromContext(c).GetBuild(id) if err != nil { retErr := fmt.Errorf("unable to get build: %w", err) @@ -725,7 +725,7 @@ func GetBuilds(c *gin.Context) { return } - b, t, err = database.FromContext(c).GetRepoBuildList(r, filters, before, after, page, perPage) + b, t, err = database.FromContext(c).ListBuildsForRepo(r, filters, before, after, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get builds for repo %s: %w", r.GetFullName(), err) @@ -898,7 +898,7 @@ func GetOrgBuilds(c *gin.Context) { } // send API call to capture the list of builds for the org (and event type if passed in) - b, t, err = database.FromContext(c).GetOrgBuildList(o, filters, page, perPage) + b, t, err = database.FromContext(c).ListBuildsForOrg(o, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get builds for org %s: %w", o, err) @@ -1063,7 +1063,7 @@ func RestartBuild(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).GetRepoBuildCount(r, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) if err != nil { retErr := fmt.Errorf("unable to restart build: unable to get count of builds for repo %s", r.GetFullName()) @@ -1287,7 +1287,7 @@ func RestartBuild(c *gin.Context) { } // send API call to capture the restarted build - b, _ = database.FromContext(c).GetBuild(b.GetNumber(), r) + b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) c.JSON(http.StatusCreated, b) @@ -1448,7 +1448,7 @@ func UpdateBuild(c *gin.Context) { } // send API call to capture the updated build - b, _ = database.FromContext(c).GetBuild(b.GetNumber(), r) + b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) c.JSON(http.StatusOK, b) @@ -1533,7 +1533,7 @@ func DeleteBuild(c *gin.Context) { }).Infof("deleting build %s", entry) // send API call to remove the build - err := database.FromContext(c).DeleteBuild(b.GetID()) + err := database.FromContext(c).DeleteBuild(b) if err != nil { retErr := fmt.Errorf("unable to delete build %s: %w", entry, err) @@ -1594,7 +1594,7 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, // send API call to capture the created build // TODO: this can be dropped once we return // the created build above - b, err = database.GetBuild(b.GetNumber(), r) + b, err = database.GetBuildForRepo(r, b.GetNumber()) if err != nil { return fmt.Errorf("unable to get new build for %s: %w", r.GetFullName(), err) } diff --git a/api/deployment/list.go b/api/deployment/list.go index bc5f9e97a..b3745aeca 100644 --- a/api/deployment/list.go +++ b/api/deployment/list.go @@ -138,7 +138,7 @@ func ListDeployments(c *gin.Context) { dWithBs := []*library.Deployment{} for _, deployment := range d { - b, err := database.FromContext(c).GetDeploymentBuildList(*deployment.URL) + b, _, err := database.FromContext(c).ListBuildsForDeployment(deployment, nil, 1, 3) if err != nil { retErr := fmt.Errorf("unable to get builds for deployment %d: %w", deployment.GetID(), err) diff --git a/api/metrics.go b/api/metrics.go index d68ab35e7..d005481b3 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -236,7 +236,7 @@ func recordGauges(c *gin.Context) { // build_count if q.BuildCount { // send API call to capture the total number of builds - b, err := database.FromContext(c).GetBuildCount() + b, err := database.FromContext(c).CountBuilds() if err != nil { logrus.Errorf("unable to get count of all builds: %v", err) } @@ -247,7 +247,7 @@ func recordGauges(c *gin.Context) { // running_build_count if q.RunningBuildCount { // send API call to capture the total number of running builds - bRun, err := database.FromContext(c).GetBuildCountByStatus("running") + bRun, err := database.FromContext(c).CountBuildsForStatus("running", nil) if err != nil { logrus.Errorf("unable to get count of all running builds: %v", err) } @@ -258,7 +258,7 @@ func recordGauges(c *gin.Context) { // pending_build_count if q.PendingBuildCount { // send API call to capture the total number of pending builds - bPen, err := database.FromContext(c).GetBuildCountByStatus("pending") + bPen, err := database.FromContext(c).CountBuildsForStatus("pending", nil) if err != nil { logrus.Errorf("unable to get count of all pending builds: %v", err) } @@ -280,7 +280,7 @@ func recordGauges(c *gin.Context) { // failure_build_count if q.FailureBuildCount { // send API call to capture the total number of failure builds - bFail, err := database.FromContext(c).GetBuildCountByStatus("failure") + bFail, err := database.FromContext(c).CountBuildsForStatus("failure", nil) if err != nil { logrus.Errorf("unable to get count of all failure builds: %v", err) } @@ -291,7 +291,7 @@ func recordGauges(c *gin.Context) { // killed_build_count if q.KilledBuildCount { // send API call to capture the total number of killed builds - bKill, err := database.FromContext(c).GetBuildCountByStatus("killed") + bKill, err := database.FromContext(c).CountBuildsForStatus("killed", nil) if err != nil { logrus.Errorf("unable to get count of all killed builds: %v", err) } @@ -302,7 +302,7 @@ func recordGauges(c *gin.Context) { // success_build_count if q.SuccessBuildCount { // send API call to capture the total number of success builds - bSucc, err := database.FromContext(c).GetBuildCountByStatus("success") + bSucc, err := database.FromContext(c).CountBuildsForStatus("success", nil) if err != nil { logrus.Errorf("unable to get count of all success builds: %v", err) } @@ -313,7 +313,7 @@ func recordGauges(c *gin.Context) { // error_build_count if q.ErrorBuildCount { // send API call to capture the total number of error builds - bErr, err := database.FromContext(c).GetBuildCountByStatus("error") + bErr, err := database.FromContext(c).CountBuildsForStatus("error", nil) if err != nil { logrus.Errorf("unable to get count of all error builds: %v", err) } diff --git a/api/webhook.go b/api/webhook.go index 5f4ddc5bf..6881a03b7 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -15,18 +15,16 @@ import ( "strings" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/queue" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" - - "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) @@ -318,7 +316,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).GetRepoBuildCount(repo, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(repo, filters) if err != nil { retErr := fmt.Errorf("%s: unable to get count of builds for repo %s", baseErr, repo.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -673,7 +671,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the triggered build - b, err = database.FromContext(c).GetBuild(b.GetNumber(), repo) + b, err = database.FromContext(c).GetBuildForRepo(repo, b.GetNumber()) if err != nil { retErr := fmt.Errorf("%s: failed to get new build %s/%d: %w", baseErr, repo.GetFullName(), b.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -942,7 +940,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types } // get total number of builds associated with repository - t, err = database.FromContext(c).GetRepoBuildCount(dbR, nil) + t, err = database.FromContext(c).CountBuildsForRepo(dbR, nil) if err != nil { return nil, fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) } @@ -951,7 +949,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types page = 1 // capture all builds belonging to repo in database for build := int64(0); build < t; build += 100 { - b, _, err := database.FromContext(c).GetRepoBuildList(dbR, nil, time.Now().Unix(), 0, page, 100) + b, _, err := database.FromContext(c).ListBuildsForRepo(dbR, nil, time.Now().Unix(), 0, page, 100) if err != nil { return nil, fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err) } diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 172b5c251..cb607c59b 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -141,7 +141,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // send API call to capture the number of pending or running builds for the repo - builds, err := database.GetRepoBuildCount(r, filters) + builds, err := database.CountBuildsForRepo(r, filters) if err != nil { return fmt.Errorf("unable to get count of builds for repo %s: %w", r.GetFullName(), err) } @@ -362,7 +362,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // send API call to capture the triggered build - b, err = database.GetBuild(b.GetNumber(), r) + b, err = database.GetBuildForRepo(r, b.GetNumber()) if err != nil { return fmt.Errorf("unable to get new build %s/%d: %w", r.GetFullName(), b.GetNumber(), err) } diff --git a/database/build/build.go b/database/build/build.go new file mode 100644 index 000000000..6deb13892 --- /dev/null +++ b/database/build/build.go @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the BuildInterface interface. + config struct { + // specifies to skip creating tables and indexes for the Build engine + SkipCreation bool + } + + // engine represents the build functionality that implements the BuildInterface interface. + engine struct { + // engine configuration settings used in build functions + config *config + + // gorm.io/gorm database client used in build functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in build functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with builds in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new Build engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating build database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of builds table and indexes in the database") + + return e, nil + } + + // create the builds table + err := e.CreateBuildTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) + } + + // create the indexes for the builds table + err = e.CreateBuildIndexes() + if err != nil { + return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableBuild, err) + } + + return e, nil +} diff --git a/database/build/build_test.go b/database/build/build_test.go new file mode 100644 index 000000000..6304cd167 --- /dev/null +++ b/database/build/build_test.go @@ -0,0 +1,268 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestBuild_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{SkipCreation: false}, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new postgres build engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + ) + if err != nil { + t.Errorf("unable to create new sqlite build engine: %v", err) + } + + 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), + } +} + +// testDeployment is a test helper function to create a library +// Repo type with all fields set to their zero values. +func testDeployment() *library.Deployment { + return &library.Deployment{ + ID: new(int64), + RepoID: new(int64), + URL: new(string), + User: new(string), + Commit: new(string), + Ref: new(string), + Task: new(string), + Target: new(string), + Description: new(string), + } +} + +// testRepo is a test helper function to create a library +// Repo type with all fields set to their zero values. +func testRepo() *library.Repo { + return &library.Repo{ + ID: new(int64), + UserID: 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), + AllowPull: new(bool), + AllowPush: new(bool), + AllowDeploy: new(bool), + AllowTag: new(bool), + AllowComment: 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(v driver.Value) bool { + return true +} diff --git a/database/build/count.go b/database/build/count.go new file mode 100644 index 000000000..7700c5786 --- /dev/null +++ b/database/build/count.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" +) + +// CountBuilds gets the count of all builds from the database. +func (e *engine) CountBuilds() (int64, error) { + e.logger.Tracef("getting count of all builds from the database") + + // variable to store query results + var b int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Count(&b). + Error + + return b, err +} diff --git a/database/build/count_deployment.go b/database/build/count_deployment.go new file mode 100644 index 000000000..6203f196b --- /dev/null +++ b/database/build/count_deployment.go @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountBuildsForDeployment gets the count of builds by deployment URL from the database. +func (e *engine) CountBuildsForDeployment(d *library.Deployment, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "deployment": d.GetURL(), + }).Tracef("getting count of builds for deployment %s from the database", d.GetURL()) + + // variable to store query results + var b int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("source = ?", d.GetURL()). + Where(filters). + Order("number DESC"). + Count(&b). + Error + + return b, err +} diff --git a/database/build/count_deployment_test.go b/database/build/count_deployment_test.go new file mode 100644 index 000000000..53c0c1df6 --- /dev/null +++ b/database/build/count_deployment_test.go @@ -0,0 +1,102 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CountBuildsForDeployment(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetSource("https://github.com/github/octocat/deployments/1") + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetSource("https://github.com/github/octocat/deployments/1") + + _deployment := testDeployment() + _deployment.SetID(1) + _deployment.SetRepoID(1) + _deployment.SetURL("https://github.com/github/octocat/deployments/1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE source = $1`).WithArgs("https://github.com/github/octocat/deployments/1").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountBuildsForDeployment(_deployment, filters) + + if test.failure { + if err == nil { + t.Errorf("CountBuildsForDeployment for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountBuildsForDeployment for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountBuildsForDeployment for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/count_org.go b/database/build/count_org.go new file mode 100644 index 000000000..37825bad6 --- /dev/null +++ b/database/build/count_org.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// CountBuildsForOrg gets the count of builds by org name from the database. +func (e *engine) CountBuildsForOrg(org string, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": org, + }).Tracef("getting count of builds for org %s from the database", org) + + // variable to store query results + var b int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Joins("JOIN repos ON builds.repo_id = repos.id"). + Where("repos.org = ?", org). + Where(filters). + Count(&b). + Error + + return b, err +} diff --git a/database/build/count_org_test.go b/database/build/count_org_test.go new file mode 100644 index 000000000..429149e54 --- /dev/null +++ b/database/build/count_org_test.go @@ -0,0 +1,159 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" +) + +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") + + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + _repoOne.SetTopics([]string{}) + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("bar") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + _repoTwo.SetTopics([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result without filters in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + // ensure the mock expects the query without filters + _mock.ExpectQuery(`SELECT count(*) FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1`).WithArgs("foo").WillReturnRows(_rows) + + // create expected result with event filter in mock + _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) + // ensure the mock expects the query with event filter + _mock.ExpectQuery(`SELECT count(*) FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 AND "event" = $2`).WithArgs("foo", "push").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&database.Repo{}) + if err != nil { + t.Errorf("unable to create repo table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(database.RepoFromLibrary(_repoOne)).Error + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(database.RepoFromLibrary(_repoTwo)).Error + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + filters map[string]interface{} + want int64 + }{ + { + failure: false, + name: "postgres without filters", + database: _postgres, + filters: map[string]interface{}{}, + want: 2, + }, + { + failure: false, + name: "postgres with event filter", + database: _postgres, + filters: map[string]interface{}{ + "event": "push", + }, + want: 2, + }, + { + failure: false, + name: "sqlite3 without filters", + database: _sqlite, + filters: map[string]interface{}{}, + want: 2, + }, + { + failure: false, + name: "sqlite3 with event filter", + database: _sqlite, + filters: map[string]interface{}{ + "event": "push", + }, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountBuildsForOrg("foo", test.filters) + + if test.failure { + if err == nil { + t.Errorf("CountBuildsForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountBuildsForOrg for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountBuildsForOrg for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/count_repo.go b/database/build/count_repo.go new file mode 100644 index 000000000..b49a415e0 --- /dev/null +++ b/database/build/count_repo.go @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CountBuildsForRepo gets the count of builds by repo ID from the database. +func (e *engine) CountBuildsForRepo(r *library.Repo, filters map[string]interface{}) (int64, error) { + e.logger.WithFields(logrus.Fields{ + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting count of builds for repo %s from the database", r.GetFullName()) + + // variable to store query results + var b int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("repo_id = ?", r.GetID()). + Where(filters). + Count(&b). + Error + + return b, err +} diff --git a/database/build/count_repo_test.go b/database/build/count_repo_test.go new file mode 100644 index 000000000..673887183 --- /dev/null +++ b/database/build/count_repo_test.go @@ -0,0 +1,104 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +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) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountBuildsForRepo(_repo, filters) + + if test.failure { + if err == nil { + t.Errorf("CountBuildsForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountBuildsForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountBuildsForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/count_status.go b/database/build/count_status.go new file mode 100644 index 000000000..af6a9f957 --- /dev/null +++ b/database/build/count_status.go @@ -0,0 +1,27 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" +) + +// CountBuildsForStatus gets the count of builds by status from the database. +func (e *engine) CountBuildsForStatus(status string, filters map[string]interface{}) (int64, error) { + e.logger.Tracef("getting count of builds for status %s from the database", status) + + // variable to store query results + var b int64 + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("status = ?", status). + Where(filters). + Count(&b). + Error + + return b, err +} diff --git a/database/build/count_status_test.go b/database/build/count_status_test.go new file mode 100644 index 000000000..f88759d1c --- /dev/null +++ b/database/build/count_status_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CountBuildsForStatus(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetStatus("running") + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetStatus("running") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE status = $1`).WithArgs("running").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountBuildsForStatus("running", filters) + + if test.failure { + if err == nil { + t.Errorf("CountBuildsForStatus for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountBuildsForStatus for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountBuildsForStatus for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/count_test.go b/database/build/count_test.go new file mode 100644 index 000000000..6254648ee --- /dev/null +++ b/database/build/count_test.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CountBuilds(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) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "builds"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CountBuilds() + + if test.failure { + if err == nil { + t.Errorf("CountBuilds for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CountBuilds for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CountBuilds for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/create.go b/database/build/create.go new file mode 100644 index 000000000..911c6f148 --- /dev/null +++ b/database/build/create.go @@ -0,0 +1,39 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with update.go +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateBuild creates a new build in the database. +func (e *engine) CreateBuild(b *library.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) + + // 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 err + } + + // send query to the database + return e.client. + Table(constants.TableBuild). + Create(build.Crop()). + Error +} diff --git a/database/build/create_test.go b/database/build/create_test.go new file mode 100644 index 000000000..3cfe1fdf9 --- /dev/null +++ b/database/build/create_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CreateBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "builds" +("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","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31) RETURNING "id"`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateBuild(_build) + + if test.failure { + if err == nil { + t.Errorf("CreateBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateBuild for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/build/delete.go b/database/build/delete.go new file mode 100644 index 000000000..76643eed1 --- /dev/null +++ b/database/build/delete.go @@ -0,0 +1,30 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// DeleteBuild deletes an existing build from the database. +func (e *engine) DeleteBuild(b *library.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) + + // send query to the database + return e.client. + Table(constants.TableBuild). + Delete(build). + Error +} diff --git a/database/build/delete_test.go b/database/build/delete_test.go new file mode 100644 index 000000000..91dd1c9c7 --- /dev/null +++ b/database/build/delete_test.go @@ -0,0 +1,73 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_DeleteBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`DELETE FROM "builds" WHERE "builds"."id" = $1`). + WithArgs(1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_build) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.DeleteBuild(_build) + + if test.failure { + if err == nil { + t.Errorf("DeleteBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("DeleteBuild for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/build/get.go b/database/build/get.go new file mode 100644 index 000000000..236d62cca --- /dev/null +++ b/database/build/get.go @@ -0,0 +1,31 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "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(id int64) (*library.Build, error) { + e.logger.Tracef("getting build %d from the database", id) + + // variable to store query results + b := new(database.Build) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("id = ?", id). + Take(b). + Error + if err != nil { + return nil, err + } + + return b.ToLibrary(), nil +} diff --git a/database/build/get_repo.go b/database/build/get_repo.go new file mode 100644 index 000000000..8d93dcb3c --- /dev/null +++ b/database/build/get_repo.go @@ -0,0 +1,37 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// GetBuildForRepo gets a build by repo ID and number from the database. +func (e *engine) GetBuildForRepo(r *library.Repo, number int) (*library.Build, error) { + e.logger.WithFields(logrus.Fields{ + "build": number, + "org": r.GetOrg(), + "repo": r.GetName(), + }).Tracef("getting build %s/%d from the database", r.GetFullName(), number) + + // variable to store query results + b := new(database.Build) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("repo_id = ?", r.GetID()). + Where("number = ?", number). + Take(b). + Error + if err != nil { + return nil, err + } + + return b.ToLibrary(), nil +} diff --git a/database/build/get_repo_test.go b/database/build/get_repo_test.go new file mode 100644 index 000000000..f1341d960 --- /dev/null +++ b/database/build/get_repo_test.go @@ -0,0 +1,94 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_GetBuildForRepo(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND number = $2 LIMIT 1`).WithArgs(1, 1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_build) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _build, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _build, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetBuildForRepo(_repo, 1) + + if test.failure { + if err == nil { + t.Errorf("GetBuildForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + 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) + } + }) + } +} diff --git a/database/build/get_test.go b/database/build/get_test.go new file mode 100644 index 000000000..7aec15f13 --- /dev/null +++ b/database/build/get_test.go @@ -0,0 +1,85 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_GetBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "builds" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_build) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _build, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _build, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.GetBuild(1) + + if test.failure { + if err == nil { + t.Errorf("GetBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("GetBuild for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("GetBuild for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/index.go b/database/build/index.go new file mode 100644 index 000000000..77e15e451 --- /dev/null +++ b/database/build/index.go @@ -0,0 +1,69 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +const ( + // CreateCreatedIndex represents a query to create an + // index on the builds table for the created column. + CreateCreatedIndex = ` +CREATE INDEX +IF NOT EXISTS +builds_created +ON builds (created); +` + + // CreateRepoIDIndex represents a query to create an + // index on the builds table for the repo_id column. + CreateRepoIDIndex = ` +CREATE INDEX +IF NOT EXISTS +builds_repo_id +ON builds (repo_id); +` + + // CreateSourceIndex represents a query to create an + // index on the builds table for the source column. + CreateSourceIndex = ` +CREATE INDEX +IF NOT EXISTS +builds_source +ON builds (source); +` + + // CreateStatusIndex represents a query to create an + // index on the builds table for the status column. + CreateStatusIndex = ` +CREATE INDEX +IF NOT EXISTS +builds_status +ON builds (status); +` +) + +// CreateBuildIndexes creates the indexes for the builds table in the database. +func (e *engine) CreateBuildIndexes() error { + e.logger.Tracef("creating indexes for builds table in the database") + + // create the created column index for the builds table + err := e.client.Exec(CreateCreatedIndex).Error + if err != nil { + return err + } + + // create the repo_id column index for the builds table + err = e.client.Exec(CreateRepoIDIndex).Error + if err != nil { + return err + } + + // create the source column index for the builds table + err = e.client.Exec(CreateSourceIndex).Error + if err != nil { + return err + } + + // create the status column index for the builds table + return e.client.Exec(CreateStatusIndex).Error +} diff --git a/database/build/index_test.go b/database/build/index_test.go new file mode 100644 index 000000000..bd61ff5d2 --- /dev/null +++ b/database/build/index_test.go @@ -0,0 +1,62 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CreateBuildIndexes(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateBuildIndexes() + + if test.failure { + if err == nil { + t.Errorf("CreateBuildIndexes for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateBuildIndexes for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/build/interface.go b/database/build/interface.go new file mode 100644 index 000000000..e4264f6a8 --- /dev/null +++ b/database/build/interface.go @@ -0,0 +1,61 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/library" +) + +// BuildInterface represents the Vela interface for build +// functions with the supported Database backends. +// +//nolint:revive // ignore name stutter +type BuildInterface interface { + // Build Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + + // CreateBuildIndexes defines a function that creates the indexes for the builds table. + CreateBuildIndexes() error + // CreateBuildTable defines a function that creates the builds table. + CreateBuildTable(string) error + + // Build Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CountBuilds defines a function that gets the count of all builds. + CountBuilds() (int64, error) + // CountBuildsForDeployment defines a function that gets the count of builds by deployment url. + CountBuildsForDeployment(*library.Deployment, map[string]interface{}) (int64, error) + // CountBuildsForOrg defines a function that gets the count of builds by org name. + CountBuildsForOrg(string, map[string]interface{}) (int64, error) + // CountBuildsForRepo defines a function that gets the count of builds by repo ID. + CountBuildsForRepo(*library.Repo, map[string]interface{}) (int64, error) + // CountBuildsForStatus defines a function that gets the count of builds by status. + CountBuildsForStatus(string, map[string]interface{}) (int64, error) + // CreateBuild defines a function that creates a new build. + CreateBuild(*library.Build) error + // DeleteBuild defines a function that deletes an existing build. + DeleteBuild(*library.Build) error + // GetBuild defines a function that gets a build by ID. + GetBuild(int64) (*library.Build, error) + // GetBuildForRepo defines a function that gets a build by repo ID and number. + GetBuildForRepo(*library.Repo, int) (*library.Build, error) + // LastBuildForRepo defines a function that gets the last build ran by repo ID and branch. + LastBuildForRepo(*library.Repo, string) (*library.Build, error) + // ListBuilds defines a function that gets a list of all builds. + ListBuilds() ([]*library.Build, error) + // ListBuildsForDeployment defines a function that gets a list of builds by deployment url. + ListBuildsForDeployment(*library.Deployment, map[string]interface{}, int, int) ([]*library.Build, int64, error) + // ListBuildsForOrg defines a function that gets a list of builds by org name. + ListBuildsForOrg(string, map[string]interface{}, int, int) ([]*library.Build, int64, error) + // ListBuildsForRepo defines a function that gets a list of builds by repo ID. + ListBuildsForRepo(*library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) + // ListPendingAndRunningBuilds defines a function that gets a list of pending and running builds. + ListPendingAndRunningBuilds(string) ([]*library.BuildQueue, error) + // UpdateBuild defines a function that updates an existing build. + UpdateBuild(*library.Build) error +} diff --git a/database/build/last_repo.go b/database/build/last_repo.go new file mode 100644 index 000000000..ed0adebbf --- /dev/null +++ b/database/build/last_repo.go @@ -0,0 +1,47 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "errors" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// LastBuildForRepo gets the last build by repo ID and branch from the database. +func (e *engine) LastBuildForRepo(r *library.Repo, branch string) (*library.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) + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Where("repo_id = ?", r.GetID()). + Where("branch = ?", branch). + Order("number DESC"). + Take(b). + Error + if err != nil { + // check if the query returned a record not found error + if errors.Is(err, gorm.ErrRecordNotFound) { + // the record will not exist if it is a new repo + return nil, nil + } + + return nil, err + } + + return b.ToLibrary(), nil +} diff --git a/database/build/last_repo_test.go b/database/build/last_repo_test.go new file mode 100644 index 000000000..48cb32c01 --- /dev/null +++ b/database/build/last_repo_test.go @@ -0,0 +1,95 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +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("master") + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "master", "", "", "", "", "", "", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND branch = $2 ORDER BY number DESC LIMIT 1`).WithArgs(1, "master").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_build) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _build, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _build, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.LastBuildForRepo(_repo, "master") + + if test.failure { + if err == nil { + t.Errorf("LastBuildForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("LastBuildForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("LastBuildForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/list.go b/database/build/list.go new file mode 100644 index 000000000..1139cf490 --- /dev/null +++ b/database/build/list.go @@ -0,0 +1,54 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "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() ([]*library.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{} + + // count the results + count, err := e.CountBuilds() + if err != nil { + return nil, err + } + + // short-circuit if there are no results + if count == 0 { + return builds, nil + } + + // send query to the database and store result in variable + err = e.client. + Table(constants.TableBuild). + Find(&b). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, build := range *b { + // 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()) + } + + return builds, nil +} diff --git a/database/build/list_deployment.go b/database/build/list_deployment.go new file mode 100644 index 000000000..ff397f2ae --- /dev/null +++ b/database/build/list_deployment.go @@ -0,0 +1,66 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// ListBuildsForDeployment gets a list of builds by deployment url from the database. +// +//nolint:lll // ignore long line length due to variable names +func (e *engine) ListBuildsForDeployment(d *library.Deployment, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { + e.logger.WithFields(logrus.Fields{ + "deployment": d.GetURL(), + }).Tracef("listing builds for deployment %s from the database", d.GetURL()) + + // variables to store query results and return values + count := int64(0) + b := new([]database.Build) + builds := []*library.Build{} + + // count the results + count, err := e.CountBuildsForDeployment(d, filters) + if err != nil { + return builds, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return builds, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + err = e.client. + Table(constants.TableBuild). + Where("source = ?", d.GetURL()). + Where(filters). + Order("number DESC"). + Limit(perPage). + Offset(offset). + Find(&b). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, build := range *b { + // 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()) + } + + return builds, count, nil +} diff --git a/database/build/list_deployment_test.go b/database/build/list_deployment_test.go new file mode 100644 index 000000000..94983c56e --- /dev/null +++ b/database/build/list_deployment_test.go @@ -0,0 +1,112 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_ListBuildsForDeployment(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetSource("https://github.com/github/octocat/deployments/1") + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetSource("https://github.com/github/octocat/deployments/1") + + _deployment := testDeployment() + _deployment.SetID(1) + _deployment.SetRepoID(1) + _deployment.SetURL("https://github.com/github/octocat/deployments/1") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the count query + _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE source = $1`).WithArgs("https://github.com/github/octocat/deployments/1").WillReturnRows(_rows) + + // create expected query result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "builds" WHERE source = $1 ORDER BY number DESC LIMIT 10`).WithArgs("https://github.com/github/octocat/deployments/1").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Build{_buildTwo, _buildOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Build{_buildTwo, _buildOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListBuildsForDeployment(_deployment, filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListBuildsForDeployment for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListBuildsForDeployment for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListBuildsForDeployment for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/list_org.go b/database/build/list_org.go new file mode 100644 index 000000000..8f4e62e58 --- /dev/null +++ b/database/build/list_org.go @@ -0,0 +1,69 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// 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(org string, filters map[string]interface{}, page, perPage int) ([]*library.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{} + + // count the results + count, err := e.CountBuildsForOrg(org, filters) + if err != nil { + return builds, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return builds, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + err = e.client. + Table(constants.TableBuild). + Select("builds.*"). + Joins("JOIN repos ON builds.repo_id = repos.id"). + Where("repos.org = ?", org). + Where(filters). + Order("created DESC"). + Order("id"). + Limit(perPage). + Offset(offset). + Find(&b). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, build := range *b { + // 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()) + } + + return builds, count, nil +} diff --git a/database/build/list_org_test.go b/database/build/list_org_test.go new file mode 100644 index 000000000..e9121e024 --- /dev/null +++ b/database/build/list_org_test.go @@ -0,0 +1,204 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "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") + + _repoOne := testRepo() + _repoOne.SetID(1) + _repoOne.SetUserID(1) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + _repoOne.SetTopics([]string{}) + + _repoTwo := testRepo() + _repoTwo.SetID(2) + _repoTwo.SetUserID(1) + _repoTwo.SetHash("bar") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + _repoTwo.SetTopics([]string{}) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected count query without filters result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + // ensure the mock expects the count query without filters + _mock.ExpectQuery(`SELECT count(*) FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1`).WithArgs("foo").WillReturnRows(_rows) + // create expected query without filters result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + // 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 10`).WithArgs("foo").WillReturnRows(_rows) + + // create expected count query with event filter result in mock + _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) + // ensure the mock expects the count query with event filter + _mock.ExpectQuery(`SELECT count(*) FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 AND "event" = $2`).WithArgs("foo", "push").WillReturnRows(_rows) + // create expected query with event filter result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + // 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 10`).WithArgs("foo", "push").WillReturnRows(_rows) + + // create expected count query with visibility filter result in mock + _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) + // ensure the mock expects the count query with visibility filter + _mock.ExpectQuery(`SELECT count(*) FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 AND "visibility" = $2`).WithArgs("foo", "public").WillReturnRows(_rows) + // create expected query with visibility filter result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + // 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 10`).WithArgs("foo", "public").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&database.Repo{}) + if err != nil { + t.Errorf("unable to create repo table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(database.RepoFromLibrary(_repoOne)).Error + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(database.RepoFromLibrary(_repoTwo)).Error + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + filters map[string]interface{} + want []*library.Build + }{ + { + failure: false, + name: "postgres without filters", + database: _postgres, + filters: map[string]interface{}{}, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "postgres with event filter", + database: _postgres, + filters: map[string]interface{}{ + "event": "push", + }, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "postgres with visibility filter", + database: _postgres, + filters: map[string]interface{}{ + "visibility": "public", + }, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "sqlite3 without filters", + database: _sqlite, + filters: map[string]interface{}{}, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "sqlite3 with event filter", + database: _sqlite, + filters: map[string]interface{}{ + "event": "push", + }, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "sqlite3 with visibility filter", + database: _sqlite, + filters: map[string]interface{}{ + "visibility": "public", + }, + want: []*library.Build{_buildOne, _buildTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListBuildsForOrg("foo", test.filters, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListBuildsForOrg for %s should have returned err", test.name) + } + + return + } + + if err != nil { + 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) + } + }) + } +} diff --git a/database/build/list_pending_running.go b/database/build/list_pending_running.go new file mode 100644 index 000000000..bd2a219b5 --- /dev/null +++ b/database/build/list_pending_running.go @@ -0,0 +1,46 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "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(after string) ([]*library.BuildQueue, 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{} + + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuild). + Select("builds.created, builds.number, builds.status, repos.full_name"). + InnerJoins("INNER JOIN repos ON builds.repo_id = repos.id"). + Where("builds.created > ?", after). + Where("builds.status = 'running' OR builds.status = 'pending'"). + Find(&b). + Error + if err != nil { + return nil, err + } + + // iterate through all query results + for _, build := range *b { + // 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()) + } + + return builds, nil +} diff --git a/database/build/list_pending_running_test.go b/database/build/list_pending_running_test.go new file mode 100644 index 000000000..8d47dc63b --- /dev/null +++ b/database/build/list_pending_running_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetStatus("running") + _buildOne.SetCreated(1) + _buildOne.SetDeployPayload(nil) + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetStatus("pending") + _buildTwo.SetCreated(1) + _buildTwo.SetDeployPayload(nil) + + _queueOne := new(library.BuildQueue) + _queueOne.SetCreated(1) + _queueOne.SetFullName("foo/bar") + _queueOne.SetNumber(1) + _queueOne.SetStatus("running") + + _queueTwo := new(library.BuildQueue) + _queueTwo.SetCreated(1) + _queueTwo.SetFullName("foo/bar") + _queueTwo.SetNumber(2) + _queueTwo.SetStatus("pending") + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // create expected name query result in mock + _rows := sqlmock.NewRows([]string{"created", "full_name", "number", "status"}).AddRow(1, "foo/bar", 2, "pending").AddRow(1, "foo/bar", 1, "running") + + // ensure the mock expects the name query + _mock.ExpectQuery(`SELECT builds.created, builds.number, builds.status, repos.full_name FROM "builds" INNER JOIN repos ON builds.repo_id = repos.id WHERE builds.created > $1 AND (builds.status = 'running' OR builds.status = 'pending')`).WithArgs("0").WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&database.Repo{}) + if err != nil { + t.Errorf("unable to create repo table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(database.RepoFromLibrary(_repo)).Error + if err != nil { + t.Errorf("unable to create test repo for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.BuildQueue + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.BuildQueue{_queueTwo, _queueOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.BuildQueue{_queueTwo, _queueOne}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListPendingAndRunningBuilds("0") + + if test.failure { + if err == nil { + t.Errorf("ListPendingAndRunningBuilds for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListPendingAndRunningBuilds for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListPendingAndRunningBuilds for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/list_repo.go b/database/build/list_repo.go new file mode 100644 index 000000000..83ebd4adb --- /dev/null +++ b/database/build/list_repo.go @@ -0,0 +1,69 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// 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(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, 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 + count := int64(0) + b := new([]database.Build) + builds := []*library.Build{} + + // count the results + count, err := e.CountBuildsForRepo(r, filters) + if err != nil { + return builds, 0, err + } + + // short-circuit if there are no results + if count == 0 { + return builds, 0, nil + } + + // calculate offset for pagination through results + offset := perPage * (page - 1) + + err = e.client. + Table(constants.TableBuild). + Where("repo_id = ?", r.GetID()). + Where("created < ?", before). + Where("created > ?", after). + Where(filters). + Order("number DESC"). + Limit(perPage). + Offset(offset). + Find(&b). + Error + if err != nil { + return nil, count, err + } + + // iterate through all query results + for _, build := range *b { + // 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()) + } + + return builds, count, nil +} diff --git a/database/build/list_repo_test.go b/database/build/list_repo_test.go new file mode 100644 index 000000000..ac367e414 --- /dev/null +++ b/database/build/list_repo_test.go @@ -0,0 +1,117 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetCreated(1) + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetCreated(2) + + _repo := testRepo() + _repo.SetID(1) + _repo.SetUserID(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() }() + + // create expected count query result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the count query + _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE repo_id = $1`).WithArgs(1).WillReturnRows(_rows) + + // create expected query result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // 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 10`).WithArgs(1, AnyArgument{}, 0).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Build{_buildTwo, _buildOne}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Build{_buildTwo, _buildOne}, + }, + } + + filters := map[string]interface{}{} + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, _, err := test.database.ListBuildsForRepo(_repo, filters, time.Now().UTC().Unix(), 0, 1, 10) + + if test.failure { + if err == nil { + t.Errorf("ListBuildsForRepo for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListBuildsForRepo for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListBuildsForRepo for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/list_test.go b/database/build/list_test.go new file mode 100644 index 000000000..b0e441387 --- /dev/null +++ b/database/build/list_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestBuild_Engine_ListBuilds(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) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT count(*) FROM "builds"`).WillReturnRows(_rows) + + // create expected result in mock + _rows = sqlmock.NewRows( + []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", "timestamp"}). + AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). + AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + + // ensure the mock expects the query + _mock.ExpectQuery(`SELECT * FROM "builds"`).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want []*library.Build + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: []*library.Build{_buildOne, _buildTwo}, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: []*library.Build{_buildOne, _buildTwo}, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.ListBuilds() + + if test.failure { + if err == nil { + t.Errorf("ListBuilds for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("ListBuilds for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ListBuilds for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/opts.go b/database/build/opts.go new file mode 100644 index 000000000..d5a5d4137 --- /dev/null +++ b/database/build/opts.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for Builds. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for Builds. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the build engine + e.client = client + + 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 { + // set the github.com/sirupsen/logrus logger in the build engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for Builds. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the build engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/build/opts_test.go b/database/build/opts_test.go new file mode 100644 index 000000000..2d41cc676 --- /dev/null +++ b/database/build/opts_test.go @@ -0,0 +1,161 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestBuild_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestBuild_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestBuild_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/build/table.go b/database/build/table.go new file mode 100644 index 000000000..faf76746f --- /dev/null +++ b/database/build/table.go @@ -0,0 +1,108 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import "github.com/go-vela/types/constants" + +const ( + // CreatePostgresTable represents a query to create the Postgres builds table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +builds ( + id SERIAL PRIMARY KEY, + repo_id INTEGER, + pipeline_id INTEGER, + number INTEGER, + parent INTEGER, + event VARCHAR(250), + event_action VARCHAR(250), + status VARCHAR(250), + error VARCHAR(1000), + enqueued INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + deploy VARCHAR(500), + deploy_payload VARCHAR(2000), + clone VARCHAR(1000), + source VARCHAR(1000), + title VARCHAR(1000), + message VARCHAR(2000), + commit VARCHAR(500), + sender VARCHAR(250), + author VARCHAR(250), + email VARCHAR(500), + link VARCHAR(1000), + branch VARCHAR(500), + ref VARCHAR(500), + base_ref VARCHAR(500), + head_ref VARCHAR(500), + host VARCHAR(250), + runtime VARCHAR(250), + distribution VARCHAR(250), + timestamp INTEGER, + UNIQUE(repo_id, number) +); +` + + // CreateSqliteTable represents a query to create the Sqlite builds table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +builds ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + repo_id INTEGER, + pipeline_id INTEGER, + number INTEGER, + parent INTEGER, + event TEXT, + event_action TEXT, + status TEXT, + error TEXT, + enqueued INTEGER, + created INTEGER, + started INTEGER, + finished INTEGER, + deploy TEXT, + deploy_payload TEXT, + clone TEXT, + source TEXT, + title TEXT, + message TEXT, + 'commit' TEXT, + sender TEXT, + author TEXT, + email TEXT, + link TEXT, + branch TEXT, + ref TEXT, + base_ref TEXT, + head_ref TEXT, + host TEXT, + runtime TEXT, + distribution TEXT, + timestamp INTEGER, + UNIQUE(repo_id, number) +); +` +) + +// CreateBuildTable creates the builds table in the database. +func (e *engine) CreateBuildTable(driver string) error { + e.logger.Tracef("creating builds table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the builds table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the builds table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/build/table_test.go b/database/build/table_test.go new file mode 100644 index 000000000..394a1287e --- /dev/null +++ b/database/build/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CreateBuildTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateBuildTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateBuildTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateBuildTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/build/update.go b/database/build/update.go new file mode 100644 index 000000000..d16329419 --- /dev/null +++ b/database/build/update.go @@ -0,0 +1,39 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +//nolint:dupl // ignore similar code with create.go +package build + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// UpdateBuild updates an existing build in the database. +func (e *engine) UpdateBuild(b *library.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) + + // 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 err + } + + // send query to the database + return e.client. + Table(constants.TableBuild). + Save(build.Crop()). + Error +} diff --git a/database/build/update_test.go b/database/build/update_test.go new file mode 100644 index 000000000..98ac9ae16 --- /dev/null +++ b/database/build/update_test.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_UpdateBuild(t *testing.T) { + // setup types + _build := testBuild() + _build.SetID(1) + _build.SetRepoID(1) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "builds" +SET "repo_id"=$1,"pipeline_id"=$2,"number"=$3,"parent"=$4,"event"=$5,"event_action"=$6,"status"=$7,"error"=$8,"enqueued"=$9,"created"=$10,"started"=$11,"finished"=$12,"deploy"=$13,"deploy_payload"=$14,"clone"=$15,"source"=$16,"title"=$17,"message"=$18,"commit"=$19,"sender"=$20,"author"=$21,"email"=$22,"link"=$23,"branch"=$24,"ref"=$25,"base_ref"=$26,"head_ref"=$27,"host"=$28,"runtime"=$29,"distribution"=$30 +WHERE "id" = $31`). + WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_build) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateBuild(_build) + + if test.failure { + if err == nil { + t.Errorf("UpdateBuild for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateBuild for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/interface.go b/database/interface.go index 9a2177b14..975206c93 100644 --- a/database/interface.go +++ b/database/interface.go @@ -5,6 +5,7 @@ package database import ( + "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -15,7 +16,6 @@ import ( "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" - "github.com/go-vela/types/library" ) // Interface represents the interface for Vela integrating @@ -27,94 +27,36 @@ type Interface interface { // the configured database driver. Driver() string - // Build Database Interface Functions + // BuildInterface defines the interface for builds stored in the database. + build.BuildInterface - // GetBuild defines a function that - // gets a build by number and repo ID. - GetBuild(int, *library.Repo) (*library.Build, error) - // GetBuildByID defines a function that - // gets a build by its id. - GetBuildByID(int64) (*library.Build, error) - // GetLastBuild defines a function that - // gets the last build ran by repo ID. - GetLastBuild(*library.Repo) (*library.Build, error) - // GetLastBuildByBranch defines a function that - // gets the last build ran by repo ID and branch. - GetLastBuildByBranch(*library.Repo, string) (*library.Build, error) - // GetBuildCount defines a function that - // gets the count of builds. - GetBuildCount() (int64, error) - // GetBuildCountByStatus defines a function that - // gets a the count of builds by status. - GetBuildCountByStatus(string) (int64, error) - // GetBuildList defines a function that gets - // a list of all builds. - GetBuildList() ([]*library.Build, error) - // GetDeploymentBuildList defines a function that gets - // a list of builds related to a deployment. - GetDeploymentBuildList(string) ([]*library.Build, error) - // GetRepoBuildList defines a function that - // gets a list of builds by repo ID. - GetRepoBuildList(*library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) - // GetOrgBuildList defines a function that - // gets a list of builds by org. - GetOrgBuildList(string, map[string]interface{}, int, int) ([]*library.Build, int64, error) - // GetRepoBuildCount defines a function that - // gets the count of builds by repo ID. - GetRepoBuildCount(*library.Repo, map[string]interface{}) (int64, error) - // GetOrgBuildCount defines a function that - // gets the count of builds by org. - GetOrgBuildCount(string, map[string]interface{}) (int64, error) - // GetPendingAndRunningBuilds defines a function that - // gets the list of pending and running builds. - GetPendingAndRunningBuilds(string) ([]*library.BuildQueue, error) - // CreateBuild defines a function that - // creates a new build. - CreateBuild(*library.Build) error - // UpdateBuild defines a function that - // updates a build. - UpdateBuild(*library.Build) error - // DeleteBuild defines a function that - // deletes a build by unique ID. - DeleteBuild(int64) error - - // HookInterface provides the interface for functionality - // related to hooks stored in the database. + // HookInterface defines the interface for hooks stored in the database. hook.HookInterface - // LogInterface provides the interface for functionality - // related to logs stored in the database. + // LogInterface defines the interface for logs stored in the database. log.LogInterface - // PipelineInterface provides the interface for functionality - // related to pipelines stored in the database. + // PipelineInterface defines the interface for pipelines stored in the database. pipeline.PipelineInterface - // RepoInterface provides the interface for functionality - // related to repos stored in the database. + // RepoInterface defines the interface for repos stored in the database. repo.RepoInterface - // ScheduleInterface provides the interface for functionality - // related to schedules stored in the database. + // ScheduleInterface defines the interface for schedules stored in the database. schedule.ScheduleInterface - // SecretInterface provides the interface for functionality - // related to secrets stored in the database. + // SecretInterface defines the interface for secrets stored in the database. secret.SecretInterface - // ServiceInterface provides the interface for functionality - // related to services stored in the database. + // ServiceInterface defines the interface for services stored in the database. service.ServiceInterface - // StepInterface provides the interface for functionality - // related to steps stored in the database. + // StepInterface defines the interface for steps stored in the database. step.StepInterface - // UserInterface provides the interface for functionality - // related to users stored in the database. + // UserInterface defines the interface for users stored in the database. user.UserInterface - // WorkerInterface provides the interface for functionality - // related to workers stored in the database. + // WorkerInterface defines the interface for workers stored in the database. worker.WorkerInterface } diff --git a/database/postgres/build.go b/database/postgres/build.go deleted file mode 100644 index c8b7b66df..000000000 --- a/database/postgres/build.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetBuild gets a build by number and repo ID from the database. -func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "build": number, - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting build %s/%d from the database", r.GetFullName(), number) - - // variable to store query results - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectRepoBuild, r.GetID(), number). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return b.ToLibrary(), result.Error -} - -// GetBuildByID gets a build by id from the database. -func (c *client) GetBuildByID(id int64) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "build": id, - }).Tracef("getting build %d from the database", id) - - // variable to store query result - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectBuildByID, id). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return b.ToLibrary(), result.Error -} - -// GetLastBuild gets the last build by repo ID from the database. -func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { - c.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) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectLastRepoBuild, r.GetID()). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return b.ToLibrary(), result.Error -} - -// GetLastBuildByBranch gets the last build by repo ID and branch from the database. -func (c *client) GetLastBuildByBranch(r *library.Repo, branch string) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting last build for repo %s on branch %s from the database", r.GetFullName(), branch) - - // variable to store query results - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectLastRepoBuildByBranch, r.GetID(), branch). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return b.ToLibrary(), result.Error -} - -// GetPendingAndRunningBuilds returns the list of pending -// and running builds within the given timeframe. -func (c *client) GetPendingAndRunningBuilds(after string) ([]*library.BuildQueue, error) { - c.Logger.Trace("getting pending and running builds from the database") - - // variable to store query results - b := new([]database.BuildQueue) - - // send query to the database and store result in variable - result := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectPendingAndRunningBuilds, after). - Scan(b) - - // variable we want to return - builds := []*library.BuildQueue{} - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, result.Error -} - -// CreateBuild creates a new build in the database. -func (c *client) CreateBuild(b *library.Build) error { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("creating build %d in the database", b.GetNumber()) - - // cast to database type - build := database.BuildFromLibrary(b) - - // validate the necessary fields are populated - err := build.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableBuild). - Create(build.Crop()).Error -} - -// UpdateBuild updates a build in the database. -func (c *client) UpdateBuild(b *library.Build) error { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("updating build %d in the database", b.GetNumber()) - - // cast to database type - build := database.BuildFromLibrary(b) - - // validate the necessary fields are populated - err := build.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Postgres. - Table(constants.TableBuild). - Save(build.Crop()).Error -} - -// DeleteBuild deletes a build by unique ID from the database. -func (c *client) DeleteBuild(id int64) error { - c.Logger.Tracef("deleting build %d in the database", id) - - // send query to the database - return c.Postgres. - Table(constants.TableBuild). - Exec(dml.DeleteBuild, id).Error -} diff --git a/database/postgres/build_count.go b/database/postgres/build_count.go deleted file mode 100644 index 0d7af8f5f..000000000 --- a/database/postgres/build_count.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildCount gets a count of all builds from the database. -func (c *client) GetBuildCount() (int64, error) { - c.Logger.Trace("getting count of builds from the database") - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectBuildsCount). - Pluck("count", &b).Error - - return b, err -} - -// GetBuildCountByStatus gets a count of all builds by status from the database. -func (c *client) GetBuildCountByStatus(status string) (int64, error) { - c.Logger.Tracef("getting count of builds by status %s from the database", status) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Raw(dml.SelectBuildsCountByStatus, status). - Pluck("count", &b).Error - - return b, err -} - -// GetOrgBuildCount gets the count of all builds by repo ID from the database. -func (c *client) GetOrgBuildCount(org string, filters map[string]interface{}) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("getting count of builds for org %s from the database", org) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Joins("JOIN repos ON builds.repo_id = repos.id and repos.org = ?", org). - Where(filters). - Count(&b).Error - - return b, err -} - -// GetRepoBuildCount gets the count of all builds by repo ID from the database. -func (c *client) GetRepoBuildCount(r *library.Repo, filters map[string]interface{}) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "name": r.GetName(), - }).Tracef("getting count of builds for repo %s from the database", r.GetFullName()) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Where("repo_id = ?", r.GetID()). - Where(filters). - Count(&b).Error - - return b, err -} diff --git a/database/postgres/build_count_test.go b/database/postgres/build_count_test.go deleted file mode 100644 index 0c4522798..000000000 --- a/database/postgres/build_count_test.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuildCount(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildsCount).Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildCount() - - if test.failure { - if err == nil { - t.Errorf("GetBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetBuildCountByStatus(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildsCountByStatus, "running").Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildCountByStatus("running") - - if test.failure { - if err == nil { - t.Errorf("GetBuildCountByStatus should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildCountByStatus returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildCountByStatus is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgBuildCount(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - filters := map[string]interface{}{} - // run tests - for _, test := range tests { - got, err := _database.GetOrgBuildCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildCount is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgBuildCountByEvent(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"event\" = $2").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - filters := map[string]interface{}{ - "event": "push", - } - - // run tests - for _, test := range tests { - got, err := _database.GetOrgBuildCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildCountByEvent should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildCountByEvent returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildCountByEvent is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetRepoBuildCount(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) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE repo_id = $1`).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - got, err := _database.GetRepoBuildCount(_repo, filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoBuildCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/build_list.go b/database/postgres/build_list.go deleted file mode 100644 index 76fe1dce4..000000000 --- a/database/postgres/build_list.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildList gets a list of all builds from the database. -func (c *client) GetBuildList() ([]*library.Build, error) { - c.Logger.Trace("listing builds from the database") - - // variable to store query results - b := new([]database.Build) - - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Raw(dml.ListBuilds). - Scan(b).Error - - // variable we want to return - builds := []*library.Build{} - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, err -} - -// GetDeploymentBuildList gets a list of all builds from the database. -func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "deployment": deployment, - }).Tracef("listing builds for deployment %s from the database", deployment) - - // variable to store query results - b := new([]database.Build) - - filters := map[string]string{} - if len(deployment) > 0 { - filters["source"] = deployment - } - // send query to the database and store result in variable - err := c.Postgres. - Table(constants.TableBuild). - Select("*"). - Where(filters). - Limit(3). - Order("number DESC"). - Scan(b).Error - - // variable we want to return - builds := []*library.Build{} - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, err -} - -// GetOrgBuildList gets a list of all builds by org name and allows filters from the database. -func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("listing builds for org %s from the database", org) - - // variables to store query results - b := new([]database.Build) - builds := []*library.Build{} - count := int64(0) - - // count the results - count, err := c.GetOrgBuildCount(org, filters) - if err != nil { - return builds, 0, err - } - - // short-circuit if there are no results - if count == 0 { - return builds, 0, nil - } - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err = c.Postgres. - Table(constants.TableBuild). - Select("builds.*"). - Joins("JOIN repos ON builds.repo_id = repos.id and repos.org = ?", org). - Where(filters). - Order("created DESC"). - Order("id"). - Limit(perPage). - Offset(offset). - Scan(b).Error - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, count, err -} - -// GetRepoBuildList gets a list of all builds by repo ID from the database. -func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("listing builds for repo %s from the database", r.GetFullName()) - - // variable to store query results - b := new([]database.Build) - builds := []*library.Build{} - count := int64(0) - - // count the results - count, err := c.GetRepoBuildCount(r, filters) - if err != nil { - return builds, 0, err - } - - // short-circuit if there are no results - if count == 0 { - return builds, 0, nil - } - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - err = c.Postgres. - Table(constants.TableBuild). - Where("repo_id = ?", r.GetID()). - Where("created < ?", before). - Where("created > ?", after). - Where(filters). - Order("number DESC"). - Limit(perPage). - Offset(offset). - Scan(b).Error - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, count, err -} diff --git a/database/postgres/build_list_test.go b/database/postgres/build_list_test.go deleted file mode 100644 index bd2e34878..000000000 --- a/database/postgres/build_list_test.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - "time" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuildList(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.ListBuilds).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildList() - - if test.failure { - if err == nil { - t.Errorf("GetBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetDeploymentBuildList(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - _buildOne.SetSource("https://github.com/github/octocat/deployments/1") - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetSource("https://github.com/github/octocat/deployments/1") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "https://github.com/github/octocat/deployments/1", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT * FROM \"builds\" WHERE \"source\" = $1 ORDER BY number DESC LIMIT 3").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildTwo, _buildOne}, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetDeploymentBuildList("https://github.com/github/octocat/deployments/1") - - if test.failure { - if err == nil { - t.Errorf("GetDeploymentBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetDeploymentBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetDeploymentBuildList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgBuildList(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1").WillReturnRows(_rows) - - // create expected return in mock - _rows = sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgBuildList_NonAdmin(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"visibility\" = $2").WillReturnRows(_rows) - - // create expected return in mock - _rows = sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"visibility\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne}, - }, - } - - filters := map[string]interface{}{ - "visibility": "public", - } - - // run tests - for _, test := range tests { - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildList is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetOrgBuildListByEvent(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) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(2) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT count(*) FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"event\" = $2").WillReturnRows(_rows) - - // create expected return in mock - _rows = sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query - _mock.ExpectQuery("SELECT builds.* FROM \"builds\" JOIN repos ON builds.repo_id = repos.id and repos.org = $1 WHERE \"event\" = $2 ORDER BY created DESC,id LIMIT 10").WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - filters := map[string]interface{}{ - "event": "push", - } - - // run tests - for _, test := range tests { - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildListByEvent should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildListByEvent returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildListByEvent is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetRepoBuildList(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - _buildOne.SetCreated(1) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetCreated(2) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"count"}).AddRow(3) - - // ensure the mock expects the query - _mock.ExpectQuery(`SELECT count(*) FROM "builds" WHERE repo_id = $1`).WillReturnRows(_rows) - - // create expected return in mock - _rows = sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). - AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // 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 10`).WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - before int64 - after int64 - want []*library.Build - }{ - { - failure: false, - before: time.Now().UTC().Unix(), - after: 0, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - got, _, err := _database.GetRepoBuildList(_repo, filters, test.before, test.after, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetRepoBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoBuildList is %v, want %v", got, test.want) - } - } -} diff --git a/database/postgres/build_test.go b/database/postgres/build_test.go deleted file mode 100644 index 06d6238b2..000000000 --- a/database/postgres/build_test.go +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - - "github.com/go-vela/server/database/postgres/dml" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -func TestPostgres_Client_GetBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectRepoBuild, 1, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuild(1, _repo) - - if test.failure { - if err == nil { - t.Errorf("GetBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuild returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuild is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetBuildByID(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectBuildByID, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetBuildByID(1) - - if test.failure { - if err == nil { - t.Errorf("GetBuildByID should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildByID returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildByID is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetLastBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectLastRepoBuild, 1).Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetLastBuild(_repo) - - if test.failure { - if err == nil { - t.Errorf("GetLastBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastBuild returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastBuild is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetLastBuildByBranch(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectLastRepoBuildByBranch, 1, "master").Statement - - // create expected return in mock - _rows := sqlmock.NewRows( - []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", "timestamp"}, - ).AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetLastBuildByBranch(_repo, "master") - - if test.failure { - if err == nil { - t.Errorf("GetLastBuildByBranch should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastBuildByBranch returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastBuildByBranch is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_GetPendingAndRunningBuilds(t *testing.T) { - // setup types - _buildOne := new(library.BuildQueue) - _buildOne.SetCreated(0) - _buildOne.SetFullName("") - _buildOne.SetNumber(1) - _buildOne.SetStatus("") - - _buildTwo := new(library.BuildQueue) - _buildTwo.SetCreated(0) - _buildTwo.SetFullName("") - _buildTwo.SetNumber(2) - _buildTwo.SetStatus("") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Raw(dml.SelectPendingAndRunningBuilds, "").Statement - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"created", "full_name", "number", "status"}). - AddRow(0, "", 1, "").AddRow(0, "", 2, "") - - // ensure the mock expects the query for test case 1 - _mock.ExpectQuery(_query.SQL.String()).WillReturnRows(_rows) - // ensure the mock expects the error for test case 2 - _mock.ExpectQuery(_query.SQL.String()).WillReturnError(gorm.ErrRecordNotFound) - - // setup tests - tests := []struct { - failure bool - want []*library.BuildQueue - }{ - { - failure: false, - want: []*library.BuildQueue{_buildOne, _buildTwo}, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - got, err := _database.GetPendingAndRunningBuilds("") - - if test.failure { - if err == nil { - t.Errorf("GetPendingAndRunningBuilds should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetPendingAndRunningBuilds returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetPendingAndRunningBuilds is %v, want %v", got, test.want) - } - } -} - -func TestPostgres_Client_CreateBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // create expected return in mock - _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) - - // ensure the mock expects the query - _mock.ExpectQuery(`INSERT INTO "builds" ("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","id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31) RETURNING "id"`). - WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnRows(_rows) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.CreateBuild(_build) - - if test.failure { - if err == nil { - t.Errorf("CreateBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateBuild returned err: %v", err) - } - } -} - -func TestPostgres_Client_UpdateBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the query - _mock.ExpectExec(`UPDATE "builds" SET "repo_id"=$1,"pipeline_id"=$2,"number"=$3,"parent"=$4,"event"=$5,"event_action"=$6,"status"=$7,"error"=$8,"enqueued"=$9,"created"=$10,"started"=$11,"finished"=$12,"deploy"=$13,"deploy_payload"=$14,"clone"=$15,"source"=$16,"title"=$17,"message"=$18,"commit"=$19,"sender"=$20,"author"=$21,"email"=$22,"link"=$23,"branch"=$24,"ref"=$25,"base_ref"=$26,"head_ref"=$27,"host"=$28,"runtime"=$29,"distribution"=$30 WHERE "id" = $31`). - WithArgs(1, nil, 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, AnyArgument{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1). - WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.UpdateBuild(_build) - - if test.failure { - if err == nil { - t.Errorf("UpdateBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateBuild returned err: %v", err) - } - } -} - -func TestPostgres_Client_DeleteBuild(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // capture the current expected SQL query - // - // https://gorm.io/docs/sql_builder.html#DryRun-Mode - _query := _database.Postgres.Session(&gorm.Session{DryRun: true}).Exec(dml.DeleteBuild, 1).Statement - - // ensure the mock expects the query - _mock.ExpectExec(_query.SQL.String()).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := _database.DeleteBuild(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteBuild returned err: %v", err) - } - } -} - -// testBuild is a test helper function to create a -// library Build type with all fields set to their -// zero values. -func testBuild() *library.Build { - i64 := int64(0) - i := 0 - str := "" - - return &library.Build{ - ID: &i64, - RepoID: &i64, - PipelineID: &i64, - Number: &i, - Parent: &i, - Event: &str, - EventAction: &str, - Status: &str, - Error: &str, - Enqueued: &i64, - Created: &i64, - Started: &i64, - Finished: &i64, - Deploy: &str, - Clone: &str, - Source: &str, - Title: &str, - Message: &str, - Commit: &str, - Sender: &str, - Author: &str, - Email: &str, - Link: &str, - Branch: &str, - Ref: &str, - BaseRef: &str, - HeadRef: &str, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/postgres/ddl/build.go b/database/postgres/ddl/build.go deleted file mode 100644 index 58eacf15b..000000000 --- a/database/postgres/ddl/build.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateBuildTable represents a query to - // create the builds table for Vela. - CreateBuildTable = ` -CREATE TABLE -IF NOT EXISTS -builds ( - id SERIAL PRIMARY KEY, - repo_id INTEGER, - pipeline_id INTEGER, - number INTEGER, - parent INTEGER, - event VARCHAR(250), - event_action VARCHAR(250), - status VARCHAR(250), - error VARCHAR(1000), - enqueued INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - deploy VARCHAR(500), - deploy_payload VARCHAR(2000), - clone VARCHAR(1000), - source VARCHAR(1000), - title VARCHAR(1000), - message VARCHAR(2000), - commit VARCHAR(500), - sender VARCHAR(250), - author VARCHAR(250), - email VARCHAR(500), - link VARCHAR(1000), - branch VARCHAR(500), - ref VARCHAR(500), - base_ref VARCHAR(500), - head_ref VARCHAR(500), - host VARCHAR(250), - runtime VARCHAR(250), - distribution VARCHAR(250), - timestamp INTEGER, - UNIQUE(repo_id, number) -); -` - - // CreateBuildRepoIDIndex represents a query to create an - // index on the builds table for the repo_id column. - CreateBuildRepoIDIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_repo_id -ON builds (repo_id); -` - - // CreateBuildStatusIndex represents a query to create an - // index on the builds table for the status column. - CreateBuildStatusIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_status -ON builds (status); -` - - // CreateBuildCreatedIndex represents a query to create an - // index on the builds table for the created column. - CreateBuildCreatedIndex = ` -CREATE INDEX CONCURRENTLY -IF NOT EXISTS -builds_created -ON builds (created); -` - - // CreateBuildSourceIndex represents a query to create an - // index on the builds table for the source column. - CreateBuildSourceIndex = ` -CREATE INDEX CONCURRENTLY -IF NOT EXISTS -builds_source -ON builds (source); -` -) diff --git a/database/postgres/ddl/doc.go b/database/postgres/ddl/doc.go deleted file mode 100644 index 3e21c882f..000000000 --- a/database/postgres/ddl/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package ddl provides the Postgres data definition language (DDL) for Vela. -// -// https://en.wikipedia.org/wiki/Data_definition_language -// -// Usage: -// -// import "github.com/go-vela/server/database/postgres/ddl" -package ddl diff --git a/database/postgres/dml/build.go b/database/postgres/dml/build.go deleted file mode 100644 index 9080157c6..000000000 --- a/database/postgres/dml/build.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListBuilds represents a query to - // list all builds in the database. - ListBuilds = ` -SELECT * -FROM builds; -` - - // SelectBuildByID represents a query to select - // a build for its id in the database. - SelectBuildByID = ` -SELECT * -FROM builds -WHERE id = ? -LIMIT 1; -` - - // SelectRepoBuild represents a query to select - // a build for a repo_id in the database. - SelectRepoBuild = ` -SELECT * -FROM builds -WHERE repo_id = ? -AND number = ? -LIMIT 1; -` - - // SelectLastRepoBuild represents a query to select - // the last build for a repo_id in the database. - SelectLastRepoBuild = ` -SELECT * -FROM builds -WHERE repo_id = ? -ORDER BY number DESC -LIMIT 1; -` - - // SelectLastRepoBuildByBranch represents a query to - // select the last build for a repo_id and branch name - // in the database. - SelectLastRepoBuildByBranch = ` -SELECT * -FROM builds -WHERE repo_id = ? -AND branch = ? -ORDER BY number DESC -LIMIT 1; -` - - // SelectBuildsCount represents a query to select - // the count of builds in the database. - SelectBuildsCount = ` -SELECT count(*) as count -FROM builds; -` - - // SelectBuildsCountByStatus represents a query to select - // the count of builds for a status in the database. - SelectBuildsCountByStatus = ` -SELECT count(*) as count -FROM builds -WHERE status = ?; -` - - // DeleteBuild represents a query to - // remove a build from the database. - DeleteBuild = ` -DELETE -FROM builds -WHERE id = ?; -` - - // SelectPendingAndRunningBuilds represents a joined query - // between the builds & repos table to select - // the created builds that are in pending or running builds status - // since the specified timeframe. - SelectPendingAndRunningBuilds = ` -SELECT builds.created, builds.number, builds.status, repos.full_name -FROM builds INNER JOIN repos -ON builds.repo_id = repos.id -WHERE builds.created > ? -AND (builds.status = 'running' OR builds.status = 'pending'); -` -) diff --git a/database/postgres/dml/doc.go b/database/postgres/dml/doc.go deleted file mode 100644 index f7e517d36..000000000 --- a/database/postgres/dml/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package dml provides the Postgres data manipulation language (DML) for Vela. -// -// https://en.wikipedia.org/wiki/Data_manipulation_language -// -// Usage: -// -// import "github.com/go-vela/server/database/postgres/dml" -package dml diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 0c316531b..fea05037d 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -5,14 +5,13 @@ package postgres import ( - "fmt" "time" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" - "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "github.com/go-vela/server/database/schedule" "github.com/go-vela/server/database/secret" @@ -20,7 +19,6 @@ import ( "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" - "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" "gorm.io/driver/postgres" @@ -51,6 +49,8 @@ type ( Postgres *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/build#BuildInterface + build.BuildInterface // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface hook.HookInterface // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface @@ -167,6 +167,12 @@ func NewTest() (*client, sqlmock.Sqlmock, error) { return nil, nil, err } + // ensure the mock expects the build queries + _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -257,64 +263,6 @@ func setupDatabase(c *client) error { return nil } - // create the tables in the database - err = createTables(c) - if err != nil { - return err - } - - // create the indexes in the database - err = createIndexes(c) - if err != nil { - return err - } - - return nil -} - -// createTables is a helper function to setup -// the database with the necessary tables. -func createTables(c *client) error { - c.Logger.Trace("creating data tables in the postgres database") - - // create the builds table - err := c.Postgres.Exec(ddl.CreateBuildTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) - } - - return nil -} - -// createIndexes is a helper function to setup -// the database with the necessary indexes. -func createIndexes(c *client) error { - c.Logger.Trace("creating data indexes in the postgres database") - - // create the builds_repo_id index for the builds table - err := c.Postgres.Exec(ddl.CreateBuildRepoIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_repo_id index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_status index for the builds table - err = c.Postgres.Exec(ddl.CreateBuildStatusIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_status index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_created index for the builds table - err = c.Postgres.Exec(ddl.CreateBuildCreatedIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_source index for the builds table - err = c.Postgres.Exec(ddl.CreateBuildSourceIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) - } - return nil } @@ -322,6 +270,18 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error + // create the database agnostic engine for builds + // + // https://pkg.go.dev/github.com/go-vela/server/database/build#New + c.BuildInterface, err = build.New( + build.WithClient(c.Postgres), + build.WithLogger(c.Logger), + build.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic engine for hooks // // https://pkg.go.dev/github.com/go-vela/server/database/hook#New diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index d61f443fd..a8f74d1ff 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -5,24 +5,22 @@ package postgres import ( - "database/sql/driver" "testing" "time" "github.com/go-vela/server/database/schedule" "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" - "github.com/go-vela/server/database/postgres/ddl" "github.com/go-vela/server/database/repo" "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/user" "github.com/go-vela/server/database/worker" - "github.com/go-vela/types/library" ) func TestPostgres_New(t *testing.T) { @@ -83,15 +81,12 @@ func TestPostgres_setupDatabase(t *testing.T) { // ensure the mock expects the ping _mock.ExpectPing() - // ensure the mock expects the table queries - _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - - // ensure the mock expects the index queries - _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - + // ensure the mock expects the build queries + _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -171,87 +166,6 @@ func TestPostgres_setupDatabase(t *testing.T) { } } -func TestPostgres_createTables(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the table queries - _mock.ExpectExec(ddl.CreateBuildTable).WillReturnResult(sqlmock.NewResult(1, 1)) - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createTables(_database) - - if test.failure { - if err == nil { - t.Errorf("createTables should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createTables returned err: %v", err) - } - } -} - -func TestPostgres_createIndexes(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the index queries - _mock.ExpectExec(ddl.CreateBuildRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(ddl.CreateBuildSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createIndexes(_database) - - if test.failure { - if err == nil { - t.Errorf("createIndexes should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createIndexes returned err: %v", err) - } - } -} - func TestPostgres_createServices(t *testing.T) { // setup types // setup the test database client @@ -262,6 +176,12 @@ func TestPostgres_createServices(t *testing.T) { defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() + // ensure the mock expects the build queries + _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) @@ -318,52 +238,3 @@ func TestPostgres_createServices(t *testing.T) { } } } - -// 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(v driver.Value) bool { - return true -} - -// testRepo is a test helper function to create a -// library Repo type with all fields set to their -// zero values. -func testRepo() *library.Repo { - i64 := int64(0) - i := 0 - str := "" - b := false - - return &library.Repo{ - ID: &i64, - PipelineType: &str, - UserID: &i64, - Hash: &str, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - BuildLimit: &i64, - Timeout: &i64, - Counter: &i, - Visibility: &str, - Private: &b, - Trusted: &b, - Active: &b, - AllowPull: &b, - AllowPush: &b, - AllowDeploy: &b, - AllowTag: &b, - AllowComment: &b, - PreviousName: &str, - } -} diff --git a/database/sqlite/build.go b/database/sqlite/build.go deleted file mode 100644 index 974f619b0..000000000 --- a/database/sqlite/build.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "errors" - - "github.com/sirupsen/logrus" - - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - - "gorm.io/gorm" -) - -// GetBuild gets a build by number and repo ID from the database. -func (c *client) GetBuild(number int, r *library.Repo) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "build": number, - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting build %s/%d from the database", r.GetFullName(), number) - - // variable to store query results - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectRepoBuild, r.GetID(), number). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return b.ToLibrary(), result.Error -} - -// GetBuildByID gets a build by its ID from the database. -func (c *client) GetBuildByID(id int64) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "build": id, - }).Tracef("getting build %d from the database", id) - - // variable to store query result - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectBuildByID, id). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - return nil, gorm.ErrRecordNotFound - } - - return b.ToLibrary(), result.Error -} - -// GetLastBuild gets the last build by repo ID from the database. -func (c *client) GetLastBuild(r *library.Repo) (*library.Build, error) { - c.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) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectLastRepoBuild, r.GetID()). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return b.ToLibrary(), result.Error -} - -// GetLastBuildByBranch gets the last build by repo ID and branch from the database. -func (c *client) GetLastBuildByBranch(r *library.Repo, branch string) (*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("getting last build for repo %s on branch %s from the database", r.GetFullName(), branch) - - // variable to store query results - b := new(database.Build) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectLastRepoBuildByBranch, r.GetID(), branch). - Scan(b) - - // check if the query returned a record not found error or no rows were returned - if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.RowsAffected == 0 { - // the record will not exist if it's a new repo - return nil, nil - } - - return b.ToLibrary(), result.Error -} - -// GetPendingAndRunningBuilds returns the list of pending -// and running builds within the given timeframe. -func (c *client) GetPendingAndRunningBuilds(after string) ([]*library.BuildQueue, error) { - c.Logger.Trace("getting pending and running builds from the database") - - // variable to store query results - b := new([]database.BuildQueue) - - // send query to the database and store result in variable - result := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectPendingAndRunningBuilds, after). - Scan(b) - - // variable we want to return - builds := []*library.BuildQueue{} - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, result.Error -} - -// CreateBuild creates a new build in the database. -func (c *client) CreateBuild(b *library.Build) error { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("creating build %d in the database", b.GetNumber()) - - // cast to database type - build := database.BuildFromLibrary(b) - - // validate the necessary fields are populated - err := build.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableBuild). - Create(build.Crop()).Error -} - -// UpdateBuild updates a build in the database. -func (c *client) UpdateBuild(b *library.Build) error { - c.Logger.WithFields(logrus.Fields{ - "build": b.GetNumber(), - }).Tracef("updating build %d in the database", b.GetNumber()) - - // cast to database type - build := database.BuildFromLibrary(b) - - // validate the necessary fields are populated - err := build.Validate() - if err != nil { - return err - } - - // send query to the database - return c.Sqlite. - Table(constants.TableBuild). - Save(build.Crop()).Error -} - -// DeleteBuild deletes a build by unique ID from the database. -func (c *client) DeleteBuild(id int64) error { - c.Logger.Tracef("deleting build %d in the database", id) - - // send query to the database - return c.Sqlite. - Table(constants.TableBuild). - Exec(dml.DeleteBuild, id).Error -} diff --git a/database/sqlite/build_count.go b/database/sqlite/build_count.go deleted file mode 100644 index 2a363ddcf..000000000 --- a/database/sqlite/build_count.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildCount gets a count of all builds from the database. -func (c *client) GetBuildCount() (int64, error) { - c.Logger.Trace("getting count of builds from the database") - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectBuildsCount). - Pluck("count", &b).Error - - return b, err -} - -// GetBuildCountByStatus gets a count of all builds by status from the database. -func (c *client) GetBuildCountByStatus(status string) (int64, error) { - c.Logger.Tracef("getting count of builds by status %s from the database", status) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.SelectBuildsCountByStatus, status). - Pluck("count", &b).Error - - return b, err -} - -// GetOrgBuildCount gets the count of all builds by repo ID from the database. -func (c *client) GetOrgBuildCount(org string, filters map[string]interface{}) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("getting count of builds for org %s from the database", org) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Joins("JOIN repos ON builds.repo_id = repos.id and repos.org = ?", org). - Where(filters). - Count(&b).Error - - return b, err -} - -// GetRepoBuildCount gets the count of all builds by repo ID from the database. -func (c *client) GetRepoBuildCount(r *library.Repo, filters map[string]interface{}) (int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "name": r.GetName(), - }).Tracef("getting count of builds for repo %s from the database", r.GetFullName()) - - // variable to store query results - var b int64 - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Where("repo_id = ?", r.GetID()). - Where(filters). - Count(&b).Error - - return b, err -} diff --git a/database/sqlite/build_count_test.go b/database/sqlite/build_count_test.go deleted file mode 100644 index ec4c2120d..000000000 --- a/database/sqlite/build_count_test.go +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the build table - err = _database.Sqlite.Exec(ddl.CreateBuildTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableBuild, err) - } -} - -func TestSqlite_Client_GetBuildCount(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) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the builds in the database - err := _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - got, err := _database.GetBuildCount() - - if test.failure { - if err == nil { - t.Errorf("GetBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetBuildCountByStatus(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetStatus("running") - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetStatus("running") - _buildTwo.SetDeployPayload(nil) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the builds in the database - err := _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - got, err := _database.GetBuildCountByStatus("running") - - if test.failure { - if err == nil { - t.Errorf("GetBuildCountByStatus should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildCountByStatus returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildCountByStatus is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgBuildCount(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) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the builds in the database - err = _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - got, err := _database.GetOrgBuildCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildCount is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgBuildCountByEvent(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetEvent("push") - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetEvent("push") - _buildTwo.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - filters := map[string]interface{}{ - "event": "push", - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the builds in the database - err = _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - got, err := _database.GetOrgBuildCount("foo", filters) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildCountByEvent should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildCountByEvent returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildCountByEvent is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetRepoBuildCount(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) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want int64 - }{ - { - failure: false, - want: 2, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the builds in the database - err = _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - got, err := _database.GetRepoBuildCount(_repo, filters) - - if test.failure { - if err == nil { - t.Errorf("GetRepoBuildCount should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoBuildCount returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoBuildCount is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/build_list.go b/database/sqlite/build_list.go deleted file mode 100644 index 300a7c9a8..000000000 --- a/database/sqlite/build_list.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "github.com/go-vela/server/database/sqlite/dml" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" - "github.com/sirupsen/logrus" -) - -// GetBuildList gets a list of all builds from the database. -func (c *client) GetBuildList() ([]*library.Build, error) { - c.Logger.Trace("listing builds from the database") - - // variable to store query results - b := new([]database.Build) - - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Raw(dml.ListBuilds). - Scan(b).Error - - // variable we want to return - builds := []*library.Build{} - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, err -} - -// GetDeploymentBuildList gets a list of all builds from the database. -func (c *client) GetDeploymentBuildList(deployment string) ([]*library.Build, error) { - c.Logger.WithFields(logrus.Fields{ - "deployment": deployment, - }).Tracef("listing builds for deployment %s from the database", deployment) - - // variable to store query results - b := new([]database.Build) - filters := map[string]string{} - - if len(deployment) > 0 { - filters["source"] = deployment - } - // send query to the database and store result in variable - err := c.Sqlite. - Table(constants.TableBuild). - Select("*"). - Where(filters). - Limit(3). - Order("number DESC"). - Scan(b).Error - - // variable we want to return - builds := []*library.Build{} - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, err -} - -// GetOrgBuildList gets a list of all builds by org name from the database. -func (c *client) GetOrgBuildList(org string, filters map[string]interface{}, page int, perPage int) ([]*library.Build, int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": org, - }).Tracef("listing builds for org %s from the database", org) - - // variable to store query results - b := new([]database.Build) - builds := []*library.Build{} - count := int64(0) - - // // count the results - count, err := c.GetOrgBuildCount(org, filters) - - if err != nil { - return builds, 0, err - } - - // short-circuit if there are no results - if count == 0 { - return builds, 0, nil - } - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err = c.Sqlite. - Table(constants.TableBuild). - Select("builds.*"). - Joins("JOIN repos ON builds.repo_id = repos.id AND repos.org = ?", org). - Where(filters). - Order("created DESC"). - Order("id"). - Limit(perPage). - Offset(offset). - Scan(b).Error - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, count, err -} - -// GetRepoBuildList gets a list of all builds by repo ID from the database. -func (c *client) GetRepoBuildList(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { - c.Logger.WithFields(logrus.Fields{ - "org": r.GetOrg(), - "repo": r.GetName(), - }).Tracef("listing builds for repo %s from the database", r.GetFullName()) - - // variable to store query results - b := new([]database.Build) - builds := []*library.Build{} - count := int64(0) - - // count the results - count, err := c.GetRepoBuildCount(r, filters) - if err != nil { - return builds, 0, err - } - - // short-circuit if there are no results - if count == 0 { - return builds, 0, nil - } - - // calculate offset for pagination through results - offset := perPage * (page - 1) - - // send query to the database and store result in variable - err = c.Sqlite. - Table(constants.TableBuild). - Where("repo_id = ?", r.GetID()). - Where("created < ?", before). - Where("created > ?", after). - Where(filters). - Order("number DESC"). - Limit(perPage). - Offset(offset). - Scan(b).Error - - // iterate through all query results - for _, build := range *b { - // https://golang.org/doc/faq#closures_and_goroutines - tmp := build - - // convert query result to library type - builds = append(builds, tmp.ToLibrary()) - } - - return builds, count, err -} diff --git a/database/sqlite/build_list_test.go b/database/sqlite/build_list_test.go deleted file mode 100644 index 908c501bc..000000000 --- a/database/sqlite/build_list_test.go +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "log" - "reflect" - "testing" - "time" - - "github.com/go-vela/server/database/sqlite/ddl" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -func init() { - // setup the test database client - _database, err := NewTest() - if err != nil { - log.Fatalf("unable to create new sqlite test database: %v", err) - } - - // create the build table - err = _database.Sqlite.Exec(ddl.CreateBuildTable).Error - if err != nil { - log.Fatalf("unable to create %s table: %v", constants.TableBuild, err) - } -} - -func TestSqlite_Client_GetBuildList(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) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range test.want { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetBuildList() - - if test.failure { - if err == nil { - t.Errorf("GetBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetDeploymentBuildList(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetEvent("deployment") - _buildOne.SetDeployPayload(nil) - _buildOne.SetSource("https://github.com/github/octocat/deployments/1") - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildOne.SetEvent("deployment") - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetSource("https://github.com/github/octocat/deployments/1") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildTwo, _buildOne}, - }, - } - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range test.want { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetDeploymentBuildList("https://github.com/github/octocat/deployments/1") - - if test.failure { - if err == nil { - t.Errorf("GetDeploymentBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetDeploymentBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetDeploymentBuildList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgBuildList(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetEvent("push") - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildOne.SetEvent("deployment") - _buildTwo.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne, _buildTwo}, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range test.want { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgBuildList_NonAdmin(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(2) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - - _repoOne := testRepo() - _repoOne.SetID(1) - _repoOne.SetUserID(1) - _repoOne.SetHash("baz") - _repoOne.SetOrg("foo") - _repoOne.SetName("bar") - _repoOne.SetFullName("foo/bar") - _repoOne.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.SetUserID(1) - _repoTwo.SetHash("baz") - _repoTwo.SetOrg("bar") - _repoTwo.SetName("foo") - _repoTwo.SetFullName("bar/foo") - _repoTwo.SetVisibility("private") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne}, - }, - } - - filters := map[string]interface{}{} - - repos := []*library.Repo{_repoOne, _repoTwo} - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - for _, repo := range repos { - // create the repo in the database - err := _database.CreateRepo(repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range test.want { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildList is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetOrgBuildListByEvent(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetEvent("push") - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetEvent("deployment") - _buildTwo.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildOne}, - }, - } - - filters := map[string]interface{}{ - "event": "push", - } - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range []*library.Build{_buildTwo, _buildOne} { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, _, err := _database.GetOrgBuildList("foo", filters, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetOrgBuildListByEvent should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetOrgBuildListByEvent returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetOrgBuildListByEvent is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetRepoBuildList(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - _buildOne.SetCreated(1) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetCreated(2) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.Build - }{ - { - failure: false, - want: []*library.Build{_buildTwo, _buildOne}, - }, - } - - filters := map[string]interface{}{} - - // run tests - for _, test := range tests { - // defer cleanup of the repos table - defer _database.Sqlite.Exec("delete from repos;") - - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - for _, build := range test.want { - // create the build in the database - err := _database.CreateBuild(build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, _, err := _database.GetRepoBuildList(_repo, filters, time.Now().UTC().Unix(), 0, 1, 10) - - if test.failure { - if err == nil { - t.Errorf("GetRepoBuildList should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetRepoBuildList returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetRepoBuildList is %v, want %v", got, test.want) - } - } -} diff --git a/database/sqlite/build_test.go b/database/sqlite/build_test.go deleted file mode 100644 index a0e8eb8c1..000000000 --- a/database/sqlite/build_test.go +++ /dev/null @@ -1,611 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/library" -) - -func TestSqlite_Client_GetBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the build in the database - err := _database.CreateBuild(test.want) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetBuild(1, _repo) - - // cleanup the builds table - _ = _database.Sqlite.Exec("DELETE FROM builds;") - - if test.failure { - if err == nil { - t.Errorf("GetBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuild returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuild is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetBuildByID(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: true, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the build in the database - err := _database.CreateBuild(test.want) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetBuildByID(1) - - // cleanup the builds table - _ = _database.Sqlite.Exec("DELETE FROM builds;") - - if test.failure { - if err == nil { - t.Errorf("GetBuildByID should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetBuildByID returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildByID is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetLastBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the build in the database - err := _database.CreateBuild(test.want) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetLastBuild(_repo) - - // cleanup the builds table - _ = _database.Sqlite.Exec("DELETE FROM builds;") - - if test.failure { - if err == nil { - t.Errorf("GetLastBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastBuild returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastBuild is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetLastBuildByBranch(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetBranch("master") - _build.SetDeployPayload(nil) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want *library.Build - }{ - { - failure: false, - want: _build, - }, - { - failure: false, - want: nil, - }, - } - - // run tests - for _, test := range tests { - if test.want != nil { - // create the build in the database - err := _database.CreateBuild(test.want) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetLastBuildByBranch(_repo, "master") - - // cleanup the builds table - _ = _database.Sqlite.Exec("DELETE FROM builds;") - - if test.failure { - if err == nil { - t.Errorf("GetLastBuildByBranch should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetLastBuildByBranch returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetLastBuildByBranch is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_GetPendingAndRunningBuilds(t *testing.T) { - // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetStatus("running") - _buildOne.SetCreated(1) - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetStatus("pending") - _buildTwo.SetCreated(1) - _buildTwo.SetDeployPayload(nil) - - _queueOne := new(library.BuildQueue) - _queueOne.SetCreated(1) - _queueOne.SetFullName("foo/bar") - _queueOne.SetNumber(1) - _queueOne.SetStatus("running") - - _queueTwo := new(library.BuildQueue) - _queueTwo.SetCreated(1) - _queueTwo.SetFullName("foo/bar") - _queueTwo.SetNumber(2) - _queueTwo.SetStatus("pending") - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - want []*library.BuildQueue - }{ - { - failure: false, - want: []*library.BuildQueue{_queueOne, _queueTwo}, - }, - { - failure: false, - want: []*library.BuildQueue{}, - }, - } - - // run tests - for _, test := range tests { - // create the repo in the database - err := _database.CreateRepo(_repo) - if err != nil { - t.Errorf("unable to create test repo: %v", err) - } - - if len(test.want) > 0 { - // create the builds in the database - err = _database.CreateBuild(_buildOne) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.CreateBuild(_buildTwo) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - } - - got, err := _database.GetPendingAndRunningBuilds("0") - - // cleanup the repos table - _ = _database.Sqlite.Exec("DELETE FROM repos;") - // cleanup the builds table - _ = _database.Sqlite.Exec("DELETE FROM builds;") - - if test.failure { - if err == nil { - t.Errorf("GetPendingAndRunningBuilds should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("GetPendingAndRunningBuilds returned err: %v", err) - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetPendingAndRunningBuilds is %v, want %v", got, test.want) - } - } -} - -func TestSqlite_Client_CreateBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - err := _database.CreateBuild(_build) - - if test.failure { - if err == nil { - t.Errorf("CreateBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("CreateBuild returned err: %v", err) - } - } -} - -func TestSqlite_Client_UpdateBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - _repo := testRepo() - _repo.SetID(1) - _repo.SetUserID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the build in the database - err = _database.CreateBuild(_build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err := _database.UpdateBuild(_build) - - if test.failure { - if err == nil { - t.Errorf("UpdateBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("UpdateBuild returned err: %v", err) - } - } -} - -func TestSqlite_Client_DeleteBuild(t *testing.T) { - // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup tests - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - // defer cleanup of the builds table - defer _database.Sqlite.Exec("delete from builds;") - - // create the build in the database - err = _database.CreateBuild(_build) - if err != nil { - t.Errorf("unable to create test build: %v", err) - } - - err = _database.DeleteBuild(1) - - if test.failure { - if err == nil { - t.Errorf("DeleteBuild should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("DeleteBuild returned err: %v", err) - } - } -} - -// testBuild is a test helper function to create a -// library Build type with all fields set to their -// zero values. -func testBuild() *library.Build { - i64 := int64(0) - i := 0 - str := "" - - return &library.Build{ - ID: &i64, - RepoID: &i64, - PipelineID: &i64, - Number: &i, - Parent: &i, - Event: &str, - EventAction: &str, - Status: &str, - Error: &str, - Enqueued: &i64, - Created: &i64, - Started: &i64, - Finished: &i64, - Deploy: &str, - Clone: &str, - Source: &str, - Title: &str, - Message: &str, - Commit: &str, - Sender: &str, - Author: &str, - Email: &str, - Link: &str, - Branch: &str, - Ref: &str, - BaseRef: &str, - HeadRef: &str, - Host: &str, - Runtime: &str, - Distribution: &str, - } -} diff --git a/database/sqlite/ddl/build.go b/database/sqlite/ddl/build.go deleted file mode 100644 index e4a713fdd..000000000 --- a/database/sqlite/ddl/build.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package ddl - -const ( - // CreateBuildTable represents a query to - // create the builds table for Vela. - CreateBuildTable = ` -CREATE TABLE -IF NOT EXISTS -builds ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - repo_id INTEGER, - pipeline_id INTEGER, - number INTEGER, - parent INTEGER, - event TEXT, - event_action TEXT, - status TEXT, - error TEXT, - enqueued INTEGER, - created INTEGER, - started INTEGER, - finished INTEGER, - deploy TEXT, - deploy_payload TEXT, - clone TEXT, - source TEXT, - title TEXT, - message TEXT, - 'commit' TEXT, - sender TEXT, - author TEXT, - email TEXT, - link TEXT, - branch TEXT, - ref TEXT, - base_ref TEXT, - head_ref TEXT, - host TEXT, - runtime TEXT, - distribution TEXT, - timestamp INTEGER, - UNIQUE(repo_id, number) -); -` - - // CreateBuildRepoIDIndex represents a query to create an - // index on the builds table for the repo_id column. - CreateBuildRepoIDIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_repo_id -ON builds (repo_id); -` - - // CreateBuildStatusIndex represents a query to create an - // index on the builds table for the status column. - CreateBuildStatusIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_status -ON builds (status); -` - - // CreateBuildCreatedIndex represents a query to create an - // index on the builds table for the created column. - CreateBuildCreatedIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_created -ON builds (created); -` - - // CreateBuildSourceIndex represents a query to create an - // index on the builds table for the source column. - CreateBuildSourceIndex = ` -CREATE INDEX -IF NOT EXISTS -builds_source -ON builds (source); -` -) diff --git a/database/sqlite/ddl/doc.go b/database/sqlite/ddl/doc.go deleted file mode 100644 index 3e2bd5d2b..000000000 --- a/database/sqlite/ddl/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package ddl provides the Sqlite data definition language (DDL) for Vela. -// -// https://en.wikipedia.org/wiki/Data_definition_language -// -// Usage: -// -// import "github.com/go-vela/server/database/sqlite/ddl" -package ddl diff --git a/database/sqlite/dml/build.go b/database/sqlite/dml/build.go deleted file mode 100644 index fa9f94453..000000000 --- a/database/sqlite/dml/build.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package dml - -const ( - // ListBuilds represents a query to - // list all builds in the database. - ListBuilds = ` -SELECT * -FROM builds; -` - - // SelectBuildByID represents a query to select - // a build for its id in the database. - SelectBuildByID = ` -SELECT * -FROM builds -WHERE id = ? -LIMIT 1; -` - - // SelectRepoBuild represents a query to select - // a build for a repo_id in the database. - SelectRepoBuild = ` -SELECT * -FROM builds -WHERE repo_id = ? -AND number = ? -LIMIT 1; -` - - // SelectLastRepoBuild represents a query to select - // the last build for a repo_id in the database. - SelectLastRepoBuild = ` -SELECT * -FROM builds -WHERE repo_id = ? -ORDER BY number DESC -LIMIT 1; -` - // SelectLastRepoBuildByBranch represents a query to - // select the last build for a repo_id and branch name - // in the database. - SelectLastRepoBuildByBranch = ` -SELECT * -FROM builds -WHERE repo_id = ? -AND branch = ? -ORDER BY number DESC -LIMIT 1; -` - - // SelectBuildsCount represents a query to select - // the count of builds in the database. - SelectBuildsCount = ` -SELECT count(*) as count -FROM builds; -` - - // SelectBuildsCountByStatus represents a query to select - // the count of builds for a status in the database. - SelectBuildsCountByStatus = ` -SELECT count(*) as count -FROM builds -WHERE status = ?; -` - - // DeleteBuild represents a query to - // remove a build from the database. - DeleteBuild = ` -DELETE -FROM builds -WHERE id = ?; -` - - // SelectPendingAndRunningBuilds represents a joined query - // between the builds & repos table to select - // the created builds that are in pending or running builds status - // since the specified timeframe. - SelectPendingAndRunningBuilds = ` -SELECT builds.created, builds.number, builds.status, repos.full_name -FROM builds INNER JOIN repos -ON builds.repo_id = repos.id -WHERE builds.created > ? -AND (builds.status = 'running' OR builds.status = 'pending'); -` -) diff --git a/database/sqlite/dml/doc.go b/database/sqlite/dml/doc.go deleted file mode 100644 index 151d8a9a5..000000000 --- a/database/sqlite/dml/doc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package dml provides the Sqlite data manipulation language (DML) for Vela. -// -// https://en.wikipedia.org/wiki/Data_manipulation_language -// -// Usage: -// -// import "github.com/go-vela/server/database/sqlite/dml" -package dml diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go index 3faa555ba..29f526643 100644 --- a/database/sqlite/sqlite.go +++ b/database/sqlite/sqlite.go @@ -5,9 +5,9 @@ package sqlite import ( - "fmt" "time" + "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -15,11 +15,9 @@ import ( "github.com/go-vela/server/database/schedule" "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/service" - "github.com/go-vela/server/database/sqlite/ddl" "github.com/go-vela/server/database/step" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" - "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" "gorm.io/driver/sqlite" @@ -50,6 +48,8 @@ type ( Sqlite *gorm.DB // https://pkg.go.dev/github.com/sirupsen/logrus#Entry Logger *logrus.Entry + // https://pkg.go.dev/github.com/go-vela/server/database/build#BuildInterface + build.BuildInterface // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface hook.HookInterface // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface @@ -177,12 +177,6 @@ func NewTest() (*client, error) { return nil, err } - // create the tables in the database - err = createTables(c) - if err != nil { - return nil, err - } - return c, nil } @@ -225,64 +219,6 @@ func setupDatabase(c *client) error { return nil } - // create the tables in the database - err = createTables(c) - if err != nil { - return err - } - - // create the indexes in the database - err = createIndexes(c) - if err != nil { - return err - } - - return nil -} - -// createTables is a helper function to setup -// the database with the necessary tables. -func createTables(c *client) error { - c.Logger.Trace("creating data tables in the sqlite database") - - // create the builds table - err := c.Sqlite.Exec(ddl.CreateBuildTable).Error - if err != nil { - return fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) - } - - return nil -} - -// createIndexes is a helper function to setup -// the database with the necessary indexes. -func createIndexes(c *client) error { - c.Logger.Trace("creating data indexes in the sqlite database") - - // create the builds_repo_id index for the builds table - err := c.Sqlite.Exec(ddl.CreateBuildRepoIDIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_repo_id index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_status index for the builds table - err = c.Sqlite.Exec(ddl.CreateBuildStatusIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_status index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_created index for the builds table - err = c.Sqlite.Exec(ddl.CreateBuildCreatedIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_created index for the %s table: %w", constants.TableBuild, err) - } - - // create the builds_source index for the builds table - err = c.Sqlite.Exec(ddl.CreateBuildSourceIndex).Error - if err != nil { - return fmt.Errorf("unable to create builds_source index for the %s table: %w", constants.TableBuild, err) - } - return nil } @@ -290,6 +226,18 @@ func createIndexes(c *client) error { func createServices(c *client) error { var err error + // create the database agnostic engine for builds + // + // https://pkg.go.dev/github.com/go-vela/server/database/build#New + c.BuildInterface, err = build.New( + build.WithClient(c.Sqlite), + build.WithLogger(c.Logger), + build.WithSkipCreation(c.config.SkipCreation), + ) + if err != nil { + return err + } + // create the database agnostic engine for hooks // // https://pkg.go.dev/github.com/go-vela/server/database/hook#New diff --git a/database/sqlite/sqlite_test.go b/database/sqlite/sqlite_test.go index 48ff34902..55c6940d0 100644 --- a/database/sqlite/sqlite_test.go +++ b/database/sqlite/sqlite_test.go @@ -7,8 +7,6 @@ package sqlite import ( "testing" "time" - - "github.com/go-vela/types/library" ) func TestSqlite_New(t *testing.T) { @@ -111,78 +109,6 @@ func TestSqlite_setupDatabase(t *testing.T) { } } -func TestSqlite_createTables(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createTables(_database) - - if test.failure { - if err == nil { - t.Errorf("createTables should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createTables returned err: %v", err) - } - } -} - -func TestSqlite_createIndexes(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createIndexes(_database) - - if test.failure { - if err == nil { - t.Errorf("createIndexes should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createIndexes returned err: %v", err) - } - } -} - func TestSqlite_createServices(t *testing.T) { // setup types // setup the test database client @@ -218,38 +144,3 @@ func TestSqlite_createServices(t *testing.T) { } } } - -// testRepo is a test helper function to create a -// library Repo type with all fields set to their -// zero values. -func testRepo() *library.Repo { - i64 := int64(0) - i := 0 - str := "" - b := false - - return &library.Repo{ - ID: &i64, - UserID: &i64, - Hash: &str, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - BuildLimit: &i64, - Timeout: &i64, - Counter: &i, - Visibility: &str, - Private: &b, - Trusted: &b, - Active: &b, - AllowPull: &b, - AllowPush: &b, - AllowDeploy: &b, - AllowTag: &b, - AllowComment: &b, - PreviousName: &str, - } -} diff --git a/router/middleware/build/build.go b/router/middleware/build/build.go index 87b25185b..6016adf3c 100644 --- a/router/middleware/build/build.go +++ b/router/middleware/build/build.go @@ -64,7 +64,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading build %s/%d", r.GetFullName(), number) - b, err := database.FromContext(c).GetBuild(number, r) + b, err := database.FromContext(c).GetBuildForRepo(r, number) if err != nil { retErr := fmt.Errorf("unable to read build %s/%d: %w", r.GetFullName(), number, err) util.HandleError(c, http.StatusNotFound, retErr) From f7c3c6b593305b1f0b1023c55a1519cd136e6d3d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 26 May 2023 13:39:32 -0600 Subject: [PATCH 245/298] refactor(db): return hook created or updated (#861) Co-authored-by: Jordan Brockopp --- api/admin/hook.go | 4 ++-- api/hook/create.go | 5 +---- api/hook/update.go | 5 +---- api/repo/create.go | 2 +- api/repo/repair.go | 2 +- api/webhook.go | 9 +++------ database/hook/count_repo_test.go | 4 ++-- database/hook/count_test.go | 4 ++-- database/hook/create.go | 11 +++++------ database/hook/create_test.go | 2 +- database/hook/delete_test.go | 2 +- database/hook/get_repo_test.go | 2 +- database/hook/get_test.go | 2 +- database/hook/interface.go | 4 ++-- database/hook/last_repo_test.go | 2 +- database/hook/list_repo_test.go | 4 ++-- database/hook/list_test.go | 4 ++-- database/hook/update.go | 11 +++++------ database/hook/update_test.go | 4 ++-- 19 files changed, 36 insertions(+), 47 deletions(-) diff --git a/api/admin/hook.go b/api/admin/hook.go index 322142d27..789a74a25 100644 --- a/api/admin/hook.go +++ b/api/admin/hook.go @@ -64,7 +64,7 @@ func UpdateHook(c *gin.Context) { } // send API call to update the hook - err = database.FromContext(c).UpdateHook(input) + h, err := database.FromContext(c).UpdateHook(input) if err != nil { retErr := fmt.Errorf("unable to update hook %d: %w", input.GetID(), err) @@ -73,5 +73,5 @@ func UpdateHook(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, h) } diff --git a/api/hook/create.go b/api/hook/create.go index 70f524524..b33d9fdfb 100644 --- a/api/hook/create.go +++ b/api/hook/create.go @@ -113,7 +113,7 @@ func CreateHook(c *gin.Context) { } // send API call to create the webhook - err = database.FromContext(c).CreateHook(input) + h, err := database.FromContext(c).CreateHook(input) if err != nil { retErr := fmt.Errorf("unable to create hook for repo %s: %w", r.GetFullName(), err) @@ -122,8 +122,5 @@ func CreateHook(c *gin.Context) { return } - // send API call to capture the created webhook - h, _ := database.FromContext(c).GetHookForRepo(r, input.GetNumber()) - c.JSON(http.StatusCreated, h) } diff --git a/api/hook/update.go b/api/hook/update.go index f8beeb1ec..2c5cdcfb7 100644 --- a/api/hook/update.go +++ b/api/hook/update.go @@ -157,7 +157,7 @@ func UpdateHook(c *gin.Context) { } // send API call to update the webhook - err = database.FromContext(c).UpdateHook(h) + h, err = database.FromContext(c).UpdateHook(h) if err != nil { retErr := fmt.Errorf("unable to update hook %s: %w", entry, err) @@ -166,8 +166,5 @@ func UpdateHook(c *gin.Context) { return } - // send API call to capture the updated user - h, _ = database.FromContext(c).GetHookForRepo(r, h.GetNumber()) - c.JSON(http.StatusOK, h) } diff --git a/api/repo/create.go b/api/repo/create.go index 91d42064e..e52cd23f4 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -316,7 +316,7 @@ func CreateRepo(c *gin.Context) { // update initialization hook h.SetRepoID(r.GetID()) // create first hook for repo in the database - err = database.FromContext(c).CreateHook(h) + _, err = database.FromContext(c).CreateHook(h) if err != nil { retErr := fmt.Errorf("unable to create initialization webhook for %s: %w", r.GetFullName(), err) diff --git a/api/repo/repair.go b/api/repo/repair.go index 424a7c0c1..192983d1c 100644 --- a/api/repo/repair.go +++ b/api/repo/repair.go @@ -107,7 +107,7 @@ func RepairRepo(c *gin.Context) { hook.SetRepoID(r.GetID()) - err = database.FromContext(c).CreateHook(hook) + _, err = database.FromContext(c).CreateHook(hook) if err != nil { retErr := fmt.Errorf("unable to create initialization webhook for %s: %w", r.GetFullName(), err) diff --git a/api/webhook.go b/api/webhook.go index 6881a03b7..fd958291c 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -177,7 +177,7 @@ func PostWebhook(c *gin.Context) { defer func() { // send API call to update the webhook - err = database.FromContext(c).UpdateHook(h) + _, err = database.FromContext(c).UpdateHook(h) if err != nil { logrus.Errorf("unable to update webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err) } @@ -219,7 +219,7 @@ func PostWebhook(c *gin.Context) { } // send API call to create the webhook - err = database.FromContext(c).CreateHook(h) + h, err = database.FromContext(c).CreateHook(h) if err != nil { retErr := fmt.Errorf("unable to create webhook %s/%d: %w", repo.GetFullName(), h.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -230,9 +230,6 @@ func PostWebhook(c *gin.Context) { return } - // send API call to capture the created webhook - h, _ = database.FromContext(c).GetHookForRepo(repo, h.GetNumber()) - // verify the webhook from the source control provider if c.Value("webhookvalidation").(bool) { err = scm.FromContext(c).VerifyWebhook(dupRequest, repo) @@ -765,7 +762,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r defer func() { // send API call to update the webhook - err := database.FromContext(c).CreateHook(h) + _, err := database.FromContext(c).CreateHook(h) if err != nil { logrus.Errorf("unable to create webhook %s/%d: %v", r.GetFullName(), h.GetNumber(), err) } diff --git a/database/hook/count_repo_test.go b/database/hook/count_repo_test.go index 83fe35dab..5814764e6 100644 --- a/database/hook/count_repo_test.go +++ b/database/hook/count_repo_test.go @@ -48,12 +48,12 @@ func TestHook_Engine_CountHooksForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hookOne) + _, err := _sqlite.CreateHook(_hookOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateHook(_hookTwo) + _, err = _sqlite.CreateHook(_hookTwo) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/count_test.go b/database/hook/count_test.go index 6e4df9df4..dce97587f 100644 --- a/database/hook/count_test.go +++ b/database/hook/count_test.go @@ -41,12 +41,12 @@ func TestHook_Engine_CountHooks(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hookOne) + _, err := _sqlite.CreateHook(_hookOne) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } - err = _sqlite.CreateHook(_hookTwo) + _, err = _sqlite.CreateHook(_hookTwo) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/create.go b/database/hook/create.go index ce3745da3..e2bf5489d 100644 --- a/database/hook/create.go +++ b/database/hook/create.go @@ -12,7 +12,7 @@ import ( ) // CreateHook creates a new hook in the database. -func (e *engine) CreateHook(h *library.Hook) error { +func (e *engine) CreateHook(h *library.Hook) (*library.Hook, error) { e.logger.WithFields(logrus.Fields{ "hook": h.GetNumber(), }).Tracef("creating hook %d in the database", h.GetNumber()) @@ -27,12 +27,11 @@ func (e *engine) CreateHook(h *library.Hook) error { // https://pkg.go.dev/github.com/go-vela/types/database#Hook.Validate err := hook.Validate() if err != nil { - return err + return nil, err } + result := e.client.Table(constants.TableHook).Create(hook) + // send query to the database - return e.client. - Table(constants.TableHook). - Create(hook). - Error + return hook.ToLibrary(), result.Error } diff --git a/database/hook/create_test.go b/database/hook/create_test.go index 1fd03f2b9..f05bd8a9d 100644 --- a/database/hook/create_test.go +++ b/database/hook/create_test.go @@ -57,7 +57,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateHook(_hook) + _, err := test.database.CreateHook(_hook) if test.failure { if err == nil { diff --git a/database/hook/delete_test.go b/database/hook/delete_test.go index e5deab7ad..2fb91d567 100644 --- a/database/hook/delete_test.go +++ b/database/hook/delete_test.go @@ -31,7 +31,7 @@ func TestHook_Engine_DeleteHook(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hook) + _, err := _sqlite.CreateHook(_hook) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/get_repo_test.go b/database/hook/get_repo_test.go index eb1103cad..32fb9a813 100644 --- a/database/hook/get_repo_test.go +++ b/database/hook/get_repo_test.go @@ -43,7 +43,7 @@ func TestHook_Engine_GetHookForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hook) + _, err := _sqlite.CreateHook(_hook) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/get_test.go b/database/hook/get_test.go index 79e8a9856..b84fe7b13 100644 --- a/database/hook/get_test.go +++ b/database/hook/get_test.go @@ -36,7 +36,7 @@ func TestHook_Engine_GetHook(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hook) + _, err := _sqlite.CreateHook(_hook) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/interface.go b/database/hook/interface.go index a1e5c5fe0..4ed44fd84 100644 --- a/database/hook/interface.go +++ b/database/hook/interface.go @@ -31,7 +31,7 @@ type HookInterface interface { // CountHooksForRepo defines a function that gets the count of hooks by repo ID. CountHooksForRepo(*library.Repo) (int64, error) // CreateHook defines a function that creates a new hook. - CreateHook(*library.Hook) error + CreateHook(*library.Hook) (*library.Hook, error) // DeleteHook defines a function that deletes an existing hook. DeleteHook(*library.Hook) error // GetHook defines a function that gets a hook by ID. @@ -45,5 +45,5 @@ type HookInterface interface { // ListHooksForRepo defines a function that gets a list of hooks by repo ID. ListHooksForRepo(*library.Repo, int, int) ([]*library.Hook, int64, error) // UpdateHook defines a function that updates an existing hook. - UpdateHook(*library.Hook) error + UpdateHook(*library.Hook) (*library.Hook, error) } diff --git a/database/hook/last_repo_test.go b/database/hook/last_repo_test.go index c7efeab75..ecd4a3eea 100644 --- a/database/hook/last_repo_test.go +++ b/database/hook/last_repo_test.go @@ -43,7 +43,7 @@ func TestHook_Engine_LastHookForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hook) + _, err := _sqlite.CreateHook(_hook) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/list_repo_test.go b/database/hook/list_repo_test.go index 709de156e..c229f5674 100644 --- a/database/hook/list_repo_test.go +++ b/database/hook/list_repo_test.go @@ -58,12 +58,12 @@ func TestHook_Engine_ListHooksForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hookOne) + _, err := _sqlite.CreateHook(_hookOne) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } - err = _sqlite.CreateHook(_hookTwo) + _, err = _sqlite.CreateHook(_hookTwo) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/list_test.go b/database/hook/list_test.go index ba0784213..e2fb33772 100644 --- a/database/hook/list_test.go +++ b/database/hook/list_test.go @@ -51,12 +51,12 @@ func TestHook_Engine_ListHooks(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hookOne) + _, err := _sqlite.CreateHook(_hookOne) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } - err = _sqlite.CreateHook(_hookTwo) + _, err = _sqlite.CreateHook(_hookTwo) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } diff --git a/database/hook/update.go b/database/hook/update.go index cfc746303..d7741f249 100644 --- a/database/hook/update.go +++ b/database/hook/update.go @@ -12,7 +12,7 @@ import ( ) // UpdateHook updates an existing hook in the database. -func (e *engine) UpdateHook(h *library.Hook) error { +func (e *engine) UpdateHook(h *library.Hook) (*library.Hook, error) { e.logger.WithFields(logrus.Fields{ "hook": h.GetNumber(), }).Tracef("updating hook %d in the database", h.GetNumber()) @@ -27,12 +27,11 @@ func (e *engine) UpdateHook(h *library.Hook) error { // https://pkg.go.dev/github.com/go-vela/types/database#Hook.Validate err := hook.Validate() if err != nil { - return err + return nil, err } + result := e.client.Table(constants.TableHook).Save(hook) + // send query to the database - return e.client. - Table(constants.TableHook). - Save(hook). - Error + return hook.ToLibrary(), result.Error } diff --git a/database/hook/update_test.go b/database/hook/update_test.go index a1f0d8de2..cbb309897 100644 --- a/database/hook/update_test.go +++ b/database/hook/update_test.go @@ -33,7 +33,7 @@ WHERE "id" = $14`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateHook(_hook) + _, err := _sqlite.CreateHook(_hook) if err != nil { t.Errorf("unable to create test hook for sqlite: %v", err) } @@ -59,7 +59,7 @@ WHERE "id" = $14`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateHook(_hook) + _, err = test.database.UpdateHook(_hook) if test.failure { if err == nil { From 2f1b70ed763dd1b44dccefac14affc4da6f9f043 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 30 May 2023 13:23:12 -0600 Subject: [PATCH 246/298] feat(templates): add ability to call templates within a template (#794) * yeet * initial work * remove unnecessary validation check * adding some comments * remove edits to inline testing * fix typo * render inline init work * support for render_inline * address feedback * validate template depth * added tests for compile inline * add test for error with called render_inline template in step * drop vs code nonsense * add github compiler flags to env example --------- Co-authored-by: Jacob Floyd Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- .env.example | 14 +- cmd/vela-server/main.go | 6 + cmd/vela-server/validate.go | 4 + compiler/engine.go | 4 +- compiler/native/compile.go | 31 +- compiler/native/compile_test.go | 192 ++++++++++ compiler/native/expand.go | 24 +- compiler/native/expand_test.go | 349 +++++++++++++++++- compiler/native/native.go | 4 + compiler/native/testdata/circular.yml | 16 + .../testdata/inline_circular_template.yml | 19 + .../testdata/inline_nested_template.yml | 19 + compiler/native/testdata/nested.yml | 23 ++ .../testdata/template-calls-itself.json | 18 + .../testdata/template-calls-template.json | 18 + compiler/template/native/render.go | 2 +- 16 files changed, 723 insertions(+), 20 deletions(-) create mode 100644 compiler/native/testdata/circular.yml create mode 100644 compiler/native/testdata/inline_circular_template.yml create mode 100644 compiler/native/testdata/inline_nested_template.yml create mode 100644 compiler/native/testdata/nested.yml create mode 100644 compiler/native/testdata/template-calls-itself.json create mode 100644 compiler/native/testdata/template-calls-template.json diff --git a/.env.example b/.env.example index c5bf492e9..fdffdf154 100644 --- a/.env.example +++ b/.env.example @@ -58,4 +58,16 @@ VELA_API=http://localhost:8080 # VELA_SCM_CLIENT= # github client secret from oauth application -# VELA_SCM_SECRET= \ No newline at end of file +# VELA_SCM_SECRET= + +# COMPILER FLAGS +# +# compiler github is whether or not the compiler uses github to pull templates +# +# default: false +# VELA_COMPILER_GITHUB= + +# compiler github url is the url used by the compiler to fetch templates +# +# default: https://github.com +# VELA_COMPILER_GITHUB_URL \ No newline at end of file diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 48b67af59..f9b160a8f 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -197,6 +197,12 @@ func main() { Usage: "modification retries, used by compiler, number of http requires that the modification http request will fail after", Value: 5, }, + &cli.IntFlag{ + EnvVars: []string{"VELA_MAX_TEMPLATE_DEPTH", "MAX_TEMPLATE_DEPTH"}, + Name: "max-template-depth", + Usage: "max template depth, used by compiler, maximum number of templates that can be called in a template chain", + Value: 3, + }, &cli.DurationFlag{ EnvVars: []string{"VELA_WORKER_ACTIVE_INTERVAL", "WORKER_ACTIVE_INTERVAL"}, Name: "worker-active-interval", diff --git a/cmd/vela-server/validate.go b/cmd/vela-server/validate.go index bce8b12fb..cac3b0424 100644 --- a/cmd/vela-server/validate.go +++ b/cmd/vela-server/validate.go @@ -117,5 +117,9 @@ func validateCompiler(c *cli.Context) error { } } + if c.Int("max-template-depth") < 1 { + return fmt.Errorf("max-template-depth (VELA_MAX_TEMPLATE_DEPTH) or (MAX_TEMPLATE_DEPTH) flag must be greater than 0") + } + return nil } diff --git a/compiler/engine.go b/compiler/engine.go index dfe0716c4..5d1d32993 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -73,8 +73,8 @@ type Engine interface { // for each templated step in every stage in a yaml configuration. ExpandStages(*yaml.Build, map[string]*yaml.Template, *pipeline.RuleData) (*yaml.Build, error) // ExpandSteps defines a function that injects the template - // for each templated step in a yaml configuration. - ExpandSteps(*yaml.Build, map[string]*yaml.Template, *pipeline.RuleData) (*yaml.Build, error) + // for each templated step in a yaml configuration with the provided template depth. + ExpandSteps(*yaml.Build, map[string]*yaml.Template, *pipeline.RuleData, int) (*yaml.Build, error) // Init Compiler Interface Functions diff --git a/compiler/native/compile.go b/compiler/native/compile.go index a36ddc113..f74e19bab 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -82,7 +82,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err switch { case p.Metadata.RenderInline: - newPipeline, err := c.compileInline(p, nil) + newPipeline, err := c.compileInline(p, nil, c.TemplateDepth) if err != nil { return nil, _pipeline, err } @@ -117,7 +117,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp _pipeline.SetType(c.repo.GetPipelineType()) if p.Metadata.RenderInline { - newPipeline, err := c.compileInline(p, localTemplates) + newPipeline, err := c.compileInline(p, localTemplates, c.TemplateDepth) if err != nil { return nil, _pipeline, err } @@ -169,7 +169,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp } case len(p.Steps) > 0: // inject the templates into the steps - p, err = c.ExpandSteps(p, templates, nil) + p, err = c.ExpandSteps(p, templates, nil, c.TemplateDepth) if err != nil { return nil, _pipeline, err } @@ -194,10 +194,17 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp } // compileInline parses and expands out inline pipelines. -func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Build, error) { +func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int) (*yaml.Build, error) { newPipeline := *p newPipeline.Templates = yaml.TemplateSlice{} + // return if max template depth has been reached + if depth == 0 { + retErr := fmt.Errorf("max template depth of %d exceeded", c.TemplateDepth) + + return nil, retErr + } + for _, template := range p.Templates { if c.local { for _, file := range localTemplates { @@ -231,6 +238,14 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu return nil, err } + // if template parsed contains a template reference, recurse with decremented depth + if len(parsed.Templates) > 0 && parsed.Metadata.RenderInline { + parsed, err = c.compileInline(parsed, localTemplates, depth-1) + if err != nil { + return nil, err + } + } + switch { case len(parsed.Environment) > 0: for key, value := range parsed.Environment { @@ -276,12 +291,6 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string) (*yaml.Bu } } - // validate the yaml configuration - err := c.Validate(&newPipeline) - if err != nil { - return nil, err - } - return &newPipeline, nil } @@ -307,7 +316,7 @@ func (c *client) compileSteps(p *yaml.Build, _pipeline *library.Pipeline, tmpls } // inject the templates into the steps - p, err = c.ExpandSteps(p, tmpls, r) + p, err = c.ExpandSteps(p, tmpls, r, c.TemplateDepth) if err != nil { return nil, _pipeline, err } diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 5ea927b33..67c89f3a2 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -38,6 +38,7 @@ func TestNative_Compile_StagesPipeline(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -417,6 +418,7 @@ func TestNative_Compile_StepsPipeline(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -619,6 +621,7 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -883,6 +886,7 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1112,6 +1116,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName(t *testi set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1231,6 +1236,7 @@ func TestNative_Compile_StepsPipelineTemplate_VelaFunction_TemplateName_Inline(t set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1346,6 +1352,7 @@ func TestNative_Compile_InvalidType(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1402,6 +1409,7 @@ func TestNative_Compile_Clone(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -1592,6 +1600,7 @@ func TestNative_Compile_Pipeline_Type(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -2161,6 +2170,7 @@ func Test_Compile_Inline(t *testing.T) { set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") set.String("clone-image", defaultCloneImage, "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ @@ -2360,6 +2370,179 @@ func Test_Compile_Inline(t *testing.T) { }, wantErr: false, }, + { + name: "nested templates", + args: args{ + file: "testdata/inline_nested_template.yml", + }, + want: &pipeline.Build{ + Version: "1", + ID: "__0", + Metadata: pipeline.Metadata{ + Clone: true, + Environment: []string{"steps", "services", "secrets"}, + }, + Stages: []*pipeline.Stage{ + { + Name: "init", + Environment: initEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_init_init", + Directory: "/vela/src/foo//", + Environment: initEnv, + Image: "#init", + Name: "init", + Number: 1, + Pull: "not_present", + }, + }, + }, + { + Name: "clone", + Environment: initEnv, + Steps: pipeline.ContainerSlice{ + &pipeline.Container{ + ID: "__0_clone_clone", + Directory: "/vela/src/foo//", + Environment: initEnv, + Image: defaultCloneImage, + Name: "clone", + Number: 2, + Pull: "not_present", + }, + }, + }, + { + Name: "test", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_test_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline", m, ""), + Image: "alpine", + Name: "test", + Pull: "not_present", + Number: 3, + }, + }, + }, + { + Name: "nested_test", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_test_nested_test", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo from inline", m, ""), + Image: "alpine", + Name: "nested_test", + Pull: "not_present", + Number: 4, + }, + }, + }, + { + Name: "nested_golang_foo", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_golang_foo_nested_golang_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, ""), + Image: "golang:latest", + Name: "nested_golang_foo", + Pull: "not_present", + Number: 5, + }, + }, + }, + { + Name: "nested_golang_bar", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_golang_bar_nested_golang_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, ""), + Image: "golang:latest", + Name: "nested_golang_bar", + Pull: "not_present", + Number: 6, + }, + }, + }, + { + Name: "nested_golang_star", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_golang_star_nested_golang_star", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from star", m, ""), + Image: "golang:latest", + Name: "nested_golang_star", + Pull: "not_present", + Number: 7, + }, + }, + }, + { + Name: "nested_starlark_foo", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_starlark_foo_nested_starlark_build_foo", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from foo", m, ""), + Image: "alpine", + Name: "nested_starlark_build_foo", + Pull: "not_present", + Number: 8, + }, + }, + }, + { + Name: "nested_starlark_bar", + Needs: []string{"clone"}, + Environment: initEnv, + Steps: []*pipeline.Container{ + { + ID: "__0_nested_starlark_bar_nested_starlark_build_bar", + Commands: []string{"echo $VELA_BUILD_SCRIPT | base64 -d | /bin/sh -e"}, + Directory: "/vela/src/foo//", + Entrypoint: []string{"/bin/sh", "-c"}, + Environment: generateTestEnv("echo hello from bar", m, ""), + Image: "alpine", + Name: "nested_starlark_build_bar", + Pull: "not_present", + Number: 9, + }, + }, + }, + }, + }, + wantErr: false, + }, { name: "root steps", args: args{ @@ -2468,6 +2651,14 @@ func Test_Compile_Inline(t *testing.T) { want: nil, wantErr: true, }, + { + name: "circular template call", + args: args{ + file: "testdata/inline_circular_template.yml", + }, + want: nil, + wantErr: true, + }, { name: "secrets", args: args{ @@ -2944,6 +3135,7 @@ func Test_CompileLite(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) m := &types.Metadata{ diff --git a/compiler/native/expand.go b/compiler/native/expand.go index 102ae9774..5314cf25e 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -31,7 +31,7 @@ func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template, r // iterate through all stages for _, stage := range s.Stages { // inject the templates into the steps for the stage - p, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls, r) + p, err := c.ExpandSteps(&yaml.Build{Steps: stage.Steps, Secrets: s.Secrets, Services: s.Services, Environment: s.Environment}, tmpls, r, c.TemplateDepth) if err != nil { return nil, err } @@ -47,11 +47,18 @@ func (c *client) ExpandStages(s *yaml.Build, tmpls map[string]*yaml.Template, r // ExpandSteps injects the template for each // templated step in a yaml configuration. -func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData) (*yaml.Build, error) { +func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template, r *pipeline.RuleData, depth int) (*yaml.Build, error) { if len(tmpls) == 0 { return s, nil } + // return if max template depth has been reached + if depth == 0 { + retErr := fmt.Errorf("max template depth of %d exceeded", c.TemplateDepth) + + return s, retErr + } + steps := yaml.StepSlice{} secrets := s.Secrets services := s.Services @@ -117,6 +124,19 @@ func (c *client) ExpandSteps(s *yaml.Build, tmpls map[string]*yaml.Template, r * return s, err } + // if template references other templates, expand again + if len(tmplBuild.Templates) != 0 { + // if the tmplBuild has render_inline but the parent build does not, abort + if tmplBuild.Metadata.RenderInline && !s.Metadata.RenderInline { + return s, fmt.Errorf("cannot use render_inline inside a called template (%s)", step.Template.Name) + } + + tmplBuild, err = c.ExpandSteps(tmplBuild, mapFromTemplates(tmplBuild.Templates), r, depth-1) + if err != nil { + return s, err + } + } + // loop over secrets within template for _, secret := range tmplBuild.Secrets { found := false diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index c89d23d50..a32a2286d 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -43,6 +43,7 @@ func TestNative_ExpandStages(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) tmpls := map[string]*yaml.Template{ @@ -190,6 +191,7 @@ func TestNative_ExpandSteps(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) testRepo := new(library.Repo) @@ -317,7 +319,7 @@ func TestNative_ExpandSteps(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData)) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData), compiler.TemplateDepth) if err != nil { t.Errorf("ExpandSteps_Type%s returned err: %v", test.name, err) } @@ -368,6 +370,7 @@ func TestNative_ExpandStepsMulti(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) tmpls := map[string]*yaml.Template{ @@ -582,7 +585,7 @@ func TestNative_ExpandStepsMulti(t *testing.T) { ruledata := new(pipeline.RuleData) ruledata.Branch = "main" - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, ruledata) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, ruledata, compiler.TemplateDepth) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } @@ -626,6 +629,7 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { set.Bool("github-driver", true, "doc") set.String("github-url", s.URL, "doc") set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) tmpls := map[string]*yaml.Template{ @@ -669,7 +673,7 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { t.Errorf("Creating new compiler returned err: %v", err) } - build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, new(pipeline.RuleData)) + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Secrets: yaml.SecretSlice{}, Services: yaml.ServiceSlice{}, Environment: raw.StringSliceMap{}}, tmpls, new(pipeline.RuleData), compiler.TemplateDepth) if err != nil { t.Errorf("ExpandSteps returned err: %v", err) } @@ -691,6 +695,345 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { } } +func TestNative_ExpandSteps_TemplateCallTemplate(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/template.json") + }) + + engine.GET("/api/v3/repos/faz/baz/contents/:path", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/template-calls-template.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") + c := cli.NewContext(nil, set, nil) + + testBuild := new(library.Build) + + testBuild.SetID(1) + testBuild.SetCommit("123abc456def") + + testRepo := new(library.Repo) + + testRepo.SetID(1) + testRepo.SetOrg("foo") + testRepo.SetName("bar") + + tests := []struct { + name string + tmpls map[string]*yaml.Template + }{ + { + name: "Test 1", + tmpls: map[string]*yaml.Template{ + "chain": { + Name: "chain", + Source: "github.example.com/faz/baz/template.yml", + Type: "github", + }, + }, + }, + } + + steps := yaml.StepSlice{ + &yaml.Step{ + Name: "sample", + Template: yaml.StepTemplate{ + Name: "chain", + }, + }, + } + + globalEnvironment := raw.StringSliceMap{ + "foo": "test1", + "bar": "test2", + } + + wantSteps := yaml.StepSlice{ + &yaml.Step{ + Commands: []string{"./gradlew downloadDependencies"}, + Environment: raw.StringSliceMap{ + "GRADLE_OPTS": "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=1 -Dorg.gradle.parallel=false", + "GRADLE_USER_HOME": ".gradle", + }, + Image: "openjdk:latest", + Name: "sample_call template_install", + Pull: "always", + }, + &yaml.Step{ + Commands: []string{"./gradlew check"}, + Environment: raw.StringSliceMap{ + "GRADLE_OPTS": "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=1 -Dorg.gradle.parallel=false", + "GRADLE_USER_HOME": ".gradle", + }, + Image: "openjdk:latest", + Name: "sample_call template_test", + Pull: "always", + }, + &yaml.Step{ + Commands: []string{"./gradlew build"}, + Environment: raw.StringSliceMap{ + "GRADLE_OPTS": "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=1 -Dorg.gradle.parallel=false", + "GRADLE_USER_HOME": ".gradle", + }, + Image: "openjdk:latest", + Name: "sample_call template_build", + Pull: "always", + }, + } + + wantSecrets := yaml.SecretSlice{ + &yaml.Secret{ + Name: "docker_username", + Key: "org/repo/foo/bar", + Engine: "native", + Type: "repo", + Origin: yaml.Origin{}, + }, + &yaml.Secret{ + Name: "foo_password", + Key: "org/repo/foo/password", + Engine: "vault", + Type: "repo", + Origin: yaml.Origin{}, + }, + } + + wantServices := yaml.ServiceSlice{ + &yaml.Service{ + Image: "postgres:12", + Name: "postgres", + Pull: "not_present", + }, + } + + wantEnvironment := raw.StringSliceMap{ + "foo": "test1", + "bar": "test2", + "star": "test3", + } + + // run test + compiler, err := New(c) + if err != nil { + t.Errorf("Creating new compiler returned err: %v", err) + } + + compiler.WithBuild(testBuild).WithRepo(testRepo) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + build, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData), compiler.TemplateDepth) + if err != nil { + t.Errorf("ExpandSteps_Type%s returned err: %v", test.name, err) + } + + if diff := cmp.Diff(build.Steps, wantSteps); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + + if diff := cmp.Diff(build.Secrets, wantSecrets); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + + if diff := cmp.Diff(build.Services, wantServices); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + + if diff := cmp.Diff(build.Environment, wantEnvironment); diff != "" { + t.Errorf("ExpandSteps()_Type%s mismatch (-want +got):\n%s", test.name, diff) + } + }) + } +} + +func TestNative_ExpandSteps_TemplateCallTemplate_CircularFail(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + engine.GET("/api/v3/repos/bad/design/contents/:path", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/template-calls-itself.json") + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") + c := cli.NewContext(nil, set, nil) + + testBuild := new(library.Build) + + testBuild.SetID(1) + testBuild.SetCommit("123abc456def") + + testRepo := new(library.Repo) + + testRepo.SetID(1) + testRepo.SetOrg("foo") + testRepo.SetName("bar") + + tests := []struct { + name string + tmpls map[string]*yaml.Template + }{ + { + name: "Test 1", + tmpls: map[string]*yaml.Template{ + "circle": { + Name: "circle", + Source: "github.example.com/bad/design/template.yml", + Type: "github", + }, + }, + }, + } + + steps := yaml.StepSlice{ + &yaml.Step{ + Name: "sample", + Template: yaml.StepTemplate{ + Name: "circle", + }, + }, + } + + globalEnvironment := raw.StringSliceMap{ + "foo": "test1", + "bar": "test2", + } + + // run test + compiler, err := New(c) + if err != nil { + t.Errorf("Creating new compiler returned err: %v", err) + } + + compiler.WithBuild(testBuild).WithRepo(testRepo) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData), compiler.TemplateDepth) + if err == nil { + t.Errorf("ExpandSteps_Type%s should have returned an error", test.name) + } + }) + } +} + +func TestNative_ExpandSteps_CallTemplateWithRenderInline(t *testing.T) { + // setup context + gin.SetMode(gin.TestMode) + + resp := httptest.NewRecorder() + _, engine := gin.CreateTestContext(resp) + + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) + }) + + s := httptest.NewServer(engine) + defer s.Close() + + // setup types + set := flag.NewFlagSet("test", 0) + set.Bool("github-driver", true, "doc") + set.String("github-url", s.URL, "doc") + set.String("github-token", "", "doc") + set.Int("max-template-depth", 5, "doc") + c := cli.NewContext(nil, set, nil) + + testBuild := new(library.Build) + + testBuild.SetID(1) + testBuild.SetCommit("123abc456def") + + testRepo := new(library.Repo) + + testRepo.SetID(1) + testRepo.SetOrg("foo") + testRepo.SetName("bar") + + tests := []struct { + name string + tmpls map[string]*yaml.Template + }{ + { + name: "Test 1", + tmpls: map[string]*yaml.Template{ + "render_inline": { + Name: "render_inline", + Source: "github.example.com/github/octocat/nested.yml", + Type: "github", + }, + }, + }, + } + + steps := yaml.StepSlice{ + &yaml.Step{ + Name: "sample", + Template: yaml.StepTemplate{ + Name: "render_inline", + }, + }, + } + + globalEnvironment := raw.StringSliceMap{ + "foo": "test1", + "bar": "test2", + } + + // run test + compiler, err := New(c) + if err != nil { + t.Errorf("Creating new compiler returned err: %v", err) + } + + compiler.WithBuild(testBuild).WithRepo(testRepo) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, err := compiler.ExpandSteps(&yaml.Build{Steps: steps, Services: yaml.ServiceSlice{}, Environment: globalEnvironment}, test.tmpls, new(pipeline.RuleData), compiler.TemplateDepth) + if err == nil { + t.Errorf("ExpandSteps_Type%s should have returned an error", test.name) + } + }) + } +} + func TestNative_mapFromTemplates(t *testing.T) { // setup types str := "foo" diff --git a/compiler/native/native.go b/compiler/native/native.go index 61b411838..733a32407 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -32,6 +32,7 @@ type client struct { UsePrivateGithub bool ModificationService ModificationConfig CloneImage string + TemplateDepth int build *library.Build comment string @@ -71,6 +72,8 @@ func New(ctx *cli.Context) (*client, error) { // set the clone image to use for the injected clone step c.CloneImage = ctx.String("clone-image") + c.TemplateDepth = ctx.Int("max-template-depth") + if ctx.Bool("github-driver") { logrus.Tracef("setting up Private GitHub Client for %s", ctx.String("github-url")) // setup private github service @@ -110,6 +113,7 @@ func (c *client) Duplicate() compiler.Engine { cc.UsePrivateGithub = c.UsePrivateGithub cc.ModificationService = c.ModificationService cc.CloneImage = c.CloneImage + cc.TemplateDepth = c.TemplateDepth return cc } diff --git a/compiler/native/testdata/circular.yml b/compiler/native/testdata/circular.yml new file mode 100644 index 000000000..bd8327df3 --- /dev/null +++ b/compiler/native/testdata/circular.yml @@ -0,0 +1,16 @@ +metadata: + render_inline: true + template: true + +templates: + - name: bad + source: github.example.com/github/octocat/inline_circular_template.yml + type: github + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_circular_template.yml b/compiler/native/testdata/inline_circular_template.yml new file mode 100644 index 000000000..4b0469c58 --- /dev/null +++ b/compiler/native/testdata/inline_circular_template.yml @@ -0,0 +1,19 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: nested + source: github.example.com/github/octocat/circular.yml + type: github + vars: + image: golang:latest + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/inline_nested_template.yml b/compiler/native/testdata/inline_nested_template.yml new file mode 100644 index 000000000..0faaeb0c8 --- /dev/null +++ b/compiler/native/testdata/inline_nested_template.yml @@ -0,0 +1,19 @@ +version: "1" + +metadata: + render_inline: true + +templates: + - name: nested + source: github.example.com/github/octocat/nested.yml + type: github + vars: + image: golang:latest + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/nested.yml b/compiler/native/testdata/nested.yml new file mode 100644 index 000000000..2d44729d7 --- /dev/null +++ b/compiler/native/testdata/nested.yml @@ -0,0 +1,23 @@ +metadata: + render_inline: true + template: true + +templates: + - name: golang + source: github.example.com/github/octocat/golang_inline_stages.yml + format: golang + type: github + vars: + image: golang:latest + - name: starlark + source: github.example.com/github/octocat/starlark_inline_stages.star + format: starlark + type: github + +stages: + test: + steps: + - name: test + image: alpine + commands: + - echo from inline \ No newline at end of file diff --git a/compiler/native/testdata/template-calls-itself.json b/compiler/native/testdata/template-calls-itself.json new file mode 100644 index 000000000..a930d6780 --- /dev/null +++ b/compiler/native/testdata/template-calls-itself.json @@ -0,0 +1,18 @@ +{ + "type": "file", + "encoding": "base64", + "size": 5362, + "name": "template.yml", + "path": "template.yml", + "content": "dmVyc2lvbjogIjEiCgp0ZW1wbGF0ZXM6CiAgLSBuYW1lOiB0ZXN0CiAgICBzb3VyY2U6IGdpdGh1Yi5leGFtcGxlLmNvbS9iYWQvZGVzaWduL3RlbXBsYXRlLnltbAogICAgdHlwZTogZ2l0aHViCgpzdGVwczoKICAtIG5hbWU6IGNhbGwgdGVtcGxhdGUKICAgIHRlbXBsYXRlOgogICAgICBuYW1lOiB0ZXN0Cg==", + "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", + "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", + "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.yml", + "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.yml", + "_links": { + "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", + "html": "https://github.com/octokit/octokit.rb/blob/master/template.yml" + } +} \ No newline at end of file diff --git a/compiler/native/testdata/template-calls-template.json b/compiler/native/testdata/template-calls-template.json new file mode 100644 index 000000000..6fb0be303 --- /dev/null +++ b/compiler/native/testdata/template-calls-template.json @@ -0,0 +1,18 @@ +{ + "type": "file", + "encoding": "base64", + "size": 5362, + "name": "template.yml", + "path": "template.yml", + "content": "dmVyc2lvbjogIjEiCgp0ZW1wbGF0ZXM6CiAgLSBuYW1lOiB0ZXN0CiAgICBzb3VyY2U6IGdpdGh1Yi5leGFtcGxlLmNvbS9mb28vYmFyL3RlbXBsYXRlLnltbAogICAgdHlwZTogZ2l0aHViCgpzdGVwczoKICAtIG5hbWU6IGNhbGwgdGVtcGxhdGUKICAgIHRlbXBsYXRlOgogICAgICBuYW1lOiB0ZXN0CiAgICAgIHZhcnM6CiAgICAgICAgaW1hZ2U6IG9wZW5qZGs6bGF0ZXN0CiAgICAgICAgZW52aXJvbm1lbnQ6ICJ7IEdSQURMRV9VU0VSX0hPTUU6IC5ncmFkbGUsIEdSQURMRV9PUFRTOiAtRG9yZy5ncmFkbGUuZGFlbW9uPWZhbHNlIC1Eb3JnLmdyYWRsZS53b3JrZXJzLm1heD0xIC1Eb3JnLmdyYWRsZS5wYXJhbGxlbD1mYWxzZSB9IgogICAgICAgIHB1bGxfcG9saWN5OiAicHVsbDogdHJ1ZSIK", + "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", + "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", + "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.yml", + "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.yml", + "_links": { + "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", + "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", + "html": "https://github.com/octokit/octokit.rb/blob/master/template.yml" + } +} \ No newline at end of file diff --git a/compiler/template/native/render.go b/compiler/template/native/render.go index 95389fd1d..869e4588a 100644 --- a/compiler/template/native/render.go +++ b/compiler/template/native/render.go @@ -61,7 +61,7 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM config.Steps[index].Name = fmt.Sprintf("%s_%s", name, newStep.Name) } - return &types.Build{Steps: config.Steps, Secrets: config.Secrets, Services: config.Services, Environment: config.Environment}, nil + return &types.Build{Metadata: config.Metadata, Steps: config.Steps, Secrets: config.Secrets, Services: config.Services, Environment: config.Environment, Templates: config.Templates}, nil } // RenderBuild renders the templated build. From ca68a09f317b1e9e477b5e79f9cb5d0aa499fcde Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 30 May 2023 13:28:16 -0600 Subject: [PATCH 247/298] feat(api/admin): add endpoint to clean pending / running builds (#863) * feat(api/admin): add endpoint to clean pending / running builds * db tests * add mock * actually use the mock * info logrus logging for each table clean * add msg and finished to resources update --- api/admin/clean.go | 135 +++++++++++++++++++++++++++++++++ database/build/clean.go | 35 +++++++++ database/build/clean_test.go | 120 +++++++++++++++++++++++++++++ database/build/interface.go | 2 + database/service/clean.go | 35 +++++++++ database/service/clean_test.go | 131 ++++++++++++++++++++++++++++++++ database/service/interface.go | 2 + database/step/clean.go | 35 +++++++++ database/step/clean_test.go | 131 ++++++++++++++++++++++++++++++++ database/step/interface.go | 2 + mock/server/build.go | 22 ++++++ mock/server/server.go | 1 + router/admin.go | 4 + 13 files changed, 655 insertions(+) create mode 100644 api/admin/clean.go create mode 100644 database/build/clean.go create mode 100644 database/build/clean_test.go create mode 100644 database/service/clean.go create mode 100644 database/service/clean_test.go create mode 100644 database/step/clean.go create mode 100644 database/step/clean_test.go diff --git a/api/admin/clean.go b/api/admin/clean.go new file mode 100644 index 000000000..4895c3e55 --- /dev/null +++ b/api/admin/clean.go @@ -0,0 +1,135 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package admin + +import ( + "fmt" + "net/http" + "strconv" + "time" + + "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" + "github.com/go-vela/types/constants" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/admin/clean admin AdminCleanResources +// +// Update pending build resources to error status before a given time +// +// --- +// produces: +// - application/json +// parameters: +// - in: query +// name: before +// description: filter pending resources created before a certain time +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing error message +// required: true +// schema: +// "$ref": "#/definitions/Error" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated pending resources with error message +// schema: +// type: string +// '400': +// description: Unable to update resources — bad request +// schema: +// "$ref": "#/definitions/Error" +// '401': +// description: Unable to update resources — unauthorized +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update resources +// schema: +// "$ref": "#/definitions/Error" + +// CleanResources represents the API handler to +// update any user stored in the database. +func CleanResources(c *gin.Context) { + u := user.Retrieve(c) + logrus.Infof("platform admin %s: updating pending resources in database", u.GetName()) + + // default error message + msg := "build cleaned by platform admin" + + // capture body from API request + input := new(types.Error) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for error message: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // if a message is provided, set the error message to that + if input.Message != nil { + msg = *input.Message + } + + // capture before query parameter, default to max build timeout + before, err := strconv.ParseInt(c.DefaultQuery("before", fmt.Sprint((time.Now().Add(-(time.Minute * (constants.BuildTimeoutMax + 5)))).Unix())), 10, 64) + if err != nil { + retErr := fmt.Errorf("unable to convert before query parameter %s to int64: %w", c.Query("before"), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to clean builds + builds, err := database.FromContext(c).CleanBuilds(msg, before) + if err != nil { + retErr := fmt.Errorf("unable to update builds: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + logrus.Infof("platform admin %s: cleaned %d builds in database", u.GetName(), builds) + + // clean services + services, err := database.FromContext(c).CleanServices(msg, before) + if err != nil { + retErr := fmt.Errorf("%d builds cleaned. unable to update services: %w", builds, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + logrus.Infof("platform admin %s: cleaned %d services in database", u.GetName(), services) + + // clean steps + steps, err := database.FromContext(c).CleanSteps(msg, before) + if err != nil { + retErr := fmt.Errorf("%d builds cleaned. %d services cleaned. unable to update steps: %w", builds, services, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + logrus.Infof("platform admin %s: cleaned %d steps in database", u.GetName(), steps) + + c.JSON(http.StatusOK, fmt.Sprintf("%d builds cleaned. %d services cleaned. %d steps cleaned.", builds, services, steps)) +} diff --git a/database/build/clean.go b/database/build/clean.go new file mode 100644 index 000000000..5e0541b35 --- /dev/null +++ b/database/build/clean.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "time" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CleanBuilds updates builds to an error with a provided message with a created timestamp prior to a defined moment. +func (e *engine) CleanBuilds(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.SetStatus(constants.StatusError) + b.SetError(msg) + b.SetFinished(time.Now().UTC().Unix()) + + build := database.BuildFromLibrary(b) + + // send query to the database + result := e.client. + Table(constants.TableBuild). + Where("created < ?", before). + Where("status = 'running' OR status = 'pending'"). + Updates(build) + + return result.RowsAffected, result.Error +} diff --git a/database/build/clean_test.go b/database/build/clean_test.go new file mode 100644 index 000000000..ab91da075 --- /dev/null +++ b/database/build/clean_test.go @@ -0,0 +1,120 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestBuild_Engine_CleanBuilds(t *testing.T) { + // setup types + _buildOne := testBuild() + _buildOne.SetID(1) + _buildOne.SetRepoID(1) + _buildOne.SetNumber(1) + _buildOne.SetCreated(1) + _buildOne.SetStatus("pending") + + _buildTwo := testBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepoID(1) + _buildTwo.SetNumber(2) + _buildTwo.SetCreated(2) + _buildTwo.SetStatus("running") + + // setup types + _buildThree := testBuild() + _buildThree.SetID(3) + _buildThree.SetRepoID(1) + _buildThree.SetNumber(3) + _buildThree.SetCreated(1) + _buildThree.SetStatus("success") + + _buildFour := testBuild() + _buildFour.SetID(4) + _buildFour.SetRepoID(1) + _buildFour.SetNumber(4) + _buildFour.SetCreated(5) + _buildFour.SetStatus("running") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the name query + _mock.ExpectExec(`UPDATE "builds" SET "status"=$1,"error"=$2,"finished"=$3,"deploy_payload"=$4 WHERE created < $5 AND (status = 'running' OR status = 'pending')`). + WithArgs("error", "msg", time.Now().UTC().Unix(), AnyArgument{}, 3). + WillReturnResult(sqlmock.NewResult(1, 2)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuild(_buildOne) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildTwo) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildThree) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + err = _sqlite.CreateBuild(_buildFour) + if err != nil { + t.Errorf("unable to create test build for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CleanBuilds("msg", 3) + + if test.failure { + if err == nil { + t.Errorf("CleanBuilds for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CleanBuilds for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CleanBuilds for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/build/interface.go b/database/build/interface.go index e4264f6a8..6a14ad4f8 100644 --- a/database/build/interface.go +++ b/database/build/interface.go @@ -26,6 +26,8 @@ type BuildInterface interface { // // https://en.wikipedia.org/wiki/Data_manipulation_language + // CleanBuilds defines a function that sets pending or running builds to error created before a given time. + CleanBuilds(string, int64) (int64, error) // CountBuilds defines a function that gets the count of all builds. CountBuilds() (int64, error) // CountBuildsForDeployment defines a function that gets the count of builds by deployment url. diff --git a/database/service/clean.go b/database/service/clean.go new file mode 100644 index 000000000..e8bcac16d --- /dev/null +++ b/database/service/clean.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "time" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CleanServices updates services to an error with a created timestamp prior to a defined moment. +func (e *engine) CleanServices(msg string, before int64) (int64, error) { + logrus.Tracef("cleaning pending or running steps in the database created prior to %d", before) + + s := new(library.Service) + s.SetStatus(constants.StatusError) + s.SetError(msg) + s.SetFinished(time.Now().UTC().Unix()) + + service := database.ServiceFromLibrary(s) + + // send query to the database + result := e.client. + Table(constants.TableService). + Where("created < ?", before). + Where("status = 'running' OR status = 'pending'"). + Updates(service) + + return result.RowsAffected, result.Error +} diff --git a/database/service/clean_test.go b/database/service/clean_test.go new file mode 100644 index 000000000..f30939880 --- /dev/null +++ b/database/service/clean_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestService_Engine_CleanService(t *testing.T) { + // setup types + _serviceOne := testService() + _serviceOne.SetID(1) + _serviceOne.SetRepoID(1) + _serviceOne.SetBuildID(1) + _serviceOne.SetNumber(1) + _serviceOne.SetName("foo") + _serviceOne.SetImage("bar") + _serviceOne.SetCreated(1) + _serviceOne.SetStatus("running") + + _serviceTwo := testService() + _serviceTwo.SetID(2) + _serviceTwo.SetRepoID(1) + _serviceTwo.SetBuildID(1) + _serviceTwo.SetNumber(2) + _serviceTwo.SetName("foo") + _serviceTwo.SetImage("bar") + _serviceTwo.SetCreated(1) + _serviceTwo.SetStatus("pending") + + _serviceThree := testService() + _serviceThree.SetID(3) + _serviceThree.SetRepoID(1) + _serviceThree.SetBuildID(1) + _serviceThree.SetNumber(3) + _serviceThree.SetName("foo") + _serviceThree.SetImage("bar") + _serviceThree.SetCreated(1) + _serviceThree.SetStatus("success") + + _serviceFour := testService() + _serviceFour.SetID(4) + _serviceFour.SetRepoID(1) + _serviceFour.SetBuildID(1) + _serviceFour.SetNumber(4) + _serviceFour.SetName("foo") + _serviceFour.SetImage("bar") + _serviceFour.SetCreated(5) + _serviceFour.SetStatus("pending") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the name query + _mock.ExpectExec(`UPDATE "services" SET "status"=$1,"error"=$2,"finished"=$3 WHERE created < $4 AND (status = 'running' OR status = 'pending')`). + WithArgs("error", "msg", time.Now().UTC().Unix(), 3). + WillReturnResult(sqlmock.NewResult(1, 2)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateService(_serviceOne) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceTwo) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceThree) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + err = _sqlite.CreateService(_serviceFour) + if err != nil { + t.Errorf("unable to create test service for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CleanServices("msg", 3) + + if test.failure { + if err == nil { + t.Errorf("CleanServices for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CleanServices for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CleanServices for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/service/interface.go b/database/service/interface.go index 29cb0f457..d22595859 100644 --- a/database/service/interface.go +++ b/database/service/interface.go @@ -24,6 +24,8 @@ type ServiceInterface interface { // // https://en.wikipedia.org/wiki/Data_manipulation_language + // CleanServices defines a function that sets running or pending services to error status before a given created time. + CleanServices(string, int64) (int64, error) // CountServices defines a function that gets the count of all services. CountServices() (int64, error) // CountServicesForBuild defines a function that gets the count of services by build ID. diff --git a/database/step/clean.go b/database/step/clean.go new file mode 100644 index 000000000..54e686e86 --- /dev/null +++ b/database/step/clean.go @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "time" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CleanSteps updates steps to an error with a created timestamp prior to a defined moment. +func (e *engine) CleanSteps(msg string, before int64) (int64, error) { + logrus.Tracef("cleaning pending or running steps in the database created prior to %d", before) + + s := new(library.Step) + s.SetStatus(constants.StatusError) + s.SetError(msg) + s.SetFinished(time.Now().UTC().Unix()) + + step := database.StepFromLibrary(s) + + // send query to the database + result := e.client. + Table(constants.TableStep). + Where("created < ?", before). + Where("status = 'running' OR status = 'pending'"). + Updates(step) + + return result.RowsAffected, result.Error +} diff --git a/database/step/clean_test.go b/database/step/clean_test.go new file mode 100644 index 000000000..22709749a --- /dev/null +++ b/database/step/clean_test.go @@ -0,0 +1,131 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "reflect" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestStep_Engine_CleanStep(t *testing.T) { + // setup types + _stepOne := testStep() + _stepOne.SetID(1) + _stepOne.SetRepoID(1) + _stepOne.SetBuildID(1) + _stepOne.SetNumber(1) + _stepOne.SetName("foo") + _stepOne.SetImage("bar") + _stepOne.SetCreated(1) + _stepOne.SetStatus("running") + + _stepTwo := testStep() + _stepTwo.SetID(2) + _stepTwo.SetRepoID(1) + _stepTwo.SetBuildID(1) + _stepTwo.SetNumber(2) + _stepTwo.SetName("foo") + _stepTwo.SetImage("bar") + _stepTwo.SetCreated(1) + _stepTwo.SetStatus("pending") + + _stepThree := testStep() + _stepThree.SetID(3) + _stepThree.SetRepoID(1) + _stepThree.SetBuildID(1) + _stepThree.SetNumber(3) + _stepThree.SetName("foo") + _stepThree.SetImage("bar") + _stepThree.SetCreated(1) + _stepThree.SetStatus("success") + + _stepFour := testStep() + _stepFour.SetID(4) + _stepFour.SetRepoID(1) + _stepFour.SetBuildID(1) + _stepFour.SetNumber(4) + _stepFour.SetName("foo") + _stepFour.SetImage("bar") + _stepFour.SetCreated(5) + _stepFour.SetStatus("pending") + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the name query + _mock.ExpectExec(`UPDATE "steps" SET "status"=$1,"error"=$2,"finished"=$3 WHERE created < $4 AND (status = 'running' OR status = 'pending')`). + WithArgs("error", "msg", time.Now().UTC().Unix(), 3). + WillReturnResult(sqlmock.NewResult(1, 2)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateStep(_stepOne) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepTwo) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepThree) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + err = _sqlite.CreateStep(_stepFour) + if err != nil { + t.Errorf("unable to create test step for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want int64 + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: 2, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: 2, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.CleanSteps("msg", 3) + + if test.failure { + if err == nil { + t.Errorf("CleanSteps for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CleanSteps for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("CleanSteps for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/step/interface.go b/database/step/interface.go index a410f2600..68423c8c9 100644 --- a/database/step/interface.go +++ b/database/step/interface.go @@ -24,6 +24,8 @@ type StepInterface interface { // // https://en.wikipedia.org/wiki/Data_manipulation_language + // CleanSteps defines a function that sets running or pending steps to error status before a given created time. + CleanSteps(string, int64) (int64, error) // CountSteps defines a function that gets the count of all steps. CountSteps() (int64, error) // CountStepsForBuild defines a function that gets the count of steps by build ID. diff --git a/mock/server/build.go b/mock/server/build.go index 37809bae4..db526cb29 100644 --- a/mock/server/build.go +++ b/mock/server/build.go @@ -149,6 +149,8 @@ const ( BuildTokenResp = `{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJidWlsZF9pZCI6MSwicmVwbyI6ImZvby9iYXIiLCJzdWIiOiJPY3RvY2F0IiwiaWF0IjoxNTE2MjM5MDIyfQ.hD7gXpaf9acnLBdOBa4GOEa5KZxdzd0ZvK6fGwaN4bc" }` + + CleanResourcesResp = "42 builds cleaned. 42 services cleaned. 42 steps cleaned." ) // getBuilds returns mock JSON for a http GET. @@ -337,3 +339,23 @@ func buildToken(c *gin.Context) { c.JSON(http.StatusOK, body) } + +// cleanResources has a query param :before returns mock JSON for a http PUT +// +// Pass "0" to :before to test receiving a http 500 response. Pass "1" to :before +// to test receiving a http 401 response. +func cleanResoures(c *gin.Context) { + before := c.Query("before") + + if strings.EqualFold(before, "0") { + c.AbortWithStatusJSON(http.StatusInternalServerError, "") + + return + } + + if strings.EqualFold(before, "1") { + c.AbortWithStatusJSON(http.StatusUnauthorized, "") + } + + c.JSON(http.StatusOK, CleanResourcesResp) +} diff --git a/mock/server/server.go b/mock/server/server.go index 8fb6b1061..d2f6ccbab 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -30,6 +30,7 @@ func FakeHandler() http.Handler { e.PUT("/api/v1/admin/step", updateStep) e.PUT("/api/v1/admin/user", updateUser) e.POST("/api/v1/admin/workers/:worker/register-token", registerToken) + e.PUT("api/v1/admin/clean", cleanResoures) // mock endpoints for build calls e.GET("/api/v1/repos/:org/:repo/builds/:build", getBuild) diff --git a/router/admin.go b/router/admin.go index f7fddf95f..96764617f 100644 --- a/router/admin.go +++ b/router/admin.go @@ -16,6 +16,7 @@ import ( // GET /api/v1/admin/builds/queue // GET /api/v1/admin/build/:id // PUT /api/v1/admin/build +// PUT /api/v1/admin/clean // PUT /api/v1/admin/deployment // PUT /api/v1/admin/hook // PUT /api/v1/admin/repo @@ -33,6 +34,9 @@ func AdminHandlers(base *gin.RouterGroup) { // Admin build endpoint _admin.PUT("/build", admin.UpdateBuild) + // Admin clean endpoint + _admin.PUT("/clean", admin.CleanResources) + // Admin deployment endpoint _admin.PUT("/deployment", admin.UpdateDeployment) From a5fc7c68a372938e5c6ed3be182a7052ea2a9f24 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 30 May 2023 13:33:58 -0600 Subject: [PATCH 248/298] refactor(api): move build logic to separate package (#864) * init commit * remove cleanBuild helper in favor of CleanBuild * planStep helper and address feedback and upgrade types * update path in swagger for org list builds * flaky linter overlord --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/build.go | 2185 --------------------- api/build/cancel.go | 289 +++ api/build/clean.go | 56 + api/build/create.go | 392 ++++ api/build/delete.go | 92 + api/build/doc.go | 10 + api/build/get.go | 70 + api/build/get_id.go | 118 ++ api/build/list_org.go | 195 ++ api/build/list_repo.go | 259 +++ api/build/plan.go | 71 + api/build/publish.go | 74 + api/build/restart.go | 362 ++++ api/build/skip.go | 41 + api/{build_test.go => build/skip_test.go} | 2 +- api/build/token.go | 119 ++ api/build/update.go | 186 ++ api/service/plan.go | 71 + api/step/plan.go | 97 + api/webhook/doc.go | 10 + api/{webhook.go => webhook/post.go} | 68 +- cmd/vela-server/schedule.go | 8 +- go.mod | 2 +- go.sum | 4 +- router/build.go | 28 +- router/repo.go | 4 +- router/router.go | 3 +- router/search.go | 6 +- 28 files changed, 2547 insertions(+), 2275 deletions(-) delete mode 100644 api/build.go create mode 100644 api/build/cancel.go create mode 100644 api/build/clean.go create mode 100644 api/build/create.go create mode 100644 api/build/delete.go create mode 100644 api/build/doc.go create mode 100644 api/build/get.go create mode 100644 api/build/get_id.go create mode 100644 api/build/list_org.go create mode 100644 api/build/list_repo.go create mode 100644 api/build/plan.go create mode 100644 api/build/publish.go create mode 100644 api/build/restart.go create mode 100644 api/build/skip.go rename api/{build_test.go => build/skip_test.go} (99%) create mode 100644 api/build/token.go create mode 100644 api/build/update.go create mode 100644 api/service/plan.go create mode 100644 api/step/plan.go create mode 100644 api/webhook/doc.go rename api/{webhook.go => webhook/post.go} (93%) diff --git a/api/build.go b/api/build.go deleted file mode 100644 index cd6c8b86f..000000000 --- a/api/build.go +++ /dev/null @@ -1,2185 +0,0 @@ -// Copyright (c) 2023 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package api - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/compiler" - "github.com/go-vela/server/database" - "github.com/go-vela/server/internal/token" - "github.com/go-vela/server/queue" - "github.com/go-vela/server/router/middleware/build" - "github.com/go-vela/server/router/middleware/claims" - "github.com/go-vela/server/router/middleware/executors" - "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/scm" - "github.com/go-vela/server/util" - "github.com/go-vela/types" - "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" - "github.com/go-vela/types/pipeline" - "github.com/sirupsen/logrus" -) - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds builds CreateBuild -// -// Create a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: body -// name: body -// description: Payload containing the build to update -// required: true -// schema: -// "$ref": "#/definitions/Build" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Request processed but build was skipped -// schema: -// type: string -// '201': -// description: Successfully created the build -// type: json -// schema: -// "$ref": "#/definitions/Build" -// '400': -// description: Unable to create the build -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to create the build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to create the build -// schema: -// "$ref": "#/definitions/Error" - -// CreateBuild represents the API handler to create a build in the configured backend. -// -//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity -func CreateBuild(c *gin.Context) { - // capture middleware values - m := c.MustGet("metadata").(*types.Metadata) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logger := logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }) - - logger.Infof("creating new build for repo %s", r.GetFullName()) - - // capture body from API request - input := new(library.Build) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for new build for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // verify the build has a valid event and the repo allows that event type - if (input.GetEvent() == constants.EventPush && !r.GetAllowPush()) || - (input.GetEvent() == constants.EventPull && !r.GetAllowPull()) || - (input.GetEvent() == constants.EventTag && !r.GetAllowTag()) || - (input.GetEvent() == constants.EventDeploy && !r.GetAllowDeploy()) { - retErr := fmt.Errorf("unable to create new build: %s does not have %s events enabled", r.GetFullName(), input.GetEvent()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the repo owner - u, err = database.FromContext(c).GetUser(r.GetUserID()) - if err != nil { - retErr := fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // create SQL filters for querying pending and running builds for repo - filters := map[string]interface{}{ - "status": []string{constants.StatusPending, constants.StatusRunning}, - } - - // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) - if err != nil { - retErr := fmt.Errorf("unable to create new build: unable to get count of builds for repo %s", r.GetFullName()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // check if the number of pending and running builds exceeds the limit for the repo - if builds >= r.GetBuildLimit() { - retErr := fmt.Errorf("unable to create new build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in build object - input.SetRepoID(r.GetID()) - input.SetStatus(constants.StatusPending) - input.SetCreated(time.Now().UTC().Unix()) - - // set the parent equal to the current repo counter - input.SetParent(r.GetCounter()) - // check if the parent is set to 0 - if input.GetParent() == 0 { - // parent should be "1" if it's the first build ran - input.SetParent(1) - } - - // update the build numbers based off repo counter - inc := r.GetCounter() + 1 - r.SetCounter(inc) - input.SetNumber(inc) - - // populate the build link if a web address is provided - if len(m.Vela.WebAddress) > 0 { - input.SetLink( - fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), input.GetNumber()), - ) - } - - // variable to store changeset files - var files []string - // check if the build event is not issue_comment or pull_request - if !strings.EqualFold(input.GetEvent(), constants.EventComment) && - !strings.EqualFold(input.GetEvent(), constants.EventPull) { - // send API call to capture list of files changed for the commit - files, err = scm.FromContext(c).Changeset(u, r, input.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - // check if the build event is a pull_request - if strings.EqualFold(input.GetEvent(), constants.EventPull) { - // capture number from build - number, err := getPRNumberFromBuild(input) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to get pull_request number for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture list of files changed for the pull request - files, err = scm.FromContext(c).ChangesetPR(u, r, number) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - var ( - // variable to store the raw pipeline configuration - config []byte - // variable to store executable pipeline - p *pipeline.Build - // variable to store pipeline configuration - pipeline *library.Pipeline - // variable to store the pipeline type for the repository - pipelineType = r.GetPipelineType() - ) - - // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) - if err != nil { // assume the pipeline doesn't exist in the database yet - // send API call to capture the pipeline configuration file - config, err = scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to get pipeline configuration for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } else { - config = pipeline.GetData() - } - - // ensure we use the expected pipeline type when compiling - // - // The pipeline type for a repo can change at any time which can break compiling - // existing pipelines in the system for that repo. To account for this, we update - // the repo pipeline type to match what was defined for the existing pipeline - // before compiling. After we're done compiling, we reset the pipeline type. - if len(pipeline.GetType()) > 0 { - r.SetPipelineType(pipeline.GetType()) - } - - var compiled *library.Pipeline - // parse and compile the pipeline configuration file - p, compiled, err = compiler.FromContext(c). - Duplicate(). - WithBuild(input). - WithCommit(input.GetCommit()). - WithFiles(files). - WithMetadata(m). - WithRepo(r). - WithUser(u). - Compile(config) - if err != nil { - retErr := fmt.Errorf("unable to compile pipeline configuration for %s/%d: %w", r.GetFullName(), input.GetNumber(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // reset the pipeline type for the repo - // - // The pipeline type for a repo can change at any time which can break compiling - // existing pipelines in the system for that repo. To account for this, we update - // the repo pipeline type to match what was defined for the existing pipeline - // before compiling. After we're done compiling, we reset the pipeline type. - r.SetPipelineType(pipelineType) - - // skip the build if only the init or clone steps are found - skip := SkipEmptyBuild(p) - if skip != "" { - // set build to successful status - input.SetStatus(constants.StatusSuccess) - - // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) - if err != nil { - logger.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), input.GetNumber(), err) - } - - c.JSON(http.StatusOK, skip) - - return - } - - // check if the pipeline did not already exist in the database - // - //nolint:dupl // ignore duplicate code - if pipeline == nil { - pipeline = compiled - pipeline.SetRepoID(r.GetID()) - pipeline.SetCommit(input.GetCommit()) - pipeline.SetRef(input.GetRef()) - - // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(pipeline) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to create pipeline for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to create new build: failed to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - input.SetPipelineID(pipeline.GetID()) - - // create the objects from the pipeline in the database - err = PlanBuild(database.FromContext(c), p, input, r) - if err != nil { - util.HandleError(c, http.StatusInternalServerError, err) - - return - } - - // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to create new build: failed to update repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the created build - input, _ = database.FromContext(c).GetBuildForRepo(r, input.GetNumber()) - - c.JSON(http.StatusCreated, input) - - // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) - if err != nil { - logger.Errorf("unable to set commit status for build %s/%d: %v", r.GetFullName(), input.GetNumber(), err) - } - - // publish the build to the queue - go PublishToQueue( - queue.FromGinContext(c), - database.FromContext(c), - p, - input, - r, - u, - ) -} - -// SkipEmptyBuild checks if the build should be skipped due to it -// not containing any steps besides init or clone. -// -//nolint:goconst // ignore init and clone constants -func SkipEmptyBuild(p *pipeline.Build) string { - if len(p.Stages) == 1 { - if p.Stages[0].Name == "init" { - return "skipping build since only init stage found" - } - } - - if len(p.Stages) == 2 { - if p.Stages[0].Name == "init" && p.Stages[1].Name == "clone" { - return "skipping build since only init and clone stages found" - } - } - - if len(p.Steps) == 1 { - if p.Steps[0].Name == "init" { - return "skipping build since only init step found" - } - } - - if len(p.Steps) == 2 { - if p.Steps[0].Name == "init" && p.Steps[1].Name == "clone" { - return "skipping build since only init and clone steps found" - } - } - - return "" -} - -// swagger:operation GET /api/v1/search/builds/{id} builds GetBuildByID -// -// Get a single build by its id in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: id -// description: build id -// required: true -// type: number -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved build -// schema: -// "$ref": "#/definitions/Build" -// '400': -// description: Unable to retrieve the build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the build -// schema: -// "$ref": "#/definitions/Error" - -// 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 *library.Repo - ) - - // Capture user from middleware - u := user.Retrieve(c) - - // Parse build ID from path - id, err := strconv.ParseInt(c.Param("id"), 10, 64) - - if err != nil { - retErr := fmt.Errorf("unable to parse build id: %w", err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": id, - "user": u.GetName(), - }).Infof("reading build %d", id) - - // Get build from database - b, err = database.FromContext(c).GetBuild(id) - if err != nil { - retErr := fmt.Errorf("unable to get build: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // Get repo from database using repo ID field from build - r, err = database.FromContext(c).GetRepo(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(u, u.GetToken(), r.GetOrg(), r.GetName()) - if err != nil { - logrus.Errorf("unable to get user %s access level for repo %s", u.GetName(), r.GetFullName()) - } - - // Ensure that user has at least read access to repo to return the build - if perm == "none" && !u.GetAdmin() { - retErr := fmt.Errorf("unable to retrieve build %d: user does not have read access to repo %s", id, r.GetFullName()) - - util.HandleError(c, http.StatusUnauthorized, retErr) - - return - } - - c.JSON(http.StatusOK, b) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds builds GetBuilds -// -// Get builds from the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: query -// name: event -// description: Filter by build event -// type: string -// enum: -// - push -// - pull_request -// - tag -// - deployment -// - comment -// - in: query -// name: commit -// description: Filter builds based on the commit hash -// type: string -// - in: query -// name: branch -// description: Filter builds by branch -// type: string -// - in: query -// name: status -// description: Filter by build status -// type: string -// enum: -// - canceled -// - error -// - failure -// - killed -// - pending -// - running -// - success -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// - in: query -// name: before -// description: filter builds created before a certain time -// type: integer -// default: 1 -// - in: query -// name: after -// description: filter builds created after a certain time -// type: integer -// default: 0 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the builds -// schema: -// type: array -// items: -// "$ref": "#/definitions/Build" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of builds -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of builds -// schema: -// "$ref": "#/definitions/Error" - -// GetBuilds represents the API handler to capture a -// list of builds for a repo from the configured backend. -func GetBuilds(c *gin.Context) { - // variables that will hold the build list, build list filters and total count - var ( - filters = map[string]interface{}{} - b []*library.Build - t int64 - ) - - // capture middleware values - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading builds for repo %s", r.GetFullName()) - - // capture the branch name parameter - branch := c.Query("branch") - // capture the event type parameter - event := c.Query("event") - // capture the status type parameter - status := c.Query("status") - // capture the commit hash parameter - commit := c.Query("commit") - - // check if branch filter was provided - if len(branch) > 0 { - // add branch to filters map - filters["branch"] = branch - } - // check if event filter was provided - if len(event) > 0 { - // verify the event provided is a valid event type - if event != constants.EventComment && event != constants.EventDeploy && - event != constants.EventPush && event != constants.EventPull && - event != constants.EventTag { - retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // add event to filters map - filters["event"] = event - } - // check if status filter was provided - if len(status) > 0 { - // verify the status provided is a valid status type - if status != constants.StatusCanceled && status != constants.StatusError && - status != constants.StatusFailure && status != constants.StatusKilled && - status != constants.StatusPending && status != constants.StatusRunning && - status != constants.StatusSuccess { - retErr := fmt.Errorf("unable to process status %s: invalid status type provided", status) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // add status to filters map - filters["status"] = status - } - - // check if commit hash filter was provided - if len(commit) > 0 { - // add commit to filters map - filters["commit"] = commit - } - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // capture before query parameter if present, default to now - before, err := strconv.ParseInt(c.DefaultQuery("before", strconv.FormatInt(time.Now().UTC().Unix(), 10)), 10, 64) - if err != nil { - retErr := fmt.Errorf("unable to convert before query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture after query parameter if present, default to 0 - after, err := strconv.ParseInt(c.DefaultQuery("after", "0"), 10, 64) - if err != nil { - retErr := fmt.Errorf("unable to convert after query parameter for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - b, t, err = database.FromContext(c).ListBuildsForRepo(r, filters, before, after, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to get builds for repo %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, b) -} - -// swagger:operation GET /api/v1/repos/{org} builds GetOrgBuilds -// -// Get a list of builds by org in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: query -// name: page -// description: The page of results to retrieve -// type: integer -// default: 1 -// - in: query -// name: per_page -// description: How many results per page to return -// type: integer -// maximum: 100 -// default: 10 -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved build list -// schema: -// type: array -// items: -// "$ref": "#/definitions/Build" -// headers: -// X-Total-Count: -// description: Total number of results -// type: integer -// Link: -// description: see https://tools.ietf.org/html/rfc5988 -// type: string -// '400': -// description: Unable to retrieve the list of builds -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to retrieve the list of builds -// schema: -// "$ref": "#/definitions/Error" - -// GetOrgBuilds represents the API handler to capture a -// list of builds associated with an org from the configured backend. -func GetOrgBuilds(c *gin.Context) { - // variables that will hold the build list, build list filters and total count - var ( - filters = map[string]interface{}{} - b []*library.Build - t int64 - ) - - // capture middleware values - o := org.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "org": o, - "user": u.GetName(), - }).Infof("reading builds for org %s", o) - - // capture the branch name parameter - branch := c.Query("branch") - // capture the event type parameter - event := c.Query("event") - // capture the status type parameter - status := c.Query("status") - - // check if branch filter was provided - if len(branch) > 0 { - // add branch to filters map - filters["branch"] = branch - } - // check if event filter was provided - if len(event) > 0 { - // verify the event provided is a valid event type - if event != constants.EventComment && event != constants.EventDeploy && - event != constants.EventPush && event != constants.EventPull && - event != constants.EventTag { - retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // add event to filters map - filters["event"] = event - } - // check if status filter was provided - if len(status) > 0 { - // verify the status provided is a valid status type - if status != constants.StatusCanceled && status != constants.StatusError && - status != constants.StatusFailure && status != constants.StatusKilled && - status != constants.StatusPending && status != constants.StatusRunning && - status != constants.StatusSuccess { - retErr := fmt.Errorf("unable to process status %s: invalid status type provided", status) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // add status to filters map - filters["status"] = status - } - - // capture page query parameter if present - page, err := strconv.Atoi(c.DefaultQuery("page", "1")) - if err != nil { - retErr := fmt.Errorf("unable to convert page query parameter for org %s: %w", o, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // capture per_page query parameter if present - perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) - if err != nil { - retErr := fmt.Errorf("unable to convert per_page query parameter for Org %s: %w", o, err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // ensure per_page isn't above or below allowed values - perPage = util.MaxInt(1, util.MinInt(100, perPage)) - - // See if the user is an org admin to bypass individual permission checks - perm, err := scm.FromContext(c).OrgAccess(u, o) - if err != nil { - logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) - } - // Only show public repos to non-admins - //nolint:goconst // ignore need for constant - if perm != "admin" { - filters["visibility"] = constants.VisibilityPublic - } - - // send API call to capture the list of builds for the org (and event type if passed in) - b, t, err = database.FromContext(c).ListBuildsForOrg(o, filters, page, perPage) - - if err != nil { - retErr := fmt.Errorf("unable to get builds for org %s: %w", o, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // create pagination object - pagination := Pagination{ - Page: page, - PerPage: perPage, - Total: t, - } - // set pagination headers - pagination.SetHeaderLink(c) - - c.JSON(http.StatusOK, b) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build} builds GetBuild -// -// Get a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number to retrieve -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved the build -// type: json -// schema: -// "$ref": "#/definitions/Build" - -// GetBuild represents the API handler to capture -// a build for a repo from the configured backend. -func GetBuild(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("reading build %s/%d", r.GetFullName(), b.GetNumber()) - - c.JSON(http.StatusOK, b) -} - -// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build} builds RestartBuild -// -// Restart a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number to restart -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Request processed but build was skipped -// schema: -// type: string -// '201': -// description: Successfully restarted the build -// schema: -// "$ref": "#/definitions/Build" -// '400': -// description: Unable to restart the build -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to restart the build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to restart the build -// schema: -// "$ref": "#/definitions/Error" - -// RestartBuild represents the API handler to restart an existing build in the configured backend. -// -//nolint:funlen // ignore statement count -func RestartBuild(c *gin.Context) { - // capture middleware values - m := c.MustGet("metadata").(*types.Metadata) - cl := claims.Retrieve(c) - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logger := logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }) - - logger.Infof("restarting build %s", entry) - - // send API call to capture the repo owner - u, err := database.FromContext(c).GetUser(r.GetUserID()) - if err != nil { - retErr := fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // create SQL filters for querying pending and running builds for repo - filters := map[string]interface{}{ - "status": []string{constants.StatusPending, constants.StatusRunning}, - } - - // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) - if err != nil { - retErr := fmt.Errorf("unable to restart build: unable to get count of builds for repo %s", r.GetFullName()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // check if the number of pending and running builds exceeds the limit for the repo - if builds >= r.GetBuildLimit() { - retErr := fmt.Errorf("unable to restart build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // update fields in build object - b.SetID(0) - b.SetCreated(time.Now().UTC().Unix()) - b.SetEnqueued(0) - b.SetStarted(0) - b.SetFinished(0) - b.SetStatus(constants.StatusPending) - b.SetHost("") - b.SetRuntime("") - b.SetDistribution("") - b.SetSender(cl.Subject) - - // update the PR event action if action was never set - // for backwards compatibility with pre-0.14 releases. - if b.GetEvent() == constants.EventPull && b.GetEventAction() == "" { - // technically, the action could have been opened or synchronize. - // will not affect behavior of the pipeline since we did not - // support actions for builds where this would be the case. - b.SetEventAction(constants.ActionOpened) - } - - // set the parent equal to the restarted build number - b.SetParent(b.GetNumber()) - // update the build numbers based off repo counter - inc := r.GetCounter() + 1 - r.SetCounter(inc) - b.SetNumber(inc) - - // populate the build link if a web address is provided - if len(m.Vela.WebAddress) > 0 { - b.SetLink( - fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), b.GetNumber()), - ) - } - - // variable to store changeset files - var files []string - // check if the build event is not issue_comment or pull_request - if !strings.EqualFold(b.GetEvent(), constants.EventComment) && - !strings.EqualFold(b.GetEvent(), constants.EventPull) { - // send API call to capture list of files changed for the commit - files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - // check if the build event is a pull_request - if strings.EqualFold(b.GetEvent(), constants.EventPull) { - // capture number from build - number, err := getPRNumberFromBuild(b) - if err != nil { - retErr := fmt.Errorf("unable to restart build: failed to get pull_request number for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture list of files changed for the pull request - files, err = scm.FromContext(c).ChangesetPR(u, r, number) - if err != nil { - retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - // variables to store pipeline configuration - var ( - // variable to store the raw pipeline configuration - config []byte - // variable to store executable pipeline - p *pipeline.Build - // variable to store pipeline configuration - pipeline *library.Pipeline - // variable to store the pipeline type for the repository - pipelineType = r.GetPipelineType() - ) - - // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) - if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) - // send API call to capture the pipeline configuration file - config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) - if err != nil { - retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } else { - config = pipeline.GetData() - } - - // ensure we use the expected pipeline type when compiling - // - // The pipeline type for a repo can change at any time which can break compiling - // existing pipelines in the system for that repo. To account for this, we update - // the repo pipeline type to match what was defined for the existing pipeline - // before compiling. After we're done compiling, we reset the pipeline type. - if len(pipeline.GetType()) > 0 { - r.SetPipelineType(pipeline.GetType()) - } - - var compiled *library.Pipeline - // parse and compile the pipeline configuration file - p, compiled, err = compiler.FromContext(c). - Duplicate(). - WithBuild(b). - WithCommit(b.GetCommit()). - WithFiles(files). - WithMetadata(m). - WithRepo(r). - WithUser(u). - Compile(config) - if err != nil { - retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // reset the pipeline type for the repo - // - // The pipeline type for a repo can change at any time which can break compiling - // existing pipelines in the system for that repo. To account for this, we update - // the repo pipeline type to match what was defined for the existing pipeline - // before compiling. After we're done compiling, we reset the pipeline type. - r.SetPipelineType(pipelineType) - - // skip the build if only the init or clone steps are found - skip := SkipEmptyBuild(p) - if skip != "" { - // set build to successful status - b.SetStatus(constants.StatusSkipped) - - // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) - if err != nil { - logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err) - } - - c.JSON(http.StatusOK, skip) - - return - } - - // check if the pipeline did not already exist in the database - // - //nolint:dupl // ignore duplicate code - if pipeline == nil { - pipeline = compiled - pipeline.SetRepoID(r.GetID()) - pipeline.SetCommit(b.GetCommit()) - pipeline.SetRef(b.GetRef()) - - // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(pipeline) - if err != nil { - retErr := fmt.Errorf("unable to create pipeline for %s: %w", r.GetFullName(), err) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - } - - b.SetPipelineID(pipeline.GetID()) - - // create the objects from the pipeline in the database - err = PlanBuild(database.FromContext(c), p, b, r) - if err != nil { - util.HandleError(c, http.StatusInternalServerError, err) - - return - } - - // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(r) - if err != nil { - retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %w", r.GetFullName(), err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // send API call to capture the restarted build - b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) - - c.JSON(http.StatusCreated, b) - - // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) - if err != nil { - logger.Errorf("unable to set commit status for build %s: %v", entry, err) - } - - // publish the build to the queue - go PublishToQueue( - queue.FromGinContext(c), - database.FromContext(c), - p, - b, - r, - u, - ) -} - -// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build} builds UpdateBuild -// -// Updates a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number to update -// required: true -// type: integer -// - in: body -// name: body -// description: Payload containing the build to update -// required: true -// schema: -// "$ref": "#/definitions/Build" -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully updated the build -// schema: -// "$ref": "#/definitions/Build" -// '404': -// description: Unable to update the build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to update the build -// schema: -// "$ref": "#/definitions/Error" - -// UpdateBuild represents the API handler to update -// a build for a repo in the configured backend. -func UpdateBuild(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("updating build %s", entry) - - // capture body from API request - input := new(library.Build) - - err := c.Bind(input) - if err != nil { - retErr := fmt.Errorf("unable to decode JSON for build %s: %w", entry, err) - - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // update build fields if provided - if len(input.GetStatus()) > 0 { - // update status if set - b.SetStatus(input.GetStatus()) - } - - if len(input.GetError()) > 0 { - // update error if set - b.SetError(input.GetError()) - } - - if input.GetEnqueued() > 0 { - // update enqueued if set - b.SetEnqueued(input.GetEnqueued()) - } - - if input.GetStarted() > 0 { - // update started if set - b.SetStarted(input.GetStarted()) - } - - if input.GetFinished() > 0 { - // update finished if set - b.SetFinished(input.GetFinished()) - } - - if len(input.GetTitle()) > 0 { - // update title if set - b.SetTitle(input.GetTitle()) - } - - if len(input.GetMessage()) > 0 { - // update message if set - b.SetMessage(input.GetMessage()) - } - - if len(input.GetHost()) > 0 { - // update host if set - b.SetHost(input.GetHost()) - } - - if len(input.GetRuntime()) > 0 { - // update runtime if set - b.SetRuntime(input.GetRuntime()) - } - - if len(input.GetDistribution()) > 0 { - // update distribution if set - b.SetDistribution(input.GetDistribution()) - } - - // send API call to update the build - err = database.FromContext(c).UpdateBuild(b) - if err != nil { - retErr := fmt.Errorf("unable to update build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // send API call to capture the updated build - b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) - - c.JSON(http.StatusOK, b) - - // check if the build is in a "final" state - if b.GetStatus() == constants.StatusSuccess || - b.GetStatus() == constants.StatusFailure || - b.GetStatus() == constants.StatusCanceled || - b.GetStatus() == constants.StatusKilled || - b.GetStatus() == constants.StatusError { - // send API call to capture the repo owner - u, err := database.FromContext(c).GetUser(r.GetUserID()) - if err != nil { - logrus.Errorf("unable to get owner for build %s: %v", entry, err) - } - - // send API call to set the status on the commit - err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) - if err != nil { - logrus.Errorf("unable to set commit status for build %s: %v", entry, err) - } - } -} - -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build} builds DeleteBuild -// -// Delete a build in the configured backend -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: build -// description: Build number to delete -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully deleted the build -// schema: -// type: string -// '400': -// description: Unable to delete the build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to delete the build -// schema: -// "$ref": "#/definitions/Error" - -// DeleteBuild represents the API handler to remove -// a build for a repo from the configured backend. -func DeleteBuild(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("deleting build %s", entry) - - // send API call to remove the build - err := database.FromContext(c).DeleteBuild(b) - if err != nil { - retErr := fmt.Errorf("unable to delete build %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, fmt.Sprintf("build %s deleted", entry)) -} - -// getPRNumberFromBuild is a helper function to -// extract the pull request number from a Build. -func getPRNumberFromBuild(b *library.Build) (int, error) { - // parse out pull request number from base ref - // - // pattern: refs/pull/1/head - var parts []string - if strings.HasPrefix(b.GetRef(), "refs/pull/") { - parts = strings.Split(b.GetRef(), "/") - } - - // just being safe to avoid out of range index errors - if len(parts) < 3 { - return 0, fmt.Errorf("invalid ref: %s", b.GetRef()) - } - - // return the results of converting number to string - return strconv.Atoi(parts[2]) -} - -// PlanBuild is a helper function to plan the build for -// execution. This creates all resources, like steps -// and services, for the build in the configured backend. -// TODO: -// - return build and error. -func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { - // update fields in build object - b.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the build - // TODO: return created build and error instead of just error - err := database.CreateBuild(b) - if err != nil { - // clean up the objects from the pipeline in the database - // TODO: - // - return build in CreateBuild - // - even if it was created, we need to get the new build id - // otherwise it will be 0, which attempts to INSERT instead - // of UPDATE-ing the existing build - which results in - // a constraint error (repo_id, number) - // - do we want to update the build or just delete it? - cleanBuild(database, b, nil, nil, err) - - return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) - } - - // send API call to capture the created build - // TODO: this can be dropped once we return - // the created build above - b, err = database.GetBuildForRepo(r, b.GetNumber()) - if err != nil { - return fmt.Errorf("unable to get new build for %s: %w", r.GetFullName(), err) - } - - // plan all services for the build - services, err := planServices(database, p, b) - if err != nil { - // clean up the objects from the pipeline in the database - cleanBuild(database, b, services, nil, err) - - return err - } - - // plan all steps for the build - steps, err := planSteps(database, p, b) - if err != nil { - // clean up the objects from the pipeline in the database - cleanBuild(database, b, services, steps, err) - - return err - } - - return nil -} - -// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { - // variable to store planned services - services := []*library.Service{} - - // iterate through all pipeline services - for _, service := range p.Services { - // create the service object - s := new(library.Service) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetName(service.Name) - s.SetImage(service.Image) - s.SetNumber(service.Number) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the service - err := database.CreateService(s) - if err != nil { - return services, fmt.Errorf("unable to create service %s: %w", s.GetName(), err) - } - - // send API call to capture the created service - s, err = database.GetServiceForBuild(b, s.GetNumber()) - if err != nil { - return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) - } - - // populate environment variables from service library - // - // https://pkg.go.dev/github.com/go-vela/types/library#Service.Environment - err = service.MergeEnv(s.Environment()) - if err != nil { - return services, err - } - - // create the log object - l := new(library.Log) - l.SetServiceID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the service logs - err = database.CreateLog(l) - if err != nil { - return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) - } - } - - return services, nil -} - -// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { - // variable to store planned steps - steps := []*library.Step{} - - // iterate through all pipeline stages - for _, stage := range p.Stages { - // iterate through all steps for each pipeline stage - for _, step := range stage.Steps { - // create the step object - s := new(library.Step) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetNumber(step.Number) - s.SetName(step.Name) - s.SetImage(step.Image) - s.SetStage(stage.Name) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the step - err := database.CreateStep(s) - if err != nil { - return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) - } - - // send API call to capture the created step - s, err = database.GetStepForBuild(b, s.GetNumber()) - if err != nil { - return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) - } - - // populate environment variables from step library - // - // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment - err = step.MergeEnv(s.Environment()) - if err != nil { - return steps, err - } - - // create the log object - l := new(library.Log) - l.SetStepID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the step logs - err = database.CreateLog(l) - if err != nil { - return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) - } - - steps = append(steps, s) - } - } - - // iterate through all pipeline steps - for _, step := range p.Steps { - // create the step object - s := new(library.Step) - s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) - s.SetNumber(step.Number) - s.SetName(step.Name) - s.SetImage(step.Image) - s.SetStatus(constants.StatusPending) - s.SetCreated(time.Now().UTC().Unix()) - - // send API call to create the step - err := database.CreateStep(s) - if err != nil { - return steps, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) - } - - // send API call to capture the created step - s, err = database.GetStepForBuild(b, s.GetNumber()) - if err != nil { - return steps, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) - } - - // populate environment variables from step library - // - // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment - err = step.MergeEnv(s.Environment()) - if err != nil { - return steps, err - } - - // create the log object - l := new(library.Log) - l.SetStepID(s.GetID()) - l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) - l.SetData([]byte{}) - - // send API call to create the step logs - err = database.CreateLog(l) - if err != nil { - return steps, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) - } - - steps = append(steps, s) - } - - return steps, nil -} - -// cleanBuild is a helper function to kill the build -// without execution. This will kill all resources, -// like steps and services, for the build in the -// configured backend. -func cleanBuild(database database.Interface, b *library.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) - b.SetFinished(time.Now().UTC().Unix()) - - // send API call to update the build - err := database.UpdateBuild(b) - if err != nil { - logrus.Errorf("unable to kill build %d: %v", b.GetNumber(), err) - } - - for _, s := range services { - // update fields in service object - s.SetStatus(constants.StatusKilled) - s.SetFinished(time.Now().UTC().Unix()) - - // send API call to update the service - err := database.UpdateService(s) - if err != nil { - logrus.Errorf("unable to kill service %s for build %d: %v", s.GetName(), b.GetNumber(), err) - } - } - - for _, s := range steps { - // update fields in step object - s.SetStatus(constants.StatusKilled) - s.SetFinished(time.Now().UTC().Unix()) - - // send API call to update the step - err := database.UpdateStep(s) - if err != nil { - logrus.Errorf("unable to kill step %s for build %d: %v", s.GetName(), b.GetNumber(), err) - } - } -} - -// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/cancel builds CancelBuild -// -// Cancel a running build -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: build -// description: Build number to cancel -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully canceled the build -// schema: -// type: string -// '400': -// description: Unable to cancel build -// schema: -// "$ref": "#/definitions/Error" -// '404': -// description: Unable to cancel build -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to cancel build -// schema: -// "$ref": "#/definitions/Error" - -// CancelBuild represents the API handler to cancel a running build. -// -//nolint:funlen // ignore statement count -func CancelBuild(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - e := executors.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - u := user.Retrieve(c) - - entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": u.GetName(), - }).Infof("canceling build %s", entry) - - switch b.GetStatus() { - case constants.StatusRunning: - // retrieve the worker info - w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) - if err != nil { - retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - 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() { - // prepare the request to the worker - client := http.DefaultClient - client.Timeout = 30 * time.Second - - // set the API endpoint path we send the request to - u := fmt.Sprintf("%s/api/v1/executors/%d/build/cancel", w.GetAddress(), executor.GetID()) - - req, err := http.NewRequestWithContext(context.Background(), "DELETE", u, nil) - if err != nil { - retErr := fmt.Errorf("unable to form a request to %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - tm := c.MustGet("token-manager").(*token.Manager) - - // set mint token options - mto := &token.MintTokenOpts{ - Hostname: "vela-server", - TokenType: constants.WorkerAuthTokenType, - TokenDuration: time.Minute * 1, - } - - // mint token - tkn, err := tm.MintToken(mto) - if err != nil { - retErr := fmt.Errorf("unable to generate auth token: %w", err) - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // add the token to authenticate to the worker - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) - - // perform the request to the worker - resp, err := client.Do(req) - if err != nil { - retErr := fmt.Errorf("unable to connect to %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - defer resp.Body.Close() - - // Read Response Body - respBody, err := io.ReadAll(resp.Body) - if err != nil { - retErr := fmt.Errorf("unable to read response from %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - err = json.Unmarshal(respBody, b) - if err != nil { - retErr := fmt.Errorf("unable to parse response from %s: %w", u, err) - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - c.JSON(resp.StatusCode, b) - - return - } - } - case constants.StatusPending: - break - - default: - retErr := fmt.Errorf("found build %s but its status was %s", entry, b.GetStatus()) - - util.HandleError(c, http.StatusBadRequest, retErr) - - return - } - - // build has been abandoned - // update the status in the build table - b.SetStatus(constants.StatusCanceled) - - err := database.FromContext(c).UpdateBuild(b) - if err != nil { - retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - // retrieve the steps for the build from the step table - steps := []*library.Step{} - page := 1 - perPage := 100 - - for page > 0 { - // retrieve build steps (per page) from the database - stepsPart, _, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to retrieve steps for build %s: %w", entry, err) - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // add page of steps to list steps - steps = append(steps, stepsPart...) - - // assume no more pages exist if under 100 results are returned - if len(stepsPart) < 100 { - page = 0 - } else { - page++ - } - } - - // iterate over each step for the build - // setting anything running or pending to canceled - for _, step := range steps { - if step.GetStatus() == constants.StatusRunning || step.GetStatus() == constants.StatusPending { - step.SetStatus(constants.StatusCanceled) - - err = database.FromContext(c).UpdateStep(step) - if err != nil { - retErr := fmt.Errorf("unable to update step %s for build %s: %w", step.GetName(), entry, err) - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } - } - - // retrieve the services for the build from the service table - services := []*library.Service{} - page = 1 - - for page > 0 { - // retrieve build services (per page) from the database - servicesPart, _, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) - if err != nil { - retErr := fmt.Errorf("unable to retrieve services for build %s: %w", entry, err) - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - - // add page of services to the list of services - services = append(services, servicesPart...) - - // assume no more pages exist if under 100 results are returned - if len(servicesPart) < 100 { - page = 0 - } else { - page++ - } - } - - // iterate over each service for the build - // setting anything running or pending to canceled - for _, service := range services { - if service.GetStatus() == constants.StatusRunning || service.GetStatus() == constants.StatusPending { - service.SetStatus(constants.StatusCanceled) - - err = database.FromContext(c).UpdateService(service) - if err != nil { - retErr := fmt.Errorf("unable to update service %s for build %s: %w", - service.GetName(), - entry, - err, - ) - util.HandleError(c, http.StatusNotFound, retErr) - - return - } - } - } - - c.JSON(http.StatusOK, b) -} - -// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/token builds GetBuildToken -// -// Get a build token -// -// --- -// produces: -// - application/json -// parameters: -// - in: path -// name: repo -// description: Name of the repo -// required: true -// type: string -// - in: path -// name: org -// description: Name of the org -// required: true -// type: string -// - in: path -// name: build -// description: Build number -// required: true -// type: integer -// security: -// - ApiKeyAuth: [] -// responses: -// '200': -// description: Successfully retrieved build token -// schema: -// "$ref": "#/definitions/Token" -// '400': -// description: Bad request -// schema: -// "$ref": "#/definitions/Error" -// '409': -// description: Conflict (requested build token for build not in pending state) -// schema: -// "$ref": "#/definitions/Error" -// '500': -// description: Unable to generate build token -// schema: -// "$ref": "#/definitions/Error" - -// GetBuildToken represents the API handler to generate a build token. -func GetBuildToken(c *gin.Context) { - // capture middleware values - b := build.Retrieve(c) - o := org.Retrieve(c) - r := repo.Retrieve(c) - cl := claims.Retrieve(c) - - // update engine logger with API metadata - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields - logrus.WithFields(logrus.Fields{ - "build": b.GetNumber(), - "org": o, - "repo": r.GetName(), - "user": cl.Subject, - }).Infof("generating build token for build %s/%d", r.GetFullName(), b.GetNumber()) - - // if build is not in a pending state, then a build token should not be needed - conflict - if !strings.EqualFold(b.GetStatus(), constants.StatusPending) { - retErr := fmt.Errorf("unable to mint build token: build is not in pending state") - util.HandleError(c, http.StatusConflict, retErr) - - return - } - - // retrieve token manager from context - tm := c.MustGet("token-manager").(*token.Manager) - - // set expiration to repo timeout plus configurable buffer - exp := (time.Duration(r.GetTimeout()) * time.Minute) + tm.BuildTokenBufferDuration - - // set mint token options - bmto := &token.MintTokenOpts{ - Hostname: cl.Subject, - BuildID: b.GetID(), - Repo: r.GetFullName(), - TokenType: constants.WorkerBuildTokenType, - TokenDuration: exp, - } - - // mint token - bt, err := tm.MintToken(bmto) - if err != nil { - retErr := fmt.Errorf("unable to generate build token: %w", err) - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - - c.JSON(http.StatusOK, library.Token{Token: &bt}) -} diff --git a/api/build/cancel.go b/api/build/cancel.go new file mode 100644 index 000000000..ff63a698d --- /dev/null +++ b/api/build/cancel.go @@ -0,0 +1,289 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/executors" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build}/cancel builds CancelBuild +// +// Cancel a running build +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: build +// description: Build number to cancel +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully canceled the build +// schema: +// type: string +// '400': +// description: Unable to cancel build +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to cancel build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to cancel build +// schema: +// "$ref": "#/definitions/Error" + +// CancelBuild represents the API handler to cancel a running build. +// +//nolint:funlen // ignore statement count +func CancelBuild(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + e := executors.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("canceling build %s", entry) + + switch b.GetStatus() { + case constants.StatusRunning: + // retrieve the worker info + w, err := database.FromContext(c).GetWorkerForHostname(b.GetHost()) + if err != nil { + retErr := fmt.Errorf("unable to get worker for build %s: %w", entry, err) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + 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() { + // prepare the request to the worker + client := http.DefaultClient + client.Timeout = 30 * time.Second + + // set the API endpoint path we send the request to + u := fmt.Sprintf("%s/api/v1/executors/%d/build/cancel", w.GetAddress(), executor.GetID()) + + req, err := http.NewRequestWithContext(context.Background(), "DELETE", u, nil) + if err != nil { + retErr := fmt.Errorf("unable to form a request to %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + tm := c.MustGet("token-manager").(*token.Manager) + + // set mint token options + mto := &token.MintTokenOpts{ + Hostname: "vela-server", + TokenType: constants.WorkerAuthTokenType, + TokenDuration: time.Minute * 1, + } + + // mint token + tkn, err := tm.MintToken(mto) + if err != nil { + retErr := fmt.Errorf("unable to generate auth token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // add the token to authenticate to the worker + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tkn)) + + // perform the request to the worker + resp, err := client.Do(req) + if err != nil { + retErr := fmt.Errorf("unable to connect to %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + defer resp.Body.Close() + + // Read Response Body + respBody, err := io.ReadAll(resp.Body) + if err != nil { + retErr := fmt.Errorf("unable to read response from %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + err = json.Unmarshal(respBody, b) + if err != nil { + retErr := fmt.Errorf("unable to parse response from %s: %w", u, err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + c.JSON(resp.StatusCode, b) + + return + } + } + case constants.StatusPending: + break + + default: + retErr := fmt.Errorf("found build %s but its status was %s", entry, b.GetStatus()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // build has been abandoned + // update the status in the build table + b.SetStatus(constants.StatusCanceled) + + err := database.FromContext(c).UpdateBuild(b) + if err != nil { + retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // retrieve the steps for the build from the step table + steps := []*library.Step{} + page := 1 + perPage := 100 + + for page > 0 { + // retrieve build steps (per page) from the database + stepsPart, _, err := database.FromContext(c).ListStepsForBuild(b, map[string]interface{}{}, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to retrieve steps for build %s: %w", entry, err) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // add page of steps to list steps + steps = append(steps, stepsPart...) + + // assume no more pages exist if under 100 results are returned + if len(stepsPart) < 100 { + page = 0 + } else { + page++ + } + } + + // iterate over each step for the build + // setting anything running or pending to canceled + for _, step := range steps { + if step.GetStatus() == constants.StatusRunning || step.GetStatus() == constants.StatusPending { + step.SetStatus(constants.StatusCanceled) + + err = database.FromContext(c).UpdateStep(step) + if err != nil { + retErr := fmt.Errorf("unable to update step %s for build %s: %w", step.GetName(), entry, err) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + } + + // retrieve the services for the build from the service table + services := []*library.Service{} + page = 1 + + for page > 0 { + // retrieve build services (per page) from the database + servicesPart, _, err := database.FromContext(c).ListServicesForBuild(b, map[string]interface{}{}, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to retrieve services for build %s: %w", entry, err) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // add page of services to the list of services + services = append(services, servicesPart...) + + // assume no more pages exist if under 100 results are returned + if len(servicesPart) < 100 { + page = 0 + } else { + page++ + } + } + + // iterate over each service for the build + // setting anything running or pending to canceled + for _, service := range services { + if service.GetStatus() == constants.StatusRunning || service.GetStatus() == constants.StatusPending { + service.SetStatus(constants.StatusCanceled) + + err = database.FromContext(c).UpdateService(service) + if err != nil { + retErr := fmt.Errorf("unable to update service %s for build %s: %w", + service.GetName(), + entry, + err, + ) + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } + } + + c.JSON(http.StatusOK, b) +} diff --git a/api/build/clean.go b/api/build/clean.go new file mode 100644 index 000000000..02c37550c --- /dev/null +++ b/api/build/clean.go @@ -0,0 +1,56 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "time" + + "github.com/go-vela/server/database" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// cleanBuild is a helper function to kill the build +// without execution. This will kill all resources, +// like steps and services, for the build in the +// configured backend. +func CleanBuild(database database.Interface, b *library.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) + b.SetFinished(time.Now().UTC().Unix()) + + // send API call to update the build + err := database.UpdateBuild(b) + if err != nil { + logrus.Errorf("unable to kill build %d: %v", b.GetNumber(), err) + } + + for _, s := range services { + // update fields in service object + s.SetStatus(constants.StatusKilled) + s.SetFinished(time.Now().UTC().Unix()) + + // send API call to update the service + err := database.UpdateService(s) + if err != nil { + logrus.Errorf("unable to kill service %s for build %d: %v", s.GetName(), b.GetNumber(), err) + } + } + + for _, s := range steps { + // update fields in step object + s.SetStatus(constants.StatusKilled) + s.SetFinished(time.Now().UTC().Unix()) + + // send API call to update the step + err := database.UpdateStep(s) + if err != nil { + logrus.Errorf("unable to kill step %s for build %d: %v", s.GetName(), b.GetNumber(), err) + } + } +} diff --git a/api/build/create.go b/api/build/create.go new file mode 100644 index 000000000..3f695d791 --- /dev/null +++ b/api/build/create.go @@ -0,0 +1,392 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/database" + "github.com/go-vela/server/queue" + "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/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds builds CreateBuild +// +// Create a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: body +// name: body +// description: Payload containing the build to create +// required: true +// schema: +// "$ref": "#/definitions/Build" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Request processed but build was skipped +// schema: +// type: string +// '201': +// description: Successfully created the build +// type: json +// schema: +// "$ref": "#/definitions/Build" +// '400': +// description: Unable to create the build +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to create the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to create the build +// schema: +// "$ref": "#/definitions/Error" + +// CreateBuild represents the API handler to create a build in the configured backend. +// +//nolint:funlen,gocyclo // ignore function length and cyclomatic complexity +func CreateBuild(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logger := logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }) + + logger.Infof("creating new build for repo %s", r.GetFullName()) + + // capture body from API request + input := new(library.Build) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for new build for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // verify the build has a valid event and the repo allows that event type + if (input.GetEvent() == constants.EventPush && !r.GetAllowPush()) || + (input.GetEvent() == constants.EventPull && !r.GetAllowPull()) || + (input.GetEvent() == constants.EventTag && !r.GetAllowTag()) || + (input.GetEvent() == constants.EventDeploy && !r.GetAllowDeploy()) { + retErr := fmt.Errorf("unable to create new build: %s does not have %s events enabled", r.GetFullName(), input.GetEvent()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the repo owner + u, err = database.FromContext(c).GetUser(r.GetUserID()) + if err != nil { + retErr := fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // create SQL filters for querying pending and running builds for repo + filters := map[string]interface{}{ + "status": []string{constants.StatusPending, constants.StatusRunning}, + } + + // send API call to capture the number of pending or running builds for the repo + builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) + if err != nil { + retErr := fmt.Errorf("unable to create new build: unable to get count of builds for repo %s", r.GetFullName()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // check if the number of pending and running builds exceeds the limit for the repo + if builds >= r.GetBuildLimit() { + retErr := fmt.Errorf("unable to create new build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in build object + input.SetRepoID(r.GetID()) + input.SetStatus(constants.StatusPending) + input.SetCreated(time.Now().UTC().Unix()) + + // set the parent equal to the current repo counter + input.SetParent(r.GetCounter()) + // check if the parent is set to 0 + if input.GetParent() == 0 { + // parent should be "1" if it's the first build ran + input.SetParent(1) + } + + // update the build numbers based off repo counter + inc := r.GetCounter() + 1 + r.SetCounter(inc) + input.SetNumber(inc) + + // populate the build link if a web address is provided + if len(m.Vela.WebAddress) > 0 { + input.SetLink( + fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), input.GetNumber()), + ) + } + + // variable to store changeset files + var files []string + // check if the build event is not issue_comment or pull_request + if !strings.EqualFold(input.GetEvent(), constants.EventComment) && + !strings.EqualFold(input.GetEvent(), constants.EventPull) { + // send API call to capture list of files changed for the commit + files, err = scm.FromContext(c).Changeset(u, r, input.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + // check if the build event is a pull_request + if strings.EqualFold(input.GetEvent(), constants.EventPull) { + // capture number from build + number, err := getPRNumberFromBuild(input) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to get pull_request number for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture list of files changed for the pull request + files, err = scm.FromContext(c).ChangesetPR(u, r, number) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to get changeset for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) + + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to get pipeline configuration for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } else { + config = pipeline.GetData() + } + + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) + } + + var compiled *library.Pipeline + // parse and compile the pipeline configuration file + p, compiled, err = compiler.FromContext(c). + Duplicate(). + WithBuild(input). + WithFiles(files). + WithMetadata(m). + WithRepo(r). + WithUser(u). + Compile(config) + if err != nil { + retErr := fmt.Errorf("unable to compile pipeline configuration for %s/%d: %w", r.GetFullName(), input.GetNumber(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) + + // skip the build if only the init or clone steps are found + skip := SkipEmptyBuild(p) + if skip != "" { + // set build to successful status + input.SetStatus(constants.StatusSuccess) + + // send API call to set the status on the commit + err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) + if err != nil { + logger.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), input.GetNumber(), err) + } + + c.JSON(http.StatusOK, skip) + + return + } + + // check if the pipeline did not already exist in the database + // + //nolint:dupl // ignore duplicate code + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(input.GetCommit()) + pipeline.SetRef(input.GetRef()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(pipeline) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to create pipeline for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the created pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + //nolint:lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to create new build: failed to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + input.SetPipelineID(pipeline.GetID()) + + // create the objects from the pipeline in the database + err = PlanBuild(database.FromContext(c), p, input, r) + if err != nil { + util.HandleError(c, http.StatusInternalServerError, err) + + return + } + + // send API call to update repo for ensuring counter is incremented + err = database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to create new build: failed to update repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the created build + input, _ = database.FromContext(c).GetBuildForRepo(r, input.GetNumber()) + + c.JSON(http.StatusCreated, input) + + // send API call to set the status on the commit + err = scm.FromContext(c).Status(u, input, r.GetOrg(), r.GetName()) + if err != nil { + logger.Errorf("unable to set commit status for build %s/%d: %v", r.GetFullName(), input.GetNumber(), err) + } + + // publish the build to the queue + go PublishToQueue( + queue.FromGinContext(c), + database.FromContext(c), + p, + input, + r, + u, + ) +} + +// getPRNumberFromBuild is a helper function to +// extract the pull request number from a Build. +func getPRNumberFromBuild(b *library.Build) (int, error) { + // parse out pull request number from base ref + // + // pattern: refs/pull/1/head + var parts []string + if strings.HasPrefix(b.GetRef(), "refs/pull/") { + parts = strings.Split(b.GetRef(), "/") + } + + // just being safe to avoid out of range index errors + if len(parts) < 3 { + return 0, fmt.Errorf("invalid ref: %s", b.GetRef()) + } + + // return the results of converting number to string + return strconv.Atoi(parts[2]) +} diff --git a/api/build/delete.go b/api/build/delete.go new file mode 100644 index 000000000..19a1fd17c --- /dev/null +++ b/api/build/delete.go @@ -0,0 +1,92 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "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/sirupsen/logrus" +) + +// swagger:operation DELETE /api/v1/repos/{org}/{repo}/builds/{build} builds DeleteBuild +// +// Delete a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number to delete +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully deleted the build +// schema: +// type: string +// '400': +// description: Unable to delete the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to delete the build +// schema: +// "$ref": "#/definitions/Error" + +// DeleteBuild represents the API handler to remove +// a build for a repo from the configured backend. +func DeleteBuild(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("deleting build %s", entry) + + // send API call to remove the build + err := database.FromContext(c).DeleteBuild(b) + if err != nil { + retErr := fmt.Errorf("unable to delete build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, fmt.Sprintf("build %s deleted", entry)) +} diff --git a/api/build/doc.go b/api/build/doc.go new file mode 100644 index 000000000..94b6571e3 --- /dev/null +++ b/api/build/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package build provides the build handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/build" +package build diff --git a/api/build/get.go b/api/build/get.go new file mode 100644 index 000000000..7e476441e --- /dev/null +++ b/api/build/get.go @@ -0,0 +1,70 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/router/middleware/build" + "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/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build} builds GetBuild +// +// Get a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number to retrieve +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the build +// type: json +// schema: +// "$ref": "#/definitions/Build" + +// GetBuild represents the API handler to capture +// a build for a repo from the configured backend. +func GetBuild(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("reading build %s/%d", r.GetFullName(), b.GetNumber()) + + c.JSON(http.StatusOK, b) +} diff --git a/api/build/get_id.go b/api/build/get_id.go new file mode 100644 index 000000000..47fb18874 --- /dev/null +++ b/api/build/get_id.go @@ -0,0 +1,118 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/search/builds/{id} builds GetBuildByID +// +// Get a single build by its id in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: id +// description: build id +// required: true +// type: number +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved build +// schema: +// "$ref": "#/definitions/Build" +// '400': +// description: Unable to retrieve the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the build +// schema: +// "$ref": "#/definitions/Error" + +// 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 *library.Repo + ) + + // Capture user from middleware + u := user.Retrieve(c) + + // Parse build ID from path + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + + if err != nil { + retErr := fmt.Errorf("unable to parse build id: %w", err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": id, + "user": u.GetName(), + }).Infof("reading build %d", id) + + // Get build from database + b, err = database.FromContext(c).GetBuild(id) + if err != nil { + retErr := fmt.Errorf("unable to get build: %w", err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // Get repo from database using repo ID field from build + r, err = database.FromContext(c).GetRepo(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(u, u.GetToken(), r.GetOrg(), r.GetName()) + if err != nil { + logrus.Errorf("unable to get user %s access level for repo %s", u.GetName(), r.GetFullName()) + } + + // Ensure that user has at least read access to repo to return the build + if perm == "none" && !u.GetAdmin() { + retErr := fmt.Errorf("unable to retrieve build %d: user does not have read access to repo", id) + + util.HandleError(c, http.StatusUnauthorized, retErr) + + return + } + + c.JSON(http.StatusOK, b) +} diff --git a/api/build/list_org.go b/api/build/list_org.go new file mode 100644 index 000000000..1ccd8b45b --- /dev/null +++ b/api/build/list_org.go @@ -0,0 +1,195 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/builds builds ListBuildsForOrg +// +// Get a list of builds by org in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved build list +// schema: +// type: array +// items: +// "$ref": "#/definitions/Build" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of builds +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of builds +// schema: +// "$ref": "#/definitions/Error" + +// ListBuildsForOrg represents the API handler to capture a +// list of builds associated with an org from the configured backend. +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 + t int64 + ) + + // capture middleware values + o := org.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "user": u.GetName(), + }).Infof("listing builds for org %s", o) + + // capture the branch name parameter + branch := c.Query("branch") + // capture the event type parameter + event := c.Query("event") + // capture the status type parameter + status := c.Query("status") + + // check if branch filter was provided + if len(branch) > 0 { + // add branch to filters map + filters["branch"] = branch + } + // check if event filter was provided + if len(event) > 0 { + // verify the event provided is a valid event type + if event != constants.EventComment && event != constants.EventDeploy && + event != constants.EventPush && event != constants.EventPull && + event != constants.EventTag { + retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // add event to filters map + filters["event"] = event + } + // check if status filter was provided + if len(status) > 0 { + // verify the status provided is a valid status type + if status != constants.StatusCanceled && status != constants.StatusError && + status != constants.StatusFailure && status != constants.StatusKilled && + status != constants.StatusPending && status != constants.StatusRunning && + status != constants.StatusSuccess { + retErr := fmt.Errorf("unable to process status %s: invalid status type provided", status) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // add status to filters map + filters["status"] = status + } + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for org %s: %w", o, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for Org %s: %w", o, err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // See if the user is an org admin to bypass individual permission checks + perm, err := scm.FromContext(c).OrgAccess(u, o) + if err != nil { + logrus.Errorf("unable to get user %s access level for org %s", u.GetName(), o) + } + // Only show public repos to non-admins + if perm != "admin" { + filters["visibility"] = constants.VisibilityPublic + } + + // send API call to capture the list of builds for the org (and event type if passed in) + b, t, err = database.FromContext(c).ListBuildsForOrg(o, filters, page, perPage) + + if err != nil { + retErr := fmt.Errorf("unable to list builds for org %s: %w", o, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, b) +} diff --git a/api/build/list_repo.go b/api/build/list_repo.go new file mode 100644 index 000000000..2dd71fc1a --- /dev/null +++ b/api/build/list_repo.go @@ -0,0 +1,259 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/api" + "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" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds builds ListBuildsForRepo +// +// Get builds from the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: query +// name: event +// description: Filter by build event +// type: string +// enum: +// - push +// - pull_request +// - tag +// - deployment +// - comment +// - in: query +// name: commit +// description: Filter builds based on the commit hash +// type: string +// - in: query +// name: branch +// description: Filter builds by branch +// type: string +// - in: query +// name: status +// description: Filter by build status +// type: string +// enum: +// - canceled +// - error +// - failure +// - killed +// - pending +// - running +// - success +// - in: query +// name: page +// description: The page of results to retrieve +// type: integer +// default: 1 +// - in: query +// name: per_page +// description: How many results per page to return +// type: integer +// maximum: 100 +// default: 10 +// - in: query +// name: before +// description: filter builds created before a certain time +// type: integer +// default: 1 +// - in: query +// name: after +// description: filter builds created after a certain time +// type: integer +// default: 0 +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the builds +// schema: +// type: array +// items: +// "$ref": "#/definitions/Build" +// headers: +// X-Total-Count: +// description: Total number of results +// type: integer +// Link: +// description: see https://tools.ietf.org/html/rfc5988 +// type: string +// '400': +// description: Unable to retrieve the list of builds +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to retrieve the list of builds +// schema: +// "$ref": "#/definitions/Error" + +// ListBuildsForRepo represents the API handler to capture a +// list of builds for a repo from the configured backend. +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 + t int64 + ) + + // capture middleware values + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }).Infof("listing builds for repo %s", r.GetFullName()) + + // capture the branch name parameter + branch := c.Query("branch") + // capture the event type parameter + event := c.Query("event") + // capture the status type parameter + status := c.Query("status") + // capture the commit hash parameter + commit := c.Query("commit") + + // check if branch filter was provided + if len(branch) > 0 { + // add branch to filters map + filters["branch"] = branch + } + // check if event filter was provided + if len(event) > 0 { + // verify the event provided is a valid event type + if event != constants.EventComment && event != constants.EventDeploy && + event != constants.EventPush && event != constants.EventPull && + event != constants.EventTag { + retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // add event to filters map + filters["event"] = event + } + // check if status filter was provided + if len(status) > 0 { + // verify the status provided is a valid status type + if status != constants.StatusCanceled && status != constants.StatusError && + status != constants.StatusFailure && status != constants.StatusKilled && + status != constants.StatusPending && status != constants.StatusRunning && + status != constants.StatusSuccess { + retErr := fmt.Errorf("unable to process status %s: invalid status type provided", status) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // add status to filters map + filters["status"] = status + } + + // check if commit hash filter was provided + if len(commit) > 0 { + // add commit to filters map + filters["commit"] = commit + } + + // capture page query parameter if present + page, err := strconv.Atoi(c.DefaultQuery("page", "1")) + if err != nil { + retErr := fmt.Errorf("unable to convert page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture per_page query parameter if present + perPage, err := strconv.Atoi(c.DefaultQuery("per_page", "10")) + if err != nil { + retErr := fmt.Errorf("unable to convert per_page query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // ensure per_page isn't above or below allowed values + perPage = util.MaxInt(1, util.MinInt(100, perPage)) + + // capture before query parameter if present, default to now + before, err := strconv.ParseInt(c.DefaultQuery("before", strconv.FormatInt(time.Now().UTC().Unix(), 10)), 10, 64) + if err != nil { + retErr := fmt.Errorf("unable to convert before query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // capture after query parameter if present, default to 0 + after, err := strconv.ParseInt(c.DefaultQuery("after", "0"), 10, 64) + if err != nil { + retErr := fmt.Errorf("unable to convert after query parameter for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + b, t, err = database.FromContext(c).ListBuildsForRepo(r, filters, before, after, page, perPage) + if err != nil { + retErr := fmt.Errorf("unable to list builds for repo %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // create pagination object + pagination := api.Pagination{ + Page: page, + PerPage: perPage, + Total: t, + } + // set pagination headers + pagination.SetHeaderLink(c) + + c.JSON(http.StatusOK, b) +} diff --git a/api/build/plan.go b/api/build/plan.go new file mode 100644 index 000000000..5790ce4a5 --- /dev/null +++ b/api/build/plan.go @@ -0,0 +1,71 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "time" + + "github.com/go-vela/server/api/service" + "github.com/go-vela/server/api/step" + "github.com/go-vela/server/database" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" +) + +// PlanBuild is a helper function to plan the build for +// execution. This creates all resources, like steps +// and services, for the build in the configured backend. +// TODO: +// - return build and error. +func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { + // update fields in build object + b.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the build + // TODO: return created build and error instead of just error + err := database.CreateBuild(b) + if err != nil { + // clean up the objects from the pipeline in the database + // TODO: + // - return build in CreateBuild + // - even if it was created, we need to get the new build id + // otherwise it will be 0, which attempts to INSERT instead + // of UPDATE-ing the existing build - which results in + // a constraint error (repo_id, number) + // - do we want to update the build or just delete it? + CleanBuild(database, b, nil, nil, err) + + return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) + } + + // send API call to capture the created build + // TODO: this can be dropped once we return + // the created build above + b, err = database.GetBuildForRepo(r, b.GetNumber()) + if err != nil { + return fmt.Errorf("unable to get new build for %s: %w", r.GetFullName(), err) + } + + // plan all services for the build + services, err := service.PlanServices(database, p, b) + if err != nil { + // clean up the objects from the pipeline in the database + CleanBuild(database, b, services, nil, err) + + return err + } + + // plan all steps for the build + steps, err := step.PlanSteps(database, p, b) + if err != nil { + // clean up the objects from the pipeline in the database + CleanBuild(database, b, services, steps, err) + + return err + } + + return nil +} diff --git a/api/build/publish.go b/api/build/publish.go new file mode 100644 index 000000000..f126b8471 --- /dev/null +++ b/api/build/publish.go @@ -0,0 +1,74 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "context" + "encoding/json" + "time" + + "github.com/go-vela/server/database" + "github.com/go-vela/server/queue" + "github.com/go-vela/types" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" + "github.com/sirupsen/logrus" +) + +// PublishToQueue is a helper function that creates +// a build item and publishes it to the queue. +func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { + item := types.ToItem(p, b, r, u) + + logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) + + byteItem, err := json.Marshal(item) + if err != nil { + logrus.Errorf("Failed to convert item to json for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + // error out the build + CleanBuild(db, b, nil, nil, err) + + return + } + + logrus.Infof("Establishing route for build %d for %s", b.GetNumber(), r.GetFullName()) + + route, err := queue.Route(&p.Worker) + if err != nil { + logrus.Errorf("unable to set route for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + // error out the build + CleanBuild(db, b, nil, nil, err) + + return + } + + logrus.Infof("Publishing item for build %d for %s to queue %s", b.GetNumber(), r.GetFullName(), route) + + err = queue.Push(context.Background(), route, byteItem) + if err != nil { + logrus.Errorf("Retrying; Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + err = queue.Push(context.Background(), route, byteItem) + if err != nil { + logrus.Errorf("Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + // error out the build + CleanBuild(db, b, nil, nil, err) + + return + } + } + + // update fields in build object + b.SetEnqueued(time.Now().UTC().Unix()) + + // update the build in the db to reflect the time it was enqueued + err = db.UpdateBuild(b) + if err != nil { + logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", b.GetNumber(), r.GetFullName(), err) + } +} diff --git a/api/build/restart.go b/api/build/restart.go new file mode 100644 index 000000000..302090a9c --- /dev/null +++ b/api/build/restart.go @@ -0,0 +1,362 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/compiler" + "github.com/go-vela/server/database" + "github.com/go-vela/server/queue" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" + "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/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" + "github.com/sirupsen/logrus" +) + +// swagger:operation POST /api/v1/repos/{org}/{repo}/builds/{build} builds RestartBuild +// +// Restart a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number to restart +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Request processed but build was skipped +// schema: +// type: string +// '201': +// description: Successfully restarted the build +// schema: +// "$ref": "#/definitions/Build" +// '400': +// description: Unable to restart the build +// schema: +// "$ref": "#/definitions/Error" +// '404': +// description: Unable to restart the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to restart the build +// schema: +// "$ref": "#/definitions/Error" + +// RestartBuild represents the API handler to restart an existing build in the configured backend. +// +//nolint:funlen // ignore statement count +func RestartBuild(c *gin.Context) { + // capture middleware values + m := c.MustGet("metadata").(*types.Metadata) + cl := claims.Retrieve(c) + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + u := user.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logger := logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": u.GetName(), + }) + + logger.Infof("restarting build %s", entry) + + // send API call to capture the repo owner + u, err := database.FromContext(c).GetUser(r.GetUserID()) + if err != nil { + retErr := fmt.Errorf("unable to get owner for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // create SQL filters for querying pending and running builds for repo + filters := map[string]interface{}{ + "status": []string{constants.StatusPending, constants.StatusRunning}, + } + + // send API call to capture the number of pending or running builds for the repo + builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) + if err != nil { + retErr := fmt.Errorf("unable to restart build: unable to get count of builds for repo %s", r.GetFullName()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // check if the number of pending and running builds exceeds the limit for the repo + if builds >= r.GetBuildLimit() { + retErr := fmt.Errorf("unable to restart build: repo %s has exceeded the concurrent build limit of %d", r.GetFullName(), r.GetBuildLimit()) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // update fields in build object + b.SetID(0) + b.SetCreated(time.Now().UTC().Unix()) + b.SetEnqueued(0) + b.SetStarted(0) + b.SetFinished(0) + b.SetStatus(constants.StatusPending) + b.SetHost("") + b.SetRuntime("") + b.SetDistribution("") + b.SetSender(cl.Subject) + + // update the PR event action if action was never set + // for backwards compatibility with pre-0.14 releases. + if b.GetEvent() == constants.EventPull && b.GetEventAction() == "" { + // technically, the action could have been opened or synchronize. + // will not affect behavior of the pipeline since we did not + // support actions for builds where this would be the case. + b.SetEventAction(constants.ActionOpened) + } + + // set the parent equal to the restarted build number + b.SetParent(b.GetNumber()) + // update the build numbers based off repo counter + inc := r.GetCounter() + 1 + r.SetCounter(inc) + b.SetNumber(inc) + + // populate the build link if a web address is provided + if len(m.Vela.WebAddress) > 0 { + b.SetLink( + fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), b.GetNumber()), + ) + } + + // variable to store changeset files + var files []string + // check if the build event is not issue_comment or pull_request + if !strings.EqualFold(b.GetEvent(), constants.EventComment) && + !strings.EqualFold(b.GetEvent(), constants.EventPull) { + // send API call to capture list of files changed for the commit + files, err = scm.FromContext(c).Changeset(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + // check if the build event is a pull_request + if strings.EqualFold(b.GetEvent(), constants.EventPull) { + // capture number from build + number, err := getPRNumberFromBuild(b) + if err != nil { + retErr := fmt.Errorf("unable to restart build: failed to get pull_request number for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture list of files changed for the pull request + files, err = scm.FromContext(c).ChangesetPR(u, r, number) + if err != nil { + retErr := fmt.Errorf("unable to restart build: failed to get changeset for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + // variables to store pipeline configuration + var ( + // variable to store the raw pipeline configuration + config []byte + // variable to store executable pipeline + p *pipeline.Build + // variable to store pipeline configuration + pipeline *library.Pipeline + // variable to store the pipeline type for the repository + pipelineType = r.GetPipelineType() + ) + + // send API call to attempt to capture the pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) + // send API call to capture the pipeline configuration file + config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) + if err != nil { + retErr := fmt.Errorf("unable to get pipeline configuration for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + } else { + config = pipeline.GetData() + } + + // ensure we use the expected pipeline type when compiling + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + if len(pipeline.GetType()) > 0 { + r.SetPipelineType(pipeline.GetType()) + } + + var compiled *library.Pipeline + // parse and compile the pipeline configuration file + p, compiled, err = compiler.FromContext(c). + Duplicate(). + WithBuild(b). + WithFiles(files). + WithMetadata(m). + WithRepo(r). + WithUser(u). + Compile(config) + if err != nil { + retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + // reset the pipeline type for the repo + // + // The pipeline type for a repo can change at any time which can break compiling + // existing pipelines in the system for that repo. To account for this, we update + // the repo pipeline type to match what was defined for the existing pipeline + // before compiling. After we're done compiling, we reset the pipeline type. + r.SetPipelineType(pipelineType) + + // skip the build if only the init or clone steps are found + skip := SkipEmptyBuild(p) + if skip != "" { + // set build to successful status + b.SetStatus(constants.StatusSkipped) + + // send API call to set the status on the commit + err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) + if err != nil { + logrus.Errorf("unable to set commit status for %s/%d: %v", r.GetFullName(), b.GetNumber(), err) + } + + c.JSON(http.StatusOK, skip) + + return + } + + // check if the pipeline did not already exist in the database + // + //nolint:dupl // ignore duplicate code + if pipeline == nil { + pipeline = compiled + pipeline.SetRepoID(r.GetID()) + pipeline.SetCommit(b.GetCommit()) + pipeline.SetRef(b.GetRef()) + + // send API call to create the pipeline + err = database.FromContext(c).CreatePipeline(pipeline) + if err != nil { + retErr := fmt.Errorf("unable to create pipeline for %s: %w", r.GetFullName(), err) + + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the created pipeline + pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) + if err != nil { + //nolint:lll // ignore long line length due to error message + retErr := fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + } + + b.SetPipelineID(pipeline.GetID()) + + // create the objects from the pipeline in the database + err = PlanBuild(database.FromContext(c), p, b, r) + if err != nil { + util.HandleError(c, http.StatusInternalServerError, err) + + return + } + + // send API call to update repo for ensuring counter is incremented + err = database.FromContext(c).UpdateRepo(r) + if err != nil { + retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %w", r.GetFullName(), err) + util.HandleError(c, http.StatusBadRequest, retErr) + + return + } + + // send API call to capture the restarted build + b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) + + c.JSON(http.StatusCreated, b) + + // send API call to set the status on the commit + err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) + if err != nil { + logger.Errorf("unable to set commit status for build %s: %v", entry, err) + } + + // publish the build to the queue + go PublishToQueue( + queue.FromGinContext(c), + database.FromContext(c), + p, + b, + r, + u, + ) +} diff --git a/api/build/skip.go b/api/build/skip.go new file mode 100644 index 000000000..4d5cf8af9 --- /dev/null +++ b/api/build/skip.go @@ -0,0 +1,41 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "github.com/go-vela/types/pipeline" +) + +// SkipEmptyBuild checks if the build should be skipped due to it +// not containing any steps besides init or clone. +// +//nolint:goconst // ignore init and clone constants +func SkipEmptyBuild(p *pipeline.Build) string { + if len(p.Stages) == 1 { + if p.Stages[0].Name == "init" { + return "skipping build since only init stage found" + } + } + + if len(p.Stages) == 2 { + if p.Stages[0].Name == "init" && p.Stages[1].Name == "clone" { + return "skipping build since only init and clone stages found" + } + } + + if len(p.Steps) == 1 { + if p.Steps[0].Name == "init" { + return "skipping build since only init step found" + } + } + + if len(p.Steps) == 2 { + if p.Steps[0].Name == "init" && p.Steps[1].Name == "clone" { + return "skipping build since only init and clone steps found" + } + } + + return "" +} diff --git a/api/build_test.go b/api/build/skip_test.go similarity index 99% rename from api/build_test.go rename to api/build/skip_test.go index 1fb395d7d..ca805a84e 100644 --- a/api/build_test.go +++ b/api/build/skip_test.go @@ -2,7 +2,7 @@ // // Use of this source code is governed by the LICENSE file in this repository. -package api +package build import ( "testing" diff --git a/api/build/token.go b/api/build/token.go new file mode 100644 index 000000000..da18a0322 --- /dev/null +++ b/api/build/token.go @@ -0,0 +1,119 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/internal/token" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/token builds GetBuildToken +// +// Get a build token +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: build +// description: Build number +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved build token +// schema: +// "$ref": "#/definitions/Token" +// '400': +// description: Bad request +// schema: +// "$ref": "#/definitions/Error" +// '409': +// description: Conflict (requested build token for build not in pending state) +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to generate build token +// schema: +// "$ref": "#/definitions/Error" + +// GetBuildToken represents the API handler to generate a build token. +func GetBuildToken(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + cl := claims.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": cl.Subject, + }).Infof("generating build token for build %s/%d", r.GetFullName(), b.GetNumber()) + + // if build is not in a pending state, then a build token should not be needed - conflict + if !strings.EqualFold(b.GetStatus(), constants.StatusPending) { + retErr := fmt.Errorf("unable to mint build token: build is not in pending state") + util.HandleError(c, http.StatusConflict, retErr) + + return + } + + // retrieve token manager from context + tm := c.MustGet("token-manager").(*token.Manager) + + // set expiration to repo timeout plus configurable buffer + exp := (time.Duration(r.GetTimeout()) * time.Minute) + tm.BuildTokenBufferDuration + + // set mint token options + bmto := &token.MintTokenOpts{ + Hostname: cl.Subject, + BuildID: b.GetID(), + Repo: r.GetFullName(), + TokenType: constants.WorkerBuildTokenType, + TokenDuration: exp, + } + + // mint token + bt, err := tm.MintToken(bmto) + if err != nil { + retErr := fmt.Errorf("unable to generate build token: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, library.Token{Token: &bt}) +} diff --git a/api/build/update.go b/api/build/update.go new file mode 100644 index 000000000..f9d3341fa --- /dev/null +++ b/api/build/update.go @@ -0,0 +1,186 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/scm" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// swagger:operation PUT /api/v1/repos/{org}/{repo}/builds/{build} builds UpdateBuild +// +// Updates a build in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number to update +// required: true +// type: integer +// - in: body +// name: body +// description: Payload containing the build to update +// required: true +// schema: +// "$ref": "#/definitions/Build" +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully updated the build +// schema: +// "$ref": "#/definitions/Build" +// '404': +// description: Unable to update the build +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Unable to update the build +// schema: +// "$ref": "#/definitions/Error" + +// UpdateBuild represents the API handler to update +// a build for a repo in the configured backend. +func UpdateBuild(c *gin.Context) { + // capture middleware values + cl := claims.Retrieve(c) + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + + entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "user": cl.Subject, + }).Infof("updating build %s", entry) + + // capture body from API request + input := new(library.Build) + + err := c.Bind(input) + if err != nil { + retErr := fmt.Errorf("unable to decode JSON for build %s: %w", entry, err) + + util.HandleError(c, http.StatusNotFound, retErr) + + return + } + + // update build fields if provided + if len(input.GetStatus()) > 0 { + // update status if set + b.SetStatus(input.GetStatus()) + } + + if len(input.GetError()) > 0 { + // update error if set + b.SetError(input.GetError()) + } + + if input.GetEnqueued() > 0 { + // update enqueued if set + b.SetEnqueued(input.GetEnqueued()) + } + + if input.GetStarted() > 0 { + // update started if set + b.SetStarted(input.GetStarted()) + } + + if input.GetFinished() > 0 { + // update finished if set + b.SetFinished(input.GetFinished()) + } + + if len(input.GetTitle()) > 0 { + // update title if set + b.SetTitle(input.GetTitle()) + } + + if len(input.GetMessage()) > 0 { + // update message if set + b.SetMessage(input.GetMessage()) + } + + if len(input.GetHost()) > 0 { + // update host if set + b.SetHost(input.GetHost()) + } + + if len(input.GetRuntime()) > 0 { + // update runtime if set + b.SetRuntime(input.GetRuntime()) + } + + if len(input.GetDistribution()) > 0 { + // update distribution if set + b.SetDistribution(input.GetDistribution()) + } + + // send API call to update the build + err = database.FromContext(c).UpdateBuild(b) + if err != nil { + retErr := fmt.Errorf("unable to update build %s: %w", entry, err) + + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + // send API call to capture the updated build + b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) + + c.JSON(http.StatusOK, b) + + // check if the build is in a "final" state + if b.GetStatus() == constants.StatusSuccess || + b.GetStatus() == constants.StatusFailure || + b.GetStatus() == constants.StatusCanceled || + b.GetStatus() == constants.StatusKilled || + b.GetStatus() == constants.StatusError { + // send API call to capture the repo owner + u, err := database.FromContext(c).GetUser(r.GetUserID()) + if err != nil { + logrus.Errorf("unable to get owner for build %s: %v", entry, err) + } + + // send API call to set the status on the commit + err = scm.FromContext(c).Status(u, b, r.GetOrg(), r.GetName()) + if err != nil { + logrus.Errorf("unable to set commit status for build %s: %v", entry, err) + } + } +} diff --git a/api/service/plan.go b/api/service/plan.go new file mode 100644 index 000000000..4912f38d1 --- /dev/null +++ b/api/service/plan.go @@ -0,0 +1,71 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package service + +import ( + "fmt" + "time" + + "github.com/go-vela/server/database" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" +) + +// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { + // variable to store planned services + services := []*library.Service{} + + // iterate through all pipeline services + for _, service := range p.Services { + // create the service object + s := new(library.Service) + s.SetBuildID(b.GetID()) + s.SetRepoID(b.GetRepoID()) + s.SetName(service.Name) + s.SetImage(service.Image) + s.SetNumber(service.Number) + s.SetStatus(constants.StatusPending) + s.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the service + err := database.CreateService(s) + if err != nil { + return services, fmt.Errorf("unable to create service %s: %w", s.GetName(), err) + } + + // send API call to capture the created service + s, err = database.GetServiceForBuild(b, s.GetNumber()) + if err != nil { + return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) + } + + // populate environment variables from service library + // + // https://pkg.go.dev/github.com/go-vela/types/library#Service.Environment + err = service.MergeEnv(s.Environment()) + if err != nil { + return services, err + } + + // create the log object + l := new(library.Log) + l.SetServiceID(s.GetID()) + l.SetBuildID(b.GetID()) + l.SetRepoID(b.GetRepoID()) + l.SetData([]byte{}) + + // send API call to create the service logs + err = database.CreateLog(l) + if err != nil { + return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) + } + } + + return services, nil +} diff --git a/api/step/plan.go b/api/step/plan.go new file mode 100644 index 000000000..b072cf4f7 --- /dev/null +++ b/api/step/plan.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package step + +import ( + "fmt" + "time" + + "github.com/go-vela/server/database" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/pipeline" +) + +// 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(database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Step, error) { + // variable to store planned steps + steps := []*library.Step{} + + // iterate through all pipeline stages + for _, stage := range p.Stages { + // iterate through all steps for each pipeline stage + for _, step := range stage.Steps { + // create the step object + s, err := planStep(database, b, step, stage.Name) + if err != nil { + return steps, err + } + + steps = append(steps, s) + } + } + + // iterate through all pipeline steps + for _, step := range p.Steps { + s, err := planStep(database, b, step, "") + if err != nil { + return steps, err + } + + steps = append(steps, s) + } + + return steps, nil +} + +func planStep(database database.Interface, b *library.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.SetNumber(c.Number) + s.SetName(c.Name) + s.SetImage(c.Image) + s.SetStage(stage) + s.SetStatus(constants.StatusPending) + s.SetCreated(time.Now().UTC().Unix()) + + // send API call to create the step + err := database.CreateStep(s) + if err != nil { + return nil, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) + } + + // send API call to capture the created step + s, err = database.GetStepForBuild(b, s.GetNumber()) + if err != nil { + return nil, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) + } + + // populate environment variables from step library + // + // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment + err = c.MergeEnv(s.Environment()) + if err != nil { + return nil, err + } + + // create the log object + l := new(library.Log) + l.SetStepID(s.GetID()) + l.SetBuildID(b.GetID()) + l.SetRepoID(b.GetRepoID()) + l.SetData([]byte{}) + + // send API call to create the step logs + err = database.CreateLog(l) + if err != nil { + return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) + } + + return s, nil +} diff --git a/api/webhook/doc.go b/api/webhook/doc.go new file mode 100644 index 000000000..0acc05476 --- /dev/null +++ b/api/webhook/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// Package webhook provides the webhook handlers for the Vela API. +// +// Usage: +// +// import "github.com/go-vela/server/api/webhook" +package webhook diff --git a/api/webhook.go b/api/webhook/post.go similarity index 93% rename from api/webhook.go rename to api/webhook/post.go index fd958291c..c25abb634 100644 --- a/api/webhook.go +++ b/api/webhook/post.go @@ -1,13 +1,12 @@ -// 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. -package api +package webhook import ( "bytes" "context" - "encoding/json" "fmt" "io" "net/http" @@ -16,6 +15,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/go-vela/server/api/build" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/queue" @@ -537,7 +537,7 @@ func PostWebhook(c *gin.Context) { repo.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found - skip := SkipEmptyBuild(p) + skip := build.SkipEmptyBuild(p) if skip != "" { // set build to successful status b.SetStatus(constants.StatusSkipped) @@ -604,7 +604,7 @@ func PostWebhook(c *gin.Context) { // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = PlanBuild(database.FromContext(c), p, b, repo) + err = build.PlanBuild(database.FromContext(c), p, b, repo) if err != nil { retErr := fmt.Errorf("%s: %w", baseErr, err) @@ -691,7 +691,7 @@ func PostWebhook(c *gin.Context) { } // publish the build to the queue - go PublishToQueue( + go build.PublishToQueue( queue.FromGinContext(c), database.FromContext(c), p, @@ -701,62 +701,6 @@ func PostWebhook(c *gin.Context) { ) } -// PublishToQueue is a helper function that creates -// a build item and publishes it to the queue. -func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { - item := types.ToItem(p, b, r, u) - - logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) - - byteItem, err := json.Marshal(item) - if err != nil { - logrus.Errorf("Failed to convert item to json for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) - - // error out the build - cleanBuild(db, b, nil, nil, err) - - return - } - - logrus.Infof("Establishing route for build %d for %s", b.GetNumber(), r.GetFullName()) - - route, err := queue.Route(&p.Worker) - if err != nil { - logrus.Errorf("unable to set route for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) - - // error out the build - cleanBuild(db, b, nil, nil, err) - - return - } - - logrus.Infof("Publishing item for build %d for %s to queue %s", b.GetNumber(), r.GetFullName(), route) - - err = queue.Push(context.Background(), route, byteItem) - if err != nil { - logrus.Errorf("Retrying; Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) - - err = queue.Push(context.Background(), route, byteItem) - if err != nil { - logrus.Errorf("Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) - - // error out the build - cleanBuild(db, b, nil, nil, err) - - return - } - } - - // update fields in build object - b.SetEnqueued(time.Now().UTC().Unix()) - - // update the build in the db to reflect the time it was enqueued - err = db.UpdateBuild(b) - if err != nil { - logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", b.GetNumber(), r.GetFullName(), err) - } -} - func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r *library.Repo) (*library.Repo, error) { logrus.Debugf("webhook is repository event, making necessary updates to repo %s", r.GetFullName()) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index cb607c59b..a71688606 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -10,7 +10,7 @@ import ( "time" "github.com/adhocore/gronx" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/build" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/queue" @@ -281,7 +281,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat r.SetPipelineType(pipelineType) // skip the build if only the init or clone steps are found - skip := api.SkipEmptyBuild(p) + skip := build.SkipEmptyBuild(p) if skip != "" { return nil } @@ -325,7 +325,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = api.PlanBuild(database, p, b, r) + err = build.PlanBuild(database, p, b, r) if err != nil { // check if the retry limit has been exceeded if i < retryLimit-1 { @@ -368,7 +368,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // publish the build to the queue - go api.PublishToQueue( + go build.PublishToQueue( queue, database, p, diff --git a/go.mod b/go.mod index 5ff15db7b..be974371f 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f + github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 diff --git a/go.sum b/go.sum index e988c342d..3b4b80685 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f h1:13H381Djx9iFC3BSj2f/ac57HlaI3mQL0el9vM7a3+k= -github.com/go-vela/types v0.19.3-0.20230519215217-0da8c8b5e90f/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= +github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c h1:eAApIK5e5MxFF8RzZAFsvTSdwq/AzdUrdhJHOGQ0ILc= +github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= diff --git a/router/build.go b/router/build.go index 4aab6a9c7..22cd37aa4 100644 --- a/router/build.go +++ b/router/build.go @@ -6,10 +6,10 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/build" "github.com/go-vela/server/api/log" "github.com/go-vela/server/router/middleware" - "github.com/go-vela/server/router/middleware/build" + bmiddleware "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/router/middleware/executors" "github.com/go-vela/server/router/middleware/perm" ) @@ -48,27 +48,27 @@ func BuildHandlers(base *gin.RouterGroup) { // Builds endpoints builds := base.Group("/builds") { - builds.POST("", perm.MustAdmin(), middleware.Payload(), api.CreateBuild) - builds.GET("", perm.MustRead(), api.GetBuilds) + builds.POST("", perm.MustAdmin(), middleware.Payload(), build.CreateBuild) + builds.GET("", perm.MustRead(), build.ListBuildsForRepo) // Build endpoints - build := builds.Group("/:build", build.Establish()) + b := builds.Group("/:build", bmiddleware.Establish()) { - build.POST("", perm.MustWrite(), api.RestartBuild) - build.GET("", perm.MustRead(), api.GetBuild) - build.PUT("", perm.MustBuildAccess(), middleware.Payload(), api.UpdateBuild) - build.DELETE("", perm.MustPlatformAdmin(), api.DeleteBuild) - build.DELETE("/cancel", executors.Establish(), perm.MustWrite(), api.CancelBuild) - build.GET("/logs", perm.MustRead(), log.ListLogsForBuild) - build.GET("/token", perm.MustWorkerAuthToken(), api.GetBuildToken) + b.POST("", perm.MustWrite(), build.RestartBuild) + b.GET("", perm.MustRead(), build.GetBuild) + b.PUT("", perm.MustBuildAccess(), middleware.Payload(), build.UpdateBuild) + b.DELETE("", perm.MustPlatformAdmin(), build.DeleteBuild) + b.DELETE("/cancel", executors.Establish(), perm.MustWrite(), build.CancelBuild) + b.GET("/logs", perm.MustRead(), log.ListLogsForBuild) + b.GET("/token", perm.MustWorkerAuthToken(), build.GetBuildToken) // Service endpoints // * Log endpoints - ServiceHandlers(build) + ServiceHandlers(b) // Step endpoints // * Log endpoints - StepHandlers(build) + StepHandlers(b) } // end of build endpoints } // end of builds endpoints } diff --git a/router/repo.go b/router/repo.go index 6d0dbf240..7b7859f6a 100644 --- a/router/repo.go +++ b/router/repo.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/build" "github.com/go-vela/server/api/repo" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/org" @@ -64,7 +64,7 @@ func RepoHandlers(base *gin.RouterGroup) { org := _repos.Group("/:org", org.Establish()) { org.GET("", repo.ListReposForOrg) - org.GET("/builds", api.GetOrgBuilds) + org.GET("/builds", build.ListBuildsForOrg) // Repo endpoints _repo := org.Group("/:repo", rmiddleware.Establish()) diff --git a/router/router.go b/router/router.go index 2ed598034..f95c6bf4b 100644 --- a/router/router.go +++ b/router/router.go @@ -35,6 +35,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/api" "github.com/go-vela/server/api/auth" + "github.com/go-vela/server/api/webhook" "github.com/go-vela/server/router/middleware" "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" @@ -84,7 +85,7 @@ func Load(options ...gin.HandlerFunc) *gin.Engine { r.GET("/version", api.Version) // Webhook endpoint - r.POST("/webhook", api.PostWebhook) + r.POST("/webhook", webhook.PostWebhook) // Authentication endpoints authenticate := r.Group("/authenticate") diff --git a/router/search.go b/router/search.go index 2aaaec699..62e3542db 100644 --- a/router/search.go +++ b/router/search.go @@ -6,7 +6,7 @@ package router import ( "github.com/gin-gonic/gin" - "github.com/go-vela/server/api" + "github.com/go-vela/server/api/build" ) // SearchHandlers is a function that extends the provided base router group @@ -18,9 +18,9 @@ func SearchHandlers(base *gin.RouterGroup) { search := base.Group("/search") { // Build endpoint - build := search.Group("/builds") + b := search.Group("/builds") { - build.GET("/:id", api.GetBuildByID) + b.GET("/:id", build.GetBuildByID) } } // end of search endpoints } From a6002745dc0634a8592d82185f980d615e89dbe2 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 2 Jun 2023 09:36:26 -0500 Subject: [PATCH 249/298] feat(database): add agnostic engine (#868) --- database/close.go | 18 +++++ database/close_test.go | 83 +++++++++++++++++++ database/database.go | 58 +++++++++++++- database/database_test.go | 79 +++++++++++++++++- database/driver.go | 10 +++ database/driver_test.go | 47 +++++++++++ database/validate.go | 75 +++++++++++++++++ database/validate_test.go | 165 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 database/close.go create mode 100644 database/close_test.go create mode 100644 database/driver.go create mode 100644 database/driver_test.go create mode 100644 database/validate.go create mode 100644 database/validate_test.go diff --git a/database/close.go b/database/close.go new file mode 100644 index 000000000..0596b972e --- /dev/null +++ b/database/close.go @@ -0,0 +1,18 @@ +// 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 + +// Close stops and terminates the connection to the database. +func (e *engine) Close() error { + e.Logger.Tracef("closing connection to the %s database", e.Driver()) + + // capture database/sql database from gorm.io/gorm database + _sql, err := e.Database.DB() + if err != nil { + return err + } + + return _sql.Close() +} diff --git a/database/close_test.go b/database/close_test.go new file mode 100644 index 000000000..b555e78d5 --- /dev/null +++ b/database/close_test.go @@ -0,0 +1,83 @@ +// 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 ( + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestDatabase_Engine_Close(t *testing.T) { + _postgres, _mock := testPostgres(t) + defer _postgres.Close() + // ensure the mock expects the close + _mock.ExpectClose() + + // create a test database without mocking the call + _unmocked, _ := testPostgres(t) + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + name: "success with postgres", + failure: false, + database: _postgres, + }, + { + name: "success with sqlite3", + failure: false, + database: _sqlite, + }, + { + name: "failure without mocked call", + failure: true, + database: _unmocked, + }, + { + name: "failure with invalid gorm database", + failure: true, + database: &engine{ + Config: &Config{ + Driver: "invalid", + }, + Database: &gorm.DB{ + Config: &gorm.Config{ + ConnPool: nil, + }, + }, + Logger: logrus.NewEntry(logrus.StandardLogger()), + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.Close() + + if test.failure { + if err == nil { + t.Errorf("Close for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("Close for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/database.go b/database/database.go index ad26dd82a..bf0ca2724 100644 --- a/database/database.go +++ b/database/database.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,10 +6,64 @@ package database import ( "fmt" + "time" + "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" + "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" + "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/user" + "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" - "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // Config represents the settings required to create the engine that implements the Interface. + Config struct { + // specifies the address to use for the database engine + Address string + // specifies the level of compression to use for the database engine + CompressionLevel int + // specifies the maximum idle connections for the database engine + ConnectionIdle int + // specifies the connection duration to use for the database engine + ConnectionLife time.Duration + // specifies the maximum open connections for the database engine + ConnectionOpen int + // specifies the driver to use for the database engine + Driver string + // specifies the encryption key to use for the database engine + EncryptionKey string + // specifies to skip creating tables and indexes for the database engine + SkipCreation bool + } + + // engine represents the functionality that implements the Interface. + engine struct { + Config *Config + Database *gorm.DB + Logger *logrus.Entry + + build.BuildInterface + hook.HookInterface + log.LogInterface + pipeline.PipelineInterface + repo.RepoInterface + schedule.ScheduleInterface + secret.SecretInterface + service.ServiceInterface + step.StepInterface + user.UserInterface + worker.WorkerInterface + } ) // New creates and returns a Vela service capable of diff --git a/database/database_test.go b/database/database_test.go index 14081a382..77de76d5b 100644 --- a/database/database_test.go +++ b/database/database_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. @@ -7,6 +7,13 @@ package database import ( "testing" "time" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" ) func TestDatabase_New(t *testing.T) { @@ -86,3 +93,73 @@ func TestDatabase_New(t *testing.T) { } } } + +// testPostgres is a helper function to create a Postgres engine for testing. +func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { + // create the engine with test configuration + _engine := &engine{ + Config: &Config{ + CompressionLevel: 3, + ConnectionLife: 30 * time.Minute, + ConnectionIdle: 2, + ConnectionOpen: 0, + Driver: "postgres", + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + Logger: logrus.NewEntry(logrus.StandardLogger()), + } + + // create the new mock sql database + _sql, _mock, err := sqlmock.New( + sqlmock.MonitorPingsOption(true), + sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual), + ) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + // ensure the mock expects the ping + _mock.ExpectPing() + + // create the new mock Postgres database client + _engine.Database, err = gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new test postgres database: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + var err error + + // create the engine with test configuration + _engine := &engine{ + Config: &Config{ + Address: "file::memory:?cache=shared", + CompressionLevel: 3, + ConnectionLife: 30 * time.Minute, + ConnectionIdle: 2, + ConnectionOpen: 0, + Driver: "sqlite3", + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + Logger: logrus.NewEntry(logrus.StandardLogger()), + } + + // create the new mock Sqlite database client + _engine.Database, err = gorm.Open( + sqlite.Open(_engine.Config.Address), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new test sqlite database: %v", err) + } + + return _engine +} diff --git a/database/driver.go b/database/driver.go new file mode 100644 index 000000000..a81662846 --- /dev/null +++ b/database/driver.go @@ -0,0 +1,10 @@ +// 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 + +// Driver outputs the configured database driver. +func (e *engine) Driver() string { + return e.Config.Driver +} diff --git a/database/driver_test.go b/database/driver_test.go new file mode 100644 index 000000000..6d382d8cd --- /dev/null +++ b/database/driver_test.go @@ -0,0 +1,47 @@ +// 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 ( + "strings" + "testing" +) + +func TestDatabase_Engine_Driver(t *testing.T) { + _postgres, _ := testPostgres(t) + defer _postgres.Close() + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + name string + database *engine + want string + }{ + { + name: "success with postgres", + database: _postgres, + want: "postgres", + }, + { + name: "success with sqlite3", + database: _sqlite, + want: "sqlite3", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.database.Driver() + + if !strings.EqualFold(got, test.want) { + t.Errorf("Driver for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/validate.go b/database/validate.go new file mode 100644 index 000000000..c16c07cd2 --- /dev/null +++ b/database/validate.go @@ -0,0 +1,75 @@ +// Copyright (c) 2023 Target Brands, Ine. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package database + +import ( + "fmt" + "strings" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" +) + +// Validate verifies the required fields from the provided configuration are populated correctly. +func (c *Config) Validate() error { + logrus.Trace("validating database configuration for engine") + + // verify a database driver was provided + if len(c.Driver) == 0 { + return fmt.Errorf("no database driver provided") + } + + // verify a database address was provided + if len(c.Address) == 0 { + return fmt.Errorf("no database address provided") + } + + // check if the database address has a trailing slash + if strings.HasSuffix(c.Address, "/") { + return fmt.Errorf("invalid database address provided: address must not have trailing slash") + } + + // verify a database encryption key was provided + if len(c.EncryptionKey) == 0 { + return fmt.Errorf("no database encryption key provided") + } + + // check the database encryption key length - enforce AES-256 by forcing 32 characters in the key + if len(c.EncryptionKey) != 32 { + return fmt.Errorf("invalid database encryption key provided: key length (%d) must be 32 characters", len(c.EncryptionKey)) + } + + // verify the database compression level is valid + switch c.CompressionLevel { + case constants.CompressionNegOne: + fallthrough + case constants.CompressionZero: + fallthrough + case constants.CompressionOne: + fallthrough + case constants.CompressionTwo: + fallthrough + case constants.CompressionThree: + fallthrough + case constants.CompressionFour: + fallthrough + case constants.CompressionFive: + fallthrough + case constants.CompressionSix: + fallthrough + case constants.CompressionSeven: + fallthrough + case constants.CompressionEight: + fallthrough + case constants.CompressionNine: + break + default: + return fmt.Errorf("invalid database compression level provided: level (%d) must be between %d and %d", + c.CompressionLevel, constants.CompressionNegOne, constants.CompressionNine, + ) + } + + return nil +} diff --git a/database/validate_test.go b/database/validate_test.go new file mode 100644 index 000000000..356705fe2 --- /dev/null +++ b/database/validate_test.go @@ -0,0 +1,165 @@ +// Copyright (c) 2023 Target Brands, Ine. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package database + +import ( + "testing" + "time" +) + +func TestDatabase_Config_Validate(t *testing.T) { + // setup tests + tests := []struct { + failure bool + name string + config *Config + }{ + { + name: "success with postgres", + failure: false, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "success with sqlite3", + failure: false, + config: &Config{ + Driver: "sqlite3", + Address: "file::memory:?cache=shared", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "success with negative compression level", + failure: false, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: -1, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "failure with empty driver", + failure: true, + config: &Config{ + Driver: "", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "failure with empty address", + failure: true, + config: &Config{ + Driver: "postgres", + Address: "", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "failure with invalid address", + failure: true, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela/", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "failure with invalid compression level", + failure: true, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: 10, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "failure with empty encryption key", + failure: true, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "", + SkipCreation: false, + }, + }, + { + name: "failure with invalid encryption key", + failure: true, + config: &Config{ + Driver: "postgres", + Address: "postgres://foo:bar@localhost:5432/vela", + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0", + SkipCreation: false, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.config.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("Validate for %s returned err: %v", test.name, err) + } + }) + } +} From e4bfa4e038167efa514c0b45aee419432aacc007 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 5 Jun 2023 10:23:43 -0500 Subject: [PATCH 250/298] feat(database): add engine.Ping() (#869) --- database/ping.go | 42 ++++++++++++++++++++++ database/ping_test.go | 82 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 database/ping.go create mode 100644 database/ping_test.go diff --git a/database/ping.go b/database/ping.go new file mode 100644 index 000000000..7ac1a09c2 --- /dev/null +++ b/database/ping.go @@ -0,0 +1,42 @@ +// 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 ( + "fmt" + "time" +) + +// Ping sends a "ping" request with backoff to the database. +func (e *engine) Ping() error { + e.Logger.Tracef("sending ping request to the %s database", e.Driver()) + + // create a loop to attempt ping requests 5 times + for i := 0; i < 5; i++ { + // capture database/sql database from gorm.io/gorm database + _sql, err := e.Database.DB() + if err != nil { + return err + } + + // send ping request to database + err = _sql.Ping() + if err != nil { + // create the duration of time to sleep for before attempting to retry + duration := time.Duration(i+1) * time.Second + + e.Logger.Warnf("unable to ping %s database - retrying in %v", e.Driver(), duration) + + // sleep for loop iteration in seconds + time.Sleep(duration) + + continue + } + + return nil + } + + return fmt.Errorf("unable to successfully ping %s database", e.Driver()) +} diff --git a/database/ping_test.go b/database/ping_test.go new file mode 100644 index 000000000..7a34ad122 --- /dev/null +++ b/database/ping_test.go @@ -0,0 +1,82 @@ +// 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 ( + "testing" + + "github.com/sirupsen/logrus" + "gorm.io/gorm" +) + +func TestDatabase_Engine_Ping(t *testing.T) { + _postgres, _mock := testPostgres(t) + defer _postgres.Close() + // ensure the mock expects the ping + _mock.ExpectPing() + + // create a test database without mocking the call + _unmocked, _ := testPostgres(t) + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + name: "success with postgres", + failure: false, + database: _postgres, + }, + { + name: "success with sqlite", + failure: false, + database: _sqlite, + }, + { + name: "failure without mocked call", + failure: true, + database: _unmocked, + }, + { + name: "failure with invalid gorm database", + failure: true, + database: &engine{ + Config: &Config{ + Driver: "invalid", + }, + Database: &gorm.DB{ + Config: &gorm.Config{ + ConnPool: nil, + }, + }, + Logger: logrus.NewEntry(logrus.StandardLogger()), + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.Ping() + + if test.failure { + if err == nil { + t.Errorf("Ping for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("Ping for %s returned err: %v", test.name, err) + } + }) + } +} From e8bdb157111bb2da2a0cf867c297a2954a791b25 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Wed, 7 Jun 2023 09:21:43 -0500 Subject: [PATCH 251/298] feat(database): add engine.NewResources() (#870) --- database/resource.go | 143 ++++++++++++++++++++++++++++++++++++++ database/resource_test.go | 112 +++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 database/resource.go create mode 100644 database/resource_test.go diff --git a/database/resource.go b/database/resource.go new file mode 100644 index 000000000..93122eadc --- /dev/null +++ b/database/resource.go @@ -0,0 +1,143 @@ +// Copyright (c) 2023 Target Brands, Ine. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package database + +import ( + "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" + "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" + "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/user" + "github.com/go-vela/server/database/worker" +) + +// NewResources creates and returns the database agnostic engines for resources. +func (e *engine) NewResources() error { + var err error + + // create the database agnostic engine for builds + e.BuildInterface, err = build.New( + build.WithClient(e.Database), + build.WithLogger(e.Logger), + build.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for hooks + e.HookInterface, err = hook.New( + hook.WithClient(e.Database), + hook.WithLogger(e.Logger), + hook.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for logs + e.LogInterface, err = log.New( + log.WithClient(e.Database), + log.WithCompressionLevel(e.Config.CompressionLevel), + log.WithLogger(e.Logger), + log.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for pipelines + e.PipelineInterface, err = pipeline.New( + pipeline.WithClient(e.Database), + pipeline.WithCompressionLevel(e.Config.CompressionLevel), + pipeline.WithLogger(e.Logger), + pipeline.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for repos + e.RepoInterface, err = repo.New( + repo.WithClient(e.Database), + repo.WithEncryptionKey(e.Config.EncryptionKey), + repo.WithLogger(e.Logger), + repo.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for schedules + e.ScheduleInterface, err = schedule.New( + schedule.WithClient(e.Database), + schedule.WithLogger(e.Logger), + schedule.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for secrets + // + // https://pkg.go.dev/github.com/go-vela/server/database/secret#New + e.SecretInterface, err = secret.New( + secret.WithClient(e.Database), + secret.WithEncryptionKey(e.Config.EncryptionKey), + secret.WithLogger(e.Logger), + secret.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for services + e.ServiceInterface, err = service.New( + service.WithClient(e.Database), + service.WithLogger(e.Logger), + service.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for steps + e.StepInterface, err = step.New( + step.WithClient(e.Database), + step.WithLogger(e.Logger), + step.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for users + e.UserInterface, err = user.New( + user.WithClient(e.Database), + user.WithEncryptionKey(e.Config.EncryptionKey), + user.WithLogger(e.Logger), + user.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + // create the database agnostic engine for workers + e.WorkerInterface, err = worker.New( + worker.WithClient(e.Database), + worker.WithLogger(e.Logger), + worker.WithSkipCreation(e.Config.SkipCreation), + ) + if err != nil { + return err + } + + return nil +} diff --git a/database/resource_test.go b/database/resource_test.go new file mode 100644 index 000000000..36a4694e6 --- /dev/null +++ b/database/resource_test.go @@ -0,0 +1,112 @@ +// 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 ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" + "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" + "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/user" + "github.com/go-vela/server/database/worker" +) + +func TestDatabase_Engine_NewResources(t *testing.T) { + _postgres, _mock := testPostgres(t) + defer _postgres.Close() + + // ensure the mock expects the build queries + _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the hook queries + _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the log queries + _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the pipeline queries + _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the repo queries + _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the schedule queries + _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the secret queries + _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the service queries + _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the step queries + _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the user queries + _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the worker queries + _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create a test database without mocking the call + _unmocked, _ := testPostgres(t) + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + name: "success with postgres", + failure: false, + database: _postgres, + }, + { + name: "success with sqlite3", + failure: false, + database: _sqlite, + }, + { + name: "failure without mocked call", + failure: true, + database: _unmocked, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.NewResources() + + if test.failure { + if err == nil { + t.Errorf("NewResources for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("NewResources for %s returned err: %v", test.name, err) + } + }) + } +} From 63d323f4af2039cc83bb1d8153f095ed552daa65 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:39:23 -0600 Subject: [PATCH 252/298] fix(mock): correct query param mocks (#866) Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- mock/server/build.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mock/server/build.go b/mock/server/build.go index db526cb29..6d989d8af 100644 --- a/mock/server/build.go +++ b/mock/server/build.go @@ -342,18 +342,18 @@ func buildToken(c *gin.Context) { // cleanResources has a query param :before returns mock JSON for a http PUT // -// Pass "0" to :before to test receiving a http 500 response. Pass "1" to :before +// Pass "1" to :before to test receiving a http 500 response. Pass "2" to :before // to test receiving a http 401 response. func cleanResoures(c *gin.Context) { before := c.Query("before") - if strings.EqualFold(before, "0") { + if strings.EqualFold(before, "1") { c.AbortWithStatusJSON(http.StatusInternalServerError, "") return } - if strings.EqualFold(before, "1") { + if strings.EqualFold(before, "2") { c.AbortWithStatusJSON(http.StatusUnauthorized, "") } From da734388cd3b8415bf714415aadd76a3f20cfdf7 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 8 Jun 2023 08:51:22 -0600 Subject: [PATCH 253/298] refactor(db/log): return library log on created and updated (#865) Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- api/log/create_service.go | 5 +---- api/log/create_step.go | 5 +---- api/log/update_service.go | 5 +---- api/log/update_step.go | 5 +---- api/service/plan.go | 2 +- api/step/plan.go | 2 +- database/log/count_build_test.go | 4 ++-- database/log/count_test.go | 4 ++-- database/log/create.go | 15 +++++++-------- database/log/create_test.go | 2 +- database/log/delete_test.go | 2 +- database/log/get_service_test.go | 2 +- database/log/get_step_test.go | 2 +- database/log/get_test.go | 2 +- database/log/interface.go | 4 ++-- database/log/list_build_test.go | 4 ++-- database/log/list_test.go | 4 ++-- database/log/update.go | 15 +++++++-------- database/log/update_test.go | 6 +++--- 19 files changed, 38 insertions(+), 52 deletions(-) diff --git a/api/log/create_service.go b/api/log/create_service.go index dd559073c..c6014f09b 100644 --- a/api/log/create_service.go +++ b/api/log/create_service.go @@ -113,7 +113,7 @@ func CreateServiceLog(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the logs - err = database.FromContext(c).CreateLog(input) + l, err := database.FromContext(c).CreateLog(input) if err != nil { retErr := fmt.Errorf("unable to create logs for service %s: %w", entry, err) @@ -122,8 +122,5 @@ func CreateServiceLog(c *gin.Context) { return } - // send API call to capture the created log - l, _ := database.FromContext(c).GetLogForService(s) - c.JSON(http.StatusCreated, l) } diff --git a/api/log/create_step.go b/api/log/create_step.go index 0f8a1ca5a..5bc83c646 100644 --- a/api/log/create_step.go +++ b/api/log/create_step.go @@ -113,7 +113,7 @@ func CreateStepLog(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the logs - err = database.FromContext(c).CreateLog(input) + l, err := database.FromContext(c).CreateLog(input) if err != nil { retErr := fmt.Errorf("unable to create logs for step %s: %w", entry, err) @@ -122,8 +122,5 @@ func CreateStepLog(c *gin.Context) { return } - // send API call to capture the created log - l, _ := database.FromContext(c).GetLogForStep(s) - c.JSON(http.StatusCreated, l) } diff --git a/api/log/update_service.go b/api/log/update_service.go index 746fd63e5..82b56f13b 100644 --- a/api/log/update_service.go +++ b/api/log/update_service.go @@ -124,7 +124,7 @@ func UpdateServiceLog(c *gin.Context) { } // send API call to update the log - err = database.FromContext(c).UpdateLog(l) + l, err = database.FromContext(c).UpdateLog(l) if err != nil { retErr := fmt.Errorf("unable to update logs for service %s: %w", entry, err) @@ -133,8 +133,5 @@ func UpdateServiceLog(c *gin.Context) { return } - // send API call to capture the updated log - l, _ = database.FromContext(c).GetLogForService(s) - c.JSON(http.StatusOK, l) } diff --git a/api/log/update_step.go b/api/log/update_step.go index a86a74113..dcb4a99d1 100644 --- a/api/log/update_step.go +++ b/api/log/update_step.go @@ -124,7 +124,7 @@ func UpdateStepLog(c *gin.Context) { } // send API call to update the log - err = database.FromContext(c).UpdateLog(l) + l, err = database.FromContext(c).UpdateLog(l) if err != nil { retErr := fmt.Errorf("unable to update logs for step %s: %w", entry, err) @@ -133,8 +133,5 @@ func UpdateStepLog(c *gin.Context) { return } - // send API call to capture the updated log - l, _ = database.FromContext(c).GetLogForStep(s) - c.JSON(http.StatusOK, l) } diff --git a/api/service/plan.go b/api/service/plan.go index 4912f38d1..fecd03f24 100644 --- a/api/service/plan.go +++ b/api/service/plan.go @@ -61,7 +61,7 @@ func PlanServices(database database.Interface, p *pipeline.Build, b *library.Bui l.SetData([]byte{}) // send API call to create the service logs - err = database.CreateLog(l) + _, err = database.CreateLog(l) if err != nil { return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) } diff --git a/api/step/plan.go b/api/step/plan.go index b072cf4f7..c74a52614 100644 --- a/api/step/plan.go +++ b/api/step/plan.go @@ -88,7 +88,7 @@ func planStep(database database.Interface, b *library.Build, c *pipeline.Contain l.SetData([]byte{}) // send API call to create the step logs - err = database.CreateLog(l) + _, err = database.CreateLog(l) if err != nil { return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) } diff --git a/database/log/count_build_test.go b/database/log/count_build_test.go index d462eedf0..e168f80ec 100644 --- a/database/log/count_build_test.go +++ b/database/log/count_build_test.go @@ -43,12 +43,12 @@ func TestLog_Engine_CountLogsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_service) + _, err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - err = _sqlite.CreateLog(_step) + _, err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/count_test.go b/database/log/count_test.go index 99e75a767..2af820203 100644 --- a/database/log/count_test.go +++ b/database/log/count_test.go @@ -37,12 +37,12 @@ func TestLog_Engine_CountLogs(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_service) + _, err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - err = _sqlite.CreateLog(_step) + _, err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/create.go b/database/log/create.go index 978da9a1f..b1767c01e 100644 --- a/database/log/create.go +++ b/database/log/create.go @@ -14,7 +14,7 @@ import ( ) // CreateLog creates a new log in the database. -func (e *engine) CreateLog(l *library.Log) error { +func (e *engine) CreateLog(l *library.Log) (*library.Log, error) { // check what the log entry is for switch { case l.GetServiceID() > 0: @@ -33,7 +33,7 @@ func (e *engine) CreateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate err := log.Validate() if err != nil { - return err + return nil, err } // compress log data for the resource @@ -43,15 +43,14 @@ func (e *engine) CreateLog(l *library.Log) error { if err != nil { switch { case l.GetServiceID() > 0: - return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + return nil, fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) case l.GetStepID() > 0: - return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + return nil, fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) } } // send query to the database - return e.client. - Table(constants.TableLog). - Create(log). - Error + result := e.client.Table(constants.TableLog).Create(log) + + return log.ToLibrary(), result.Error } diff --git a/database/log/create_test.go b/database/log/create_test.go index 1574e88a8..68e0a2d40 100644 --- a/database/log/create_test.go +++ b/database/log/create_test.go @@ -73,7 +73,7 @@ VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`). for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, log := range test.logs { - err := test.database.CreateLog(log) + _, err := test.database.CreateLog(log) if test.failure { if err == nil { diff --git a/database/log/delete_test.go b/database/log/delete_test.go index 15329a0af..dbfdbca00 100644 --- a/database/log/delete_test.go +++ b/database/log/delete_test.go @@ -29,7 +29,7 @@ func TestLog_Engine_DeleteLog(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_log) + _, err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_service_test.go b/database/log/get_service_test.go index 26f42813c..3ff82d6c8 100644 --- a/database/log/get_service_test.go +++ b/database/log/get_service_test.go @@ -42,7 +42,7 @@ func TestLog_Engine_GetLogForService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_log) + _, err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_step_test.go b/database/log/get_step_test.go index 39f019039..d092e30a9 100644 --- a/database/log/get_step_test.go +++ b/database/log/get_step_test.go @@ -42,7 +42,7 @@ func TestLog_Engine_GetLogForStep(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_log) + _, err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_test.go b/database/log/get_test.go index 31325e3ac..7127d3165 100644 --- a/database/log/get_test.go +++ b/database/log/get_test.go @@ -35,7 +35,7 @@ func TestLog_Engine_GetLog(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_log) + _, err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/interface.go b/database/log/interface.go index 8c72a5098..5b71be967 100644 --- a/database/log/interface.go +++ b/database/log/interface.go @@ -31,7 +31,7 @@ type LogInterface interface { // CountLogsForBuild defines a function that gets the count of logs by build ID. CountLogsForBuild(*library.Build) (int64, error) // CreateLog defines a function that creates a new log. - CreateLog(*library.Log) error + CreateLog(*library.Log) (*library.Log, error) // DeleteLog defines a function that deletes an existing log. DeleteLog(*library.Log) error // GetLog defines a function that gets a log by ID. @@ -45,5 +45,5 @@ type LogInterface interface { // ListLogsForBuild defines a function that gets a list of logs by build ID. ListLogsForBuild(*library.Build, int, int) ([]*library.Log, int64, error) // UpdateLog defines a function that updates an existing log. - UpdateLog(*library.Log) error + UpdateLog(*library.Log) (*library.Log, error) } diff --git a/database/log/list_build_test.go b/database/log/list_build_test.go index fb08236e9..7ffcc0f46 100644 --- a/database/log/list_build_test.go +++ b/database/log/list_build_test.go @@ -54,12 +54,12 @@ func TestLog_Engine_ListLogsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_service) + _, err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - err = _sqlite.CreateLog(_step) + _, err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/list_test.go b/database/log/list_test.go index 0cf420255..343af9d5a 100644 --- a/database/log/list_test.go +++ b/database/log/list_test.go @@ -48,12 +48,12 @@ func TestLog_Engine_ListLogs(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_service) + _, err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - err = _sqlite.CreateLog(_step) + _, err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/update.go b/database/log/update.go index fb7165004..62ba865bc 100644 --- a/database/log/update.go +++ b/database/log/update.go @@ -14,7 +14,7 @@ import ( ) // UpdateLog updates an existing log in the database. -func (e *engine) UpdateLog(l *library.Log) error { +func (e *engine) UpdateLog(l *library.Log) (*library.Log, error) { // check what the log entry is for switch { case l.GetServiceID() > 0: @@ -33,7 +33,7 @@ func (e *engine) UpdateLog(l *library.Log) error { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate err := log.Validate() if err != nil { - return err + return nil, err } // compress log data for the resource @@ -43,15 +43,14 @@ func (e *engine) UpdateLog(l *library.Log) error { if err != nil { switch { case l.GetServiceID() > 0: - return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + return nil, fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) case l.GetStepID() > 0: - return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + return nil, fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) } } // send query to the database - return e.client. - Table(constants.TableLog). - Save(log). - Error + result := e.client.Table(constants.TableLog).Save(log) + + return log.ToLibrary(), result.Error } diff --git a/database/log/update_test.go b/database/log/update_test.go index 0b4e8e127..9659cfb65 100644 --- a/database/log/update_test.go +++ b/database/log/update_test.go @@ -47,12 +47,12 @@ WHERE "id" = $6`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateLog(_service) + _, err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - err = _sqlite.CreateLog(_step) + _, err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } @@ -82,7 +82,7 @@ WHERE "id" = $6`). for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, log := range test.logs { - err = test.database.UpdateLog(log) + _, err = test.database.UpdateLog(log) if test.failure { if err == nil { From 470791d51178a9f96a33eb288c3fd102a5ae6dc7 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Thu, 8 Jun 2023 11:45:26 -0500 Subject: [PATCH 254/298] refactor(database): use agnostic engine (#873) * feat(database): add agnostic engine * feat(database): add config.Validate() * feat(database): add engine.Close() * feat(database): add engine.Driver() * chore: minor fixes * feat(database): add engine.Ping() * feat(database): add engine.NewResources() * refactor(database): use agnostic engine * feat(database): add FromCLIContext() * chore: use database.FromCLIContext() * chore(database): remove unused code * chore: misc updates * chore: fix typos --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- cmd/vela-server/database.go | 35 ------ cmd/vela-server/server.go | 3 +- database/context.go | 21 +++- database/context_test.go | 177 +++++++++++++++++--------- database/database.go | 98 +++++++++++---- database/database_test.go | 45 ++++--- database/flags.go | 9 +- database/interface.go | 18 ++- database/setup.go | 140 --------------------- database/setup_test.go | 245 ------------------------------------ 10 files changed, 256 insertions(+), 535 deletions(-) delete mode 100644 cmd/vela-server/database.go delete mode 100644 database/setup.go delete mode 100644 database/setup_test.go diff --git a/cmd/vela-server/database.go b/cmd/vela-server/database.go deleted file mode 100644 index e4db992ec..000000000 --- a/cmd/vela-server/database.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package main - -import ( - "github.com/go-vela/server/database" - - "github.com/sirupsen/logrus" - - "github.com/urfave/cli/v2" -) - -// helper function to setup the database from the CLI arguments. -func setupDatabase(c *cli.Context) (database.Interface, error) { - logrus.Debug("Creating database client from CLI configuration") - - // database configuration - _setup := &database.Setup{ - Driver: c.String("database.driver"), - Address: c.String("database.addr"), - CompressionLevel: c.Int("database.compression.level"), - ConnectionLife: c.Duration("database.connection.life"), - ConnectionIdle: c.Int("database.connection.idle"), - ConnectionOpen: c.Int("database.connection.open"), - EncryptionKey: c.String("database.encryption.key"), - SkipCreation: c.Bool("database.skip_creation"), - } - - // setup the database - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#New - return database.New(_setup) -} diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 80508e4b0..0d95e88e5 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" "github.com/go-vela/server/router" "github.com/go-vela/server/router/middleware" "github.com/sirupsen/logrus" @@ -61,7 +62,7 @@ func server(c *cli.Context) error { return err } - database, err := setupDatabase(c) + database, err := database.FromCLIContext(c) if err != nil { return err } diff --git a/database/context.go b/database/context.go index f3a872602..d27d73550 100644 --- a/database/context.go +++ b/database/context.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,6 +6,9 @@ package database import ( "context" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" ) const key = "database" @@ -35,3 +38,19 @@ func FromContext(c context.Context) Interface { func ToContext(c Setter, d Interface) { c.Set(key, d) } + +// FromCLIContext creates and returns a database engine from the urfave/cli context. +func FromCLIContext(c *cli.Context) (Interface, error) { + logrus.Debug("creating database engine from CLI configuration") + + return New(&Config{ + Address: c.String("database.addr"), + CompressionLevel: c.Int("database.compression.level"), + ConnectionLife: c.Duration("database.connection.life"), + ConnectionIdle: c.Int("database.connection.idle"), + ConnectionOpen: c.Int("database.connection.open"), + Driver: c.String("database.driver"), + EncryptionKey: c.String("database.encryption.key"), + SkipCreation: c.Bool("database.skip_creation"), + }) +} diff --git a/database/context_test.go b/database/context_test.go index 382567a43..4037b26c0 100644 --- a/database/context_test.go +++ b/database/context_test.go @@ -1,91 +1,152 @@ -// 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. package database import ( + "flag" + "reflect" "testing" + "time" "github.com/gin-gonic/gin" - "github.com/go-vela/server/database/sqlite" + "github.com/urfave/cli/v2" ) func TestDatabase_FromContext(t *testing.T) { - // setup types - want, _ := sqlite.NewTest() + _postgres, _ := testPostgres(t) + defer _postgres.Close() - defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() - - // setup context gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, want) - - // run test - got := FromContext(context) - - if got != want { - t.Errorf("FromContext is %v, want %v", got, want) + ctx, _ := gin.CreateTestContext(nil) + ctx.Set(key, _postgres) + + typeCtx, _ := gin.CreateTestContext(nil) + typeCtx.Set(key, nil) + + nilCtx, _ := gin.CreateTestContext(nil) + nilCtx.Set(key, nil) + + // setup tests + tests := []struct { + name string + context *gin.Context + want Interface + }{ + { + name: "success", + context: ctx, + want: _postgres, + }, + { + name: "failure with nil", + context: nilCtx, + want: nil, + }, + { + name: "failure with wrong type", + context: typeCtx, + want: nil, + }, } -} -func TestDatabase_FromContext_Bad(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, nil) - - // run test - got := FromContext(context) - - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := FromContext(test.context) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("FromContext for %s is %v, want %v", test.name, got, test.want) + } + }) } } -func TestDatabase_FromContext_WrongType(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) +func TestDatabase_ToContext(t *testing.T) { context, _ := gin.CreateTestContext(nil) - context.Set(key, 1) - - // run test - got := FromContext(context) - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + _postgres, _ := testPostgres(t) + defer _postgres.Close() + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + name string + database *engine + want *engine + }{ + { + name: "success with postgres", + database: _postgres, + want: _postgres, + }, + { + name: "success with sqlite3", + database: _sqlite, + want: _sqlite, + }, } -} - -func TestDatabase_FromContext_Empty(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - // run test - got := FromContext(context) + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ToContext(context, test.want) - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + got := context.Value(key) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ToContext for %s is %v, want %v", test.name, got, test.want) + } + }) } } -func TestDatabase_ToContext(t *testing.T) { - // setup types - want, _ := sqlite.NewTest() +func TestDatabase_FromCLIContext(t *testing.T) { + flags := flag.NewFlagSet("test", 0) + flags.String("database.driver", "sqlite3", "doc") + flags.String("database.addr", "file::memory:?cache=shared", "doc") + flags.Int("database.compression.level", 3, "doc") + flags.Duration("database.connection.life", 10*time.Second, "doc") + flags.Int("database.connection.idle", 5, "doc") + flags.Int("database.connection.open", 20, "doc") + flags.String("database.encryption.key", "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", "doc") + flags.Bool("database.skip_creation", true, "doc") + + // setup tests + tests := []struct { + name string + failure bool + context *cli.Context + }{ + { + name: "success", + failure: false, + context: cli.NewContext(&cli.App{Name: "vela"}, flags, nil), + }, + { + name: "failure", + failure: true, + context: cli.NewContext(&cli.App{Name: "vela"}, flag.NewFlagSet("test", 0), nil), + }, + } - defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, err := FromCLIContext(test.context) - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - ToContext(context, want) + if test.failure { + if err == nil { + t.Errorf("FromCLIContext for %s should have returned err", test.name) + } - // run test - got := context.Value(key) + return + } - if got != want { - t.Errorf("ToContext is %v, want %v", got, want) + if err != nil { + t.Errorf("FromCLIContext for %s returned err: %v", test.name, err) + } + }) } } diff --git a/database/database.go b/database/database.go index bf0ca2724..5fe3de951 100644 --- a/database/database.go +++ b/database/database.go @@ -22,6 +22,8 @@ import ( "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" "gorm.io/gorm" ) @@ -32,10 +34,10 @@ type ( Address string // specifies the level of compression to use for the database engine CompressionLevel int - // specifies the maximum idle connections for the database engine - ConnectionIdle int // specifies the connection duration to use for the database engine ConnectionLife time.Duration + // specifies the maximum idle connections for the database engine + ConnectionIdle int // specifies the maximum open connections for the database engine ConnectionOpen int // specifies the driver to use for the database engine @@ -66,38 +68,86 @@ type ( } ) -// New creates and returns a Vela service capable of -// integrating with the configured database provider. +// New creates and returns an engine capable of integrating with the configured database provider. // -// Currently the following database providers are supported: +// Currently, the following database providers are supported: // -// * Postgres -// * Sqlite -// . -func New(s *Setup) (Interface, error) { - // validate the setup being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Validate - err := s.Validate() +// * postgres +// * sqlite3 +func New(c *Config) (Interface, error) { + // validate the configuration being provided + err := c.Validate() if err != nil { return nil, err } - logrus.Debug("creating database service from setup") + // create new database engine + e := &engine{ + Config: c, + Database: new(gorm.DB), + Logger: logrus.NewEntry(logrus.StandardLogger()).WithField("database", c.Driver), + } + + e.Logger.Trace("creating database engine from configuration") // process the database driver being provided - switch s.Driver { + switch c.Driver { case constants.DriverPostgres: - // handle the Postgres database driver being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Postgres - return s.Postgres() + // create the new Postgres database client + e.Database, err = gorm.Open(postgres.Open(e.Config.Address), &gorm.Config{}) + if err != nil { + return nil, err + } case constants.DriverSqlite: - // handle the Sqlite database driver being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Sqlite - return s.Sqlite() + // create the new Sqlite database client + e.Database, err = gorm.Open(sqlite.Open(e.Config.Address), &gorm.Config{}) + if err != nil { + return nil, err + } default: // handle an invalid database driver being provided - return nil, fmt.Errorf("invalid database driver provided: %s", s.Driver) + return nil, fmt.Errorf("invalid database driver provided: %s", c.Driver) } + + // capture database/sql database from gorm.io/gorm database + db, err := e.Database.DB() + if err != nil { + return nil, err + } + + // set the maximum amount of time a connection may be reused + db.SetConnMaxLifetime(e.Config.ConnectionLife) + // set the maximum number of connections in the idle connection pool + db.SetMaxIdleConns(e.Config.ConnectionIdle) + // set the maximum number of open connections to the database + db.SetMaxOpenConns(e.Config.ConnectionOpen) + + // verify connection to the database + err = e.Ping() + if err != nil { + return nil, err + } + + // create database agnostic engines for resources + err = e.NewResources() + if err != nil { + return nil, err + } + + return e, nil +} + +// NewTest creates and returns an engine that integrates with an in-memory database provider. +// +// This function is ONLY intended to be used for testing purposes. +func NewTest() (Interface, error) { + return New(&Config{ + Address: "file::memory:?cache=shared", + CompressionLevel: 3, + ConnectionLife: 30 * time.Minute, + ConnectionIdle: 2, + ConnectionOpen: 0, + Driver: "sqlite3", + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }) } diff --git a/database/database_test.go b/database/database_test.go index 77de76d5b..6d18421bc 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -20,11 +20,13 @@ func TestDatabase_New(t *testing.T) { // setup tests tests := []struct { failure bool - setup *Setup + name string + config *Config }{ { + name: "failure with postgres", failure: true, - setup: &Setup{ + config: &Config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -36,8 +38,9 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "success with sqlite3", failure: false, - setup: &Setup{ + config: &Config{ Driver: "sqlite3", Address: "file::memory:?cache=shared", CompressionLevel: 3, @@ -49,10 +52,11 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "failure with invalid config", failure: true, - setup: &Setup{ - Driver: "mysql", - Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local", + config: &Config{ + Driver: "postgres", + Address: "", CompressionLevel: 3, ConnectionLife: 10 * time.Second, ConnectionIdle: 5, @@ -62,10 +66,11 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "failure with invalid driver", failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "", + config: &Config{ + Driver: "mysql", + Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local", CompressionLevel: 3, ConnectionLife: 10 * time.Second, ConnectionIdle: 5, @@ -78,19 +83,21 @@ func TestDatabase_New(t *testing.T) { // run tests for _, test := range tests { - _, err := New(test.setup) + t.Run(test.name, func(t *testing.T) { + _, err := New(test.config) - if test.failure { - if err == nil { - t.Errorf("New should have returned err") - } + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } - continue - } + return + } - if err != nil { - t.Errorf("New returned err: %v", err) - } + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + }) } } diff --git a/database/flags.go b/database/flags.go index 75d3c109b..f8d4fd36e 100644 --- a/database/flags.go +++ b/database/flags.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. @@ -11,13 +11,8 @@ import ( "github.com/urfave/cli/v2" ) -// Flags represents all supported command line -// interface (CLI) flags for the database. -// -// https://pkg.go.dev/github.com/urfave/cli?tab=doc#Flag +// Flags represents all supported command line interface (CLI) flags for the database. var Flags = []cli.Flag{ - // Database Flags - &cli.StringFlag{ EnvVars: []string{"VELA_DATABASE_DRIVER", "DATABASE_DRIVER"}, FilePath: "/vela/database/driver", diff --git a/database/interface.go b/database/interface.go index 975206c93..eed4b27c8 100644 --- a/database/interface.go +++ b/database/interface.go @@ -18,15 +18,23 @@ import ( "github.com/go-vela/server/database/worker" ) -// Interface represents the interface for Vela integrating -// with the different supported Database backends. +// Interface represents the interface for integrating with the supported database providers. type Interface interface { - // Database Interface Functions + // Generic Interface Functions - // Driver defines a function that outputs - // the configured database driver. + // TODO: Add this function to the interface once other code has been updated to use the agnostic engine. + // + // Close defines a function that stops and terminates the connection to the database. + // Close() error + + // Driver defines a function that outputs the configured database driver. Driver() string + // Ping defines a function that sends a "ping" request to the configured database. + Ping() error + + // Resource Interface Functions + // BuildInterface defines the interface for builds stored in the database. build.BuildInterface diff --git a/database/setup.go b/database/setup.go deleted file mode 100644 index a4b553d4d..000000000 --- a/database/setup.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package database - -import ( - "fmt" - "strings" - "time" - - "github.com/go-vela/server/database/postgres" - "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/types/constants" - "github.com/sirupsen/logrus" -) - -// Setup represents the configuration necessary for -// creating a Vela service capable of integrating -// with a configured database system. -type Setup struct { - // Database Configuration - - // specifies the driver to use for the database client - Driver string - // specifies the address to use for the database client - Address string - // specifies the level of compression to use for the database client - CompressionLevel int - // specifies the connection duration to use for the database client - ConnectionLife time.Duration - // specifies the maximum idle connections for the database client - ConnectionIdle int - // specifies the maximum open connections for the database client - ConnectionOpen int - // specifies the encryption key to use for the database client - EncryptionKey string - // specifies to skip creating tables and indexes for the database client - SkipCreation bool -} - -// Postgres creates and returns a Vela service capable of -// integrating with a Postgres database system. -func (s *Setup) Postgres() (Interface, error) { - logrus.Trace("creating postgres database client from setup") - - // create new Postgres database service - // - // https://pkg.go.dev/github.com/go-vela/server/database/postgres?tab=doc#New - return postgres.New( - postgres.WithAddress(s.Address), - postgres.WithCompressionLevel(s.CompressionLevel), - postgres.WithConnectionLife(s.ConnectionLife), - postgres.WithConnectionIdle(s.ConnectionIdle), - postgres.WithConnectionOpen(s.ConnectionOpen), - postgres.WithEncryptionKey(s.EncryptionKey), - postgres.WithSkipCreation(s.SkipCreation), - ) -} - -// Sqlite creates and returns a Vela service capable of -// integrating with a Sqlite database system. -func (s *Setup) Sqlite() (Interface, error) { - logrus.Trace("creating sqlite database client from setup") - - // create new Sqlite database service - // - // https://pkg.go.dev/github.com/go-vela/server/database/sqlite?tab=doc#New - return sqlite.New( - sqlite.WithAddress(s.Address), - sqlite.WithCompressionLevel(s.CompressionLevel), - sqlite.WithConnectionLife(s.ConnectionLife), - sqlite.WithConnectionIdle(s.ConnectionIdle), - sqlite.WithConnectionOpen(s.ConnectionOpen), - sqlite.WithEncryptionKey(s.EncryptionKey), - sqlite.WithSkipCreation(s.SkipCreation), - ) -} - -// Validate verifies the necessary fields for the -// provided configuration are populated correctly. -func (s *Setup) Validate() error { - logrus.Trace("validating database setup for client") - - // verify a database driver was provided - if len(s.Driver) == 0 { - return fmt.Errorf("no database driver provided") - } - - // verify a database address was provided - if len(s.Address) == 0 { - return fmt.Errorf("no database address provided") - } - - // check if the database address has a trailing slash - if strings.HasSuffix(s.Address, "/") { - return fmt.Errorf("database address must not have trailing slash") - } - - // verify a database encryption key was provided - if len(s.EncryptionKey) == 0 { - return fmt.Errorf("no database encryption key provided") - } - - // verify the database compression level is valid - switch s.CompressionLevel { - case constants.CompressionNegOne: - fallthrough - case constants.CompressionZero: - fallthrough - case constants.CompressionOne: - fallthrough - case constants.CompressionTwo: - fallthrough - case constants.CompressionThree: - fallthrough - case constants.CompressionFour: - fallthrough - case constants.CompressionFive: - fallthrough - case constants.CompressionSix: - fallthrough - case constants.CompressionSeven: - fallthrough - case constants.CompressionEight: - fallthrough - case constants.CompressionNine: - break - default: - return fmt.Errorf("database compression level must be between %d and %d - provided level: %d", constants.CompressionNegOne, constants.CompressionNine, s.CompressionLevel) - } - - // enforce AES-256 for the encryption key - explicitly check for 32 characters in the key - if len(s.EncryptionKey) != 32 { - return fmt.Errorf("database encryption key must have 32 characters - provided length: %d", len(s.EncryptionKey)) - } - - // setup is valid - return nil -} diff --git a/database/setup_test.go b/database/setup_test.go deleted file mode 100644 index 4ec2c958c..000000000 --- a/database/setup_test.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package database - -import ( - "testing" - "time" -) - -func TestDatabase_Setup_Postgres(t *testing.T) { - // setup types - _setup := &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: true, - setup: _setup, - }, - { - failure: true, - setup: &Setup{Driver: "postgres"}, - }, - } - - // run tests - for _, test := range tests { - _, err := test.setup.Postgres() - - if test.failure { - if err == nil { - t.Errorf("Postgres should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Postgres returned err: %v", err) - } - } -} - -func TestDatabase_Setup_Sqlite(t *testing.T) { - // setup types - _setup := &Setup{ - Driver: "sqlite3", - Address: "file::memory:?cache=shared", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: false, - setup: _setup, - }, - { - failure: true, - setup: &Setup{Driver: "sqlite3"}, - }, - } - - // run tests - for _, test := range tests { - _, err := test.setup.Sqlite() - - if test.failure { - if err == nil { - t.Errorf("Sqlite should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Sqlite returned err: %v", err) - } - } -} - -func TestDatabase_Setup_Validate(t *testing.T) { - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: false, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: false, - setup: &Setup{ - Driver: "sqlite3", - Address: "file::memory:?cache=shared", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: false, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: -1, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela/", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 10, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - } - - // run tests - for _, test := range tests { - err := test.setup.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) - } - } -} From 3e887957406f4c68a87d3e4c837e9f9ba1b2c548 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 9 Jun 2023 08:47:21 -0500 Subject: [PATCH 255/298] fix(schedules): increment repo counter after read (#877) --- cmd/vela-server/schedule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index a71688606..532dd65b7 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -233,7 +233,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // set the build numbers based off repo counter - r.SetCounter(r.GetCounter() + 1) b.SetNumber(r.GetCounter() + 1) // set the parent equal to the current repo counter b.SetParent(r.GetCounter()) @@ -242,6 +241,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat // parent should be "1" if it's the first build ran b.SetParent(1) } + r.SetCounter(r.GetCounter() + 1) // set the build link if a web address is provided if len(metadata.Vela.WebAddress) > 0 { From ad8d7d706204f65252685c1499466d981414ca61 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 9 Jun 2023 09:29:34 -0500 Subject: [PATCH 256/298] refactor(testing): use database.NewTest() (#878) * refactor(internal): sqlite.NewTest() -> database.NewTest() * refactor(router): sqlite.NewTest() -> database.NewTest() * refactor(secret): sqlite.NewTest() -> database.NewTest() * chore(database): add Close() to Interface{} --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- database/interface.go | 4 +- internal/token/refresh_test.go | 24 +- router/middleware/build/build_test.go | 54 ++-- router/middleware/claims/claims_test.go | 17 +- router/middleware/database_test.go | 9 +- router/middleware/org/org_test.go | 19 +- router/middleware/perm/perm_test.go | 280 +++++++++++--------- router/middleware/pipeline/pipeline_test.go | 42 +-- router/middleware/repo/repo_test.go | 35 ++- router/middleware/secret_test.go | 12 +- router/middleware/service/service_test.go | 72 ++--- router/middleware/step/step_test.go | 72 ++--- router/middleware/user/user_test.go | 41 +-- router/middleware/worker/worker_test.go | 19 +- secret/context_test.go | 25 +- secret/native/count_test.go | 26 +- secret/native/create_test.go | 42 +-- secret/native/delete_test.go | 20 +- secret/native/driver_test.go | 7 +- secret/native/get_test.go | 21 +- secret/native/list_test.go | 31 ++- secret/native/native_test.go | 8 +- secret/native/opts_test.go | 8 +- secret/native/update_test.go | 20 +- secret/secret_test.go | 11 +- secret/setup_test.go | 20 +- 26 files changed, 533 insertions(+), 406 deletions(-) diff --git a/database/interface.go b/database/interface.go index eed4b27c8..3ed775707 100644 --- a/database/interface.go +++ b/database/interface.go @@ -22,10 +22,8 @@ import ( type Interface interface { // Generic Interface Functions - // TODO: Add this function to the interface once other code has been updated to use the agnostic engine. - // // Close defines a function that stops and terminates the connection to the database. - // Close() error + Close() error // Driver defines a function that outputs the configured database driver. Driver() string diff --git a/internal/token/refresh_test.go b/internal/token/refresh_test.go index a1873f01e..e306f9ed6 100644 --- a/internal/token/refresh_test.go +++ b/internal/token/refresh_test.go @@ -10,10 +10,10 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - jwt "github.com/golang-jwt/jwt/v5" + "github.com/golang-jwt/jwt/v5" ) func TestTokenManager_Refresh(t *testing.T) { @@ -45,12 +45,14 @@ func TestTokenManager_Refresh(t *testing.T) { u.SetRefreshToken(rt) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) @@ -102,12 +104,14 @@ func TestTokenManager_Refresh_Expired(t *testing.T) { u.SetRefreshToken(rt) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 1822164b4..10af76ab7 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -10,11 +10,9 @@ import ( "reflect" "testing" - "github.com/go-vela/server/router/middleware/org" - "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/types/library" ) @@ -85,13 +83,15 @@ func TestBuild_Establish(t *testing.T) { got := new(library.Build) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(want) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -129,9 +129,11 @@ func TestBuild_Establish(t *testing.T) { func TestBuild_Establish_NoRepo(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -164,12 +166,14 @@ func TestBuild_Establish_NoBuildParameter(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -210,12 +214,14 @@ func TestBuild_Establish_InvalidBuildParameter(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -256,12 +262,14 @@ func TestBuild_Establish_NoBuild(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) diff --git a/router/middleware/claims/claims_test.go b/router/middleware/claims/claims_test.go index 8934a4afd..da28eb319 100644 --- a/router/middleware/claims/claims_test.go +++ b/router/middleware/claims/claims_test.go @@ -13,15 +13,12 @@ import ( "testing" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/internal/token" - "github.com/golang-jwt/jwt/v5" - "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v5" ) func TestClaims_Retrieve(t *testing.T) { @@ -271,12 +268,14 @@ func TestClaims_Establish_BadToken(t *testing.T) { u.SetHash("abc") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) diff --git a/router/middleware/database_test.go b/router/middleware/database_test.go index a3480a9f5..b0ba77b04 100644 --- a/router/middleware/database_test.go +++ b/router/middleware/database_test.go @@ -12,16 +12,17 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" ) func TestMiddleware_Database(t *testing.T) { // setup types var got database.Interface - want, _ := sqlite.NewTest() - - defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() + want, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer want.Close() // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/org/org_test.go b/router/middleware/org/org_test.go index f52e2aea3..aa64710cc 100644 --- a/router/middleware/org/org_test.go +++ b/router/middleware/org/org_test.go @@ -12,7 +12,6 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/types/library" ) @@ -60,12 +59,14 @@ func TestOrg_Establish(t *testing.T) { got := "" // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -100,9 +101,11 @@ func TestOrg_Establish(t *testing.T) { func TestOrg_Establish_NoOrgParameter(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 755db4a12..34498d21d 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -11,21 +11,19 @@ import ( "testing" "time" + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" - "github.com/golang-jwt/jwt/v5" - - "github.com/gin-gonic/gin" - "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/router/middleware/user" "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" + "github.com/golang-jwt/jwt/v5" ) func TestPerm_MustPlatformAdmin(t *testing.T) { @@ -55,12 +53,14 @@ func TestPerm_MustPlatformAdmin(t *testing.T) { tok, _ := tm.MintToken(mto) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) @@ -141,12 +141,14 @@ func TestPerm_MustPlatformAdmin_NotAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) @@ -266,12 +268,14 @@ func TestPerm_MustWorkerRegisterToken_PlatAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(u) + db.Close() }() _ = db.CreateUser(u) @@ -432,13 +436,15 @@ func TestPerm_MustBuildAccess(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -519,14 +525,16 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -603,13 +611,15 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -685,13 +695,15 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -764,13 +776,15 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -843,13 +857,15 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -922,13 +938,15 @@ func TestPerm_MustAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1018,13 +1036,15 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1114,13 +1134,15 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1210,13 +1232,15 @@ func TestPerm_MustWrite(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1306,13 +1330,15 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1402,13 +1428,15 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1498,13 +1526,15 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1594,13 +1624,15 @@ func TestPerm_MustRead(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1690,13 +1722,15 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1786,13 +1820,15 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from builds") - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateBuild(b) @@ -1868,13 +1904,15 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -1964,13 +2002,15 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -2060,13 +2100,15 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) @@ -2156,13 +2198,15 @@ func TestPerm_MustRead_NotRead(t *testing.T) { context, engine := gin.CreateTestContext(resp) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index ec4e809ed..4618524fd 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -17,7 +17,6 @@ import ( "github.com/go-vela/server/compiler" "github.com/go-vela/server/compiler/native" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/router/middleware/org" @@ -97,13 +96,15 @@ func TestPipeline_Establish(t *testing.T) { got := new(library.Pipeline) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from pipelines;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeletePipeline(want) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -141,8 +142,11 @@ func TestPipeline_Establish(t *testing.T) { func TestPipeline_Establish_NoRepo(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -175,12 +179,14 @@ func TestPipeline_Establish_NoPipelineParameter(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -276,13 +282,15 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { } // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.DeleteUser(u) + db.Close() }() _ = db.CreateRepo(r) diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index d812e1ba7..83051c09c 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -14,7 +14,6 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/types/library" ) @@ -67,12 +66,14 @@ func TestRepo_Establish(t *testing.T) { got := new(library.Repo) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(want) + db.Close() }() _ = db.CreateRepo(want) @@ -108,9 +109,11 @@ func TestRepo_Establish(t *testing.T) { func TestRepo_Establish_NoOrgParameter(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -136,9 +139,11 @@ func TestRepo_Establish_NoOrgParameter(t *testing.T) { func TestRepo_Establish_NoRepoParameter(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -164,9 +169,11 @@ func TestRepo_Establish_NoRepoParameter(t *testing.T) { func TestRepo_Establish_NoRepo(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/secret_test.go b/router/middleware/secret_test.go index 55ee9edcf..9ca21fd24 100644 --- a/router/middleware/secret_test.go +++ b/router/middleware/secret_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/server/secret" "github.com/go-vela/server/secret/native" @@ -51,14 +51,16 @@ func TestMiddleware_Secret(t *testing.T) { func TestMiddleware_Secrets(t *testing.T) { // setup types - d, _ := sqlite.NewTest() - - defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() var got secret.Service want, _ := native.New( - native.WithDatabase(d), + native.WithDatabase(db), ) s := map[string]secret.Service{"native": want} diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index bf38fc5ad..091a3e170 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -10,12 +10,10 @@ import ( "reflect" "testing" - "github.com/go-vela/server/router/middleware/org" - "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/types/library" ) @@ -74,14 +72,16 @@ func TestService_Establish(t *testing.T) { got := new(library.Service) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - db.Sqlite.Exec("delete from services;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.DeleteService(want) + db.Close() }() _ = db.CreateRepo(r) @@ -121,9 +121,11 @@ func TestService_Establish(t *testing.T) { func TestService_Establish_NoRepo(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -159,12 +161,14 @@ func TestService_Establish_NoBuild(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -210,13 +214,15 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -264,13 +270,15 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -318,13 +326,15 @@ func TestService_Establish_NoService(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index b9a0d8e9f..2d9e7ac12 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -10,12 +10,10 @@ import ( "reflect" "testing" - "github.com/go-vela/server/router/middleware/org" - "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/types/library" ) @@ -76,14 +74,16 @@ func TestStep_Establish(t *testing.T) { got := new(library.Step) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - db.Sqlite.Exec("delete from steps;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.DeleteStep(want) + db.Close() }() _ = db.CreateRepo(r) @@ -123,9 +123,11 @@ func TestStep_Establish(t *testing.T) { func TestStep_Establish_NoRepo(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -161,12 +163,14 @@ func TestStep_Establish_NoBuild(t *testing.T) { r.SetVisibility("public") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -212,13 +216,15 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -266,13 +272,15 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) @@ -320,13 +328,15 @@ func TestStep_Establish_NoStep(t *testing.T) { b.SetNumber(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from repos;") - db.Sqlite.Exec("delete from builds;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteBuild(b) + db.DeleteRepo(r) + db.Close() }() _ = db.CreateRepo(r) diff --git a/router/middleware/user/user_test.go b/router/middleware/user/user_test.go index 7561f8a7d..0ea18dfcc 100644 --- a/router/middleware/user/user_test.go +++ b/router/middleware/user/user_test.go @@ -12,18 +12,15 @@ import ( "testing" "time" + "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/server/internal/token" "github.com/go-vela/server/router/middleware/claims" "github.com/go-vela/server/scm" "github.com/go-vela/server/scm/github" - "github.com/golang-jwt/jwt/v5" - "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - - "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v5" ) func TestUser_Retrieve(t *testing.T) { @@ -89,12 +86,14 @@ func TestUser_Establish(t *testing.T) { }) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from users;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteUser(want) + db.Close() }() _ = db.CreateUser(want) @@ -151,9 +150,11 @@ func TestUser_Establish_NoToken(t *testing.T) { UserRefreshTokenDuration: time.Minute * 30, } // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -238,9 +239,11 @@ func TestUser_Establish_NoAuthorizeUser(t *testing.T) { } // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) @@ -285,9 +288,11 @@ func TestUser_Establish_NoUser(t *testing.T) { secret := "superSecret" // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/worker/worker_test.go b/router/middleware/worker/worker_test.go index cad19f15e..1cfeadfc7 100644 --- a/router/middleware/worker/worker_test.go +++ b/router/middleware/worker/worker_test.go @@ -12,7 +12,6 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" "github.com/go-vela/types/library" ) @@ -48,12 +47,14 @@ func TestWorker_Establish(t *testing.T) { got := new(library.Worker) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from workers;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteWorker(want) + db.Close() }() _ = db.CreateWorker(want) @@ -88,9 +89,11 @@ func TestWorker_Establish(t *testing.T) { func TestWorker_Establish_NoWorkerParameter(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // setup context gin.SetMode(gin.TestMode) diff --git a/secret/context_test.go b/secret/context_test.go index e9f2de71c..87f6afe06 100644 --- a/secret/context_test.go +++ b/secret/context_test.go @@ -7,20 +7,21 @@ package secret import ( "testing" - "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/server/secret/native" - "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/secret/native" ) func TestSecret_FromContext(t *testing.T) { // setup types - d, _ := sqlite.NewTest() - - defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() want, err := native.New( - native.WithDatabase(d), + native.WithDatabase(db), ) if err != nil { t.Errorf("New returned err: %v", err) @@ -82,12 +83,14 @@ func TestSecret_FromContext_Empty(t *testing.T) { func TestSecret_ToContext(t *testing.T) { // setup types - d, _ := sqlite.NewTest() - - defer func() { _sql, _ := d.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() want, err := native.New( - native.WithDatabase(d), + native.WithDatabase(db), ) if err != nil { t.Errorf("New returned err: %v", err) diff --git a/secret/native/count_test.go b/secret/native/count_test.go index faed10a88..2d1080029 100644 --- a/secret/native/count_test.go +++ b/secret/native/count_test.go @@ -7,7 +7,7 @@ package native import ( "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -28,12 +28,14 @@ func TestNative_Count(t *testing.T) { want := 1 // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(sec) + db.Close() }() _ = db.CreateSecret(sec) @@ -56,11 +58,13 @@ func TestNative_Count(t *testing.T) { } } -func TestNative_Count_Invalid(t *testing.T) { +func TestNative_Count_Empty(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - _sql, _ := db.Sqlite.DB() - _sql.Close() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // run test s, err := New( @@ -71,8 +75,8 @@ func TestNative_Count_Invalid(t *testing.T) { } got, err := s.Count("repo", "foo", "bar", []string{}) - if err == nil { - t.Errorf("Count should have returned err") + if err != nil { + t.Errorf("Count returned err: %v", err) } if got != 0 { diff --git a/secret/native/create_test.go b/secret/native/create_test.go index 08fd4b18b..328b22ae0 100644 --- a/secret/native/create_test.go +++ b/secret/native/create_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -31,12 +31,14 @@ func TestNative_Create_Org(t *testing.T) { want.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(want) + db.Close() }() // run test @@ -78,12 +80,14 @@ func TestNative_Create_Repo(t *testing.T) { want.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(want) + db.Close() }() // run test @@ -125,12 +129,14 @@ func TestNative_Create_Shared(t *testing.T) { want.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(want) + db.Close() }() // run test @@ -172,12 +178,14 @@ func TestNative_Create_Invalid(t *testing.T) { sec.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(sec) + db.Close() }() // run test diff --git a/secret/native/delete_test.go b/secret/native/delete_test.go index 743288f62..e1c49c133 100644 --- a/secret/native/delete_test.go +++ b/secret/native/delete_test.go @@ -7,7 +7,7 @@ package native import ( "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -28,12 +28,14 @@ func TestNative_Delete(t *testing.T) { sec.SetUpdatedAt(1) // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(sec) + db.Close() }() _ = db.CreateSecret(sec) @@ -54,9 +56,11 @@ func TestNative_Delete(t *testing.T) { func TestNative_Delete_Invalid(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // run test s, err := New( diff --git a/secret/native/driver_test.go b/secret/native/driver_test.go index 81cddaeb4..ec0038df5 100644 --- a/secret/native/driver_test.go +++ b/secret/native/driver_test.go @@ -8,18 +8,17 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/constants" ) func TestNative_Driver(t *testing.T) { // setup types - db, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { t.Errorf("unable to create database service: %v", err) } - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + defer db.Close() want := constants.DriverNative diff --git a/secret/native/get_test.go b/secret/native/get_test.go index 33dc174ce..438ede6a7 100644 --- a/secret/native/get_test.go +++ b/secret/native/get_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -31,12 +31,15 @@ func TestNative_Get(t *testing.T) { want.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(want) + db.Close() }() // run test @@ -61,9 +64,11 @@ func TestNative_Get(t *testing.T) { func TestNative_Get_Invalid(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // run test s, err := New( diff --git a/secret/native/list_test.go b/secret/native/list_test.go index ac9fd1c67..ae0870cd6 100644 --- a/secret/native/list_test.go +++ b/secret/native/list_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -49,12 +49,15 @@ func TestNative_List(t *testing.T) { want := []*library.Secret{sTwo, sOne} // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(sOne) + db.DeleteSecret(sTwo) + db.Close() }() // run test @@ -79,11 +82,13 @@ func TestNative_List(t *testing.T) { } } -func TestNative_List_Invalid(t *testing.T) { +func TestNative_List_Empty(t *testing.T) { // setup database - db, _ := sqlite.NewTest() - _sql, _ := db.Sqlite.DB() - _sql.Close() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // run test s, err := New( @@ -94,11 +99,11 @@ func TestNative_List_Invalid(t *testing.T) { } got, err := s.List("repo", "foo", "bar", 1, 10, []string{}) - if err == nil { - t.Errorf("List should have returned err") + if err != nil { + t.Errorf("List returned err: %v", err) } - if got != nil { - t.Errorf("List is %v, want nil", got) + if len(got) > 0 { + t.Errorf("List is %v, want []", got) } } diff --git a/secret/native/native_test.go b/secret/native/native_test.go index 1b7daaa2f..0a5e3ee49 100644 --- a/secret/native/native_test.go +++ b/secret/native/native_test.go @@ -8,17 +8,15 @@ import ( "testing" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" ) func TestNative_New(t *testing.T) { // setup types - db, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { - t.Errorf("unable to create database service: %v", err) + t.Errorf("unable to create test database engine: %v", err) } - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + defer db.Close() // setup tests tests := []struct { diff --git a/secret/native/opts_test.go b/secret/native/opts_test.go index 1cda40700..0d9d968df 100644 --- a/secret/native/opts_test.go +++ b/secret/native/opts_test.go @@ -9,17 +9,15 @@ import ( "testing" "github.com/go-vela/server/database" - "github.com/go-vela/server/database/sqlite" ) func TestNative_ClientOpt_WithDatabase(t *testing.T) { // setup types - db, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { - t.Errorf("unable to create database service: %v", err) + t.Errorf("unable to create test database engine: %v", err) } - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + defer db.Close() // setup tests tests := []struct { diff --git a/secret/native/update_test.go b/secret/native/update_test.go index 1538fd368..f8c7bf3cb 100644 --- a/secret/native/update_test.go +++ b/secret/native/update_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" "github.com/go-vela/types/library" ) @@ -48,12 +48,14 @@ func TestNative_Update(t *testing.T) { want.SetUpdatedBy("user2") // setup database - db, _ := sqlite.NewTest() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } defer func() { - db.Sqlite.Exec("delete from secrets;") - _sql, _ := db.Sqlite.DB() - _sql.Close() + db.DeleteSecret(original) + db.Close() }() _ = db.CreateSecret(original) @@ -85,9 +87,11 @@ func TestNative_Update_Invalid(t *testing.T) { sec.SetValue("foob") // setup database - db, _ := sqlite.NewTest() - - defer func() { _sql, _ := db.Sqlite.DB(); _sql.Close() }() + db, err := database.NewTest() + if err != nil { + t.Errorf("unable to create test database engine: %v", err) + } + defer db.Close() // run test s, err := New( diff --git a/secret/secret_test.go b/secret/secret_test.go index 03cc6a432..21ab33ee4 100644 --- a/secret/secret_test.go +++ b/secret/secret_test.go @@ -7,17 +7,16 @@ package secret import ( "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" ) func TestSecret_New(t *testing.T) { // setup types - _database, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { - t.Errorf("unable to create database service: %v", err) + t.Errorf("unable to create test database engine: %v", err) } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + defer db.Close() // setup tests tests := []struct { @@ -28,7 +27,7 @@ func TestSecret_New(t *testing.T) { failure: false, setup: &Setup{ Driver: "native", - Database: _database, + Database: db, }, }, { diff --git a/secret/setup_test.go b/secret/setup_test.go index da5c535c9..ef4492681 100644 --- a/secret/setup_test.go +++ b/secret/setup_test.go @@ -8,21 +8,20 @@ import ( "reflect" "testing" - "github.com/go-vela/server/database/sqlite" + "github.com/go-vela/server/database" ) func TestSecret_Setup_Native(t *testing.T) { // setup types - _database, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { - t.Errorf("unable to create database service: %v", err) + t.Errorf("unable to create test database engine: %v", err) } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + defer db.Close() _setup := &Setup{ Driver: "native", - Database: _database, + Database: db, } _native, err := _setup.Native() @@ -126,12 +125,11 @@ func TestSecret_Setup_Vault(t *testing.T) { func TestSecret_Setup_Validate(t *testing.T) { // setup types - _database, err := sqlite.NewTest() + db, err := database.NewTest() if err != nil { - t.Errorf("unable to create database service: %v", err) + t.Errorf("unable to create test database engine: %v", err) } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() + defer db.Close() // setup tests tests := []struct { @@ -142,7 +140,7 @@ func TestSecret_Setup_Validate(t *testing.T) { failure: false, setup: &Setup{ Driver: "native", - Database: _database, + Database: db, }, }, { From f8c795f7aa038582de479fffb0a3b072b0565ed1 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 9 Jun 2023 08:50:07 -0600 Subject: [PATCH 257/298] enhance(log): do not return log object for POST and PUT requests (#879) --- api/log/create_service.go | 6 ++---- api/log/create_step.go | 6 ++---- api/log/update_service.go | 4 ++-- api/log/update_step.go | 4 ++-- api/service/plan.go | 2 +- api/step/plan.go | 2 +- database/log/count_build_test.go | 4 ++-- database/log/count_test.go | 4 ++-- database/log/create.go | 15 ++++++++------- database/log/create_test.go | 2 +- database/log/delete_test.go | 2 +- database/log/get_service_test.go | 2 +- database/log/get_step_test.go | 2 +- database/log/get_test.go | 2 +- database/log/interface.go | 4 ++-- database/log/list_build_test.go | 4 ++-- database/log/list_test.go | 4 ++-- database/log/update.go | 15 ++++++++------- database/log/update_test.go | 6 +++--- mock/server/log.go | 28 ++++------------------------ 20 files changed, 48 insertions(+), 70 deletions(-) diff --git a/api/log/create_service.go b/api/log/create_service.go index c6014f09b..bf8cd4ec1 100644 --- a/api/log/create_service.go +++ b/api/log/create_service.go @@ -61,8 +61,6 @@ import ( // responses: // '201': // description: Successfully created the service logs -// schema: -// "$ref": "#/definitions/Log" // '400': // description: Unable to create the service logs // schema: @@ -113,7 +111,7 @@ func CreateServiceLog(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the logs - l, err := database.FromContext(c).CreateLog(input) + err = database.FromContext(c).CreateLog(input) if err != nil { retErr := fmt.Errorf("unable to create logs for service %s: %w", entry, err) @@ -122,5 +120,5 @@ func CreateServiceLog(c *gin.Context) { return } - c.JSON(http.StatusCreated, l) + c.JSON(http.StatusCreated, nil) } diff --git a/api/log/create_step.go b/api/log/create_step.go index 5bc83c646..d2abed7a9 100644 --- a/api/log/create_step.go +++ b/api/log/create_step.go @@ -61,8 +61,6 @@ import ( // responses: // '201': // description: Successfully created the logs for step -// schema: -// "$ref": "#/definitions/Log" // '400': // description: Unable to create the logs for a step // schema: @@ -113,7 +111,7 @@ func CreateStepLog(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the logs - l, err := database.FromContext(c).CreateLog(input) + err = database.FromContext(c).CreateLog(input) if err != nil { retErr := fmt.Errorf("unable to create logs for step %s: %w", entry, err) @@ -122,5 +120,5 @@ func CreateStepLog(c *gin.Context) { return } - c.JSON(http.StatusCreated, l) + c.JSON(http.StatusCreated, nil) } diff --git a/api/log/update_service.go b/api/log/update_service.go index 82b56f13b..92d96e1f1 100644 --- a/api/log/update_service.go +++ b/api/log/update_service.go @@ -124,7 +124,7 @@ func UpdateServiceLog(c *gin.Context) { } // send API call to update the log - l, err = database.FromContext(c).UpdateLog(l) + err = database.FromContext(c).UpdateLog(l) if err != nil { retErr := fmt.Errorf("unable to update logs for service %s: %w", entry, err) @@ -133,5 +133,5 @@ func UpdateServiceLog(c *gin.Context) { return } - c.JSON(http.StatusOK, l) + c.JSON(http.StatusOK, nil) } diff --git a/api/log/update_step.go b/api/log/update_step.go index dcb4a99d1..14a642d57 100644 --- a/api/log/update_step.go +++ b/api/log/update_step.go @@ -124,7 +124,7 @@ func UpdateStepLog(c *gin.Context) { } // send API call to update the log - l, err = database.FromContext(c).UpdateLog(l) + err = database.FromContext(c).UpdateLog(l) if err != nil { retErr := fmt.Errorf("unable to update logs for step %s: %w", entry, err) @@ -133,5 +133,5 @@ func UpdateStepLog(c *gin.Context) { return } - c.JSON(http.StatusOK, l) + c.JSON(http.StatusOK, nil) } diff --git a/api/service/plan.go b/api/service/plan.go index fecd03f24..4912f38d1 100644 --- a/api/service/plan.go +++ b/api/service/plan.go @@ -61,7 +61,7 @@ func PlanServices(database database.Interface, p *pipeline.Build, b *library.Bui l.SetData([]byte{}) // send API call to create the service logs - _, err = database.CreateLog(l) + err = database.CreateLog(l) if err != nil { return services, fmt.Errorf("unable to create service logs for service %s: %w", s.GetName(), err) } diff --git a/api/step/plan.go b/api/step/plan.go index c74a52614..b072cf4f7 100644 --- a/api/step/plan.go +++ b/api/step/plan.go @@ -88,7 +88,7 @@ func planStep(database database.Interface, b *library.Build, c *pipeline.Contain l.SetData([]byte{}) // send API call to create the step logs - _, err = database.CreateLog(l) + err = database.CreateLog(l) if err != nil { return nil, fmt.Errorf("unable to create logs for step %s: %w", s.GetName(), err) } diff --git a/database/log/count_build_test.go b/database/log/count_build_test.go index e168f80ec..d462eedf0 100644 --- a/database/log/count_build_test.go +++ b/database/log/count_build_test.go @@ -43,12 +43,12 @@ func TestLog_Engine_CountLogsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_service) + err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - _, err = _sqlite.CreateLog(_step) + err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/count_test.go b/database/log/count_test.go index 2af820203..99e75a767 100644 --- a/database/log/count_test.go +++ b/database/log/count_test.go @@ -37,12 +37,12 @@ func TestLog_Engine_CountLogs(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_service) + err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - _, err = _sqlite.CreateLog(_step) + err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/create.go b/database/log/create.go index b1767c01e..978da9a1f 100644 --- a/database/log/create.go +++ b/database/log/create.go @@ -14,7 +14,7 @@ import ( ) // CreateLog creates a new log in the database. -func (e *engine) CreateLog(l *library.Log) (*library.Log, error) { +func (e *engine) CreateLog(l *library.Log) error { // check what the log entry is for switch { case l.GetServiceID() > 0: @@ -33,7 +33,7 @@ func (e *engine) CreateLog(l *library.Log) (*library.Log, error) { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate err := log.Validate() if err != nil { - return nil, err + return err } // compress log data for the resource @@ -43,14 +43,15 @@ func (e *engine) CreateLog(l *library.Log) (*library.Log, error) { if err != nil { switch { case l.GetServiceID() > 0: - return nil, fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) case l.GetStepID() > 0: - return nil, fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) } } // send query to the database - result := e.client.Table(constants.TableLog).Create(log) - - return log.ToLibrary(), result.Error + return e.client. + Table(constants.TableLog). + Create(log). + Error } diff --git a/database/log/create_test.go b/database/log/create_test.go index 68e0a2d40..1574e88a8 100644 --- a/database/log/create_test.go +++ b/database/log/create_test.go @@ -73,7 +73,7 @@ VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`). for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, log := range test.logs { - _, err := test.database.CreateLog(log) + err := test.database.CreateLog(log) if test.failure { if err == nil { diff --git a/database/log/delete_test.go b/database/log/delete_test.go index dbfdbca00..15329a0af 100644 --- a/database/log/delete_test.go +++ b/database/log/delete_test.go @@ -29,7 +29,7 @@ func TestLog_Engine_DeleteLog(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_log) + err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_service_test.go b/database/log/get_service_test.go index 3ff82d6c8..26f42813c 100644 --- a/database/log/get_service_test.go +++ b/database/log/get_service_test.go @@ -42,7 +42,7 @@ func TestLog_Engine_GetLogForService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_log) + err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_step_test.go b/database/log/get_step_test.go index d092e30a9..39f019039 100644 --- a/database/log/get_step_test.go +++ b/database/log/get_step_test.go @@ -42,7 +42,7 @@ func TestLog_Engine_GetLogForStep(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_log) + err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/get_test.go b/database/log/get_test.go index 7127d3165..31325e3ac 100644 --- a/database/log/get_test.go +++ b/database/log/get_test.go @@ -35,7 +35,7 @@ func TestLog_Engine_GetLog(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_log) + err := _sqlite.CreateLog(_log) if err != nil { t.Errorf("unable to create test log for sqlite: %v", err) } diff --git a/database/log/interface.go b/database/log/interface.go index 5b71be967..8c72a5098 100644 --- a/database/log/interface.go +++ b/database/log/interface.go @@ -31,7 +31,7 @@ type LogInterface interface { // CountLogsForBuild defines a function that gets the count of logs by build ID. CountLogsForBuild(*library.Build) (int64, error) // CreateLog defines a function that creates a new log. - CreateLog(*library.Log) (*library.Log, error) + CreateLog(*library.Log) error // DeleteLog defines a function that deletes an existing log. DeleteLog(*library.Log) error // GetLog defines a function that gets a log by ID. @@ -45,5 +45,5 @@ type LogInterface interface { // ListLogsForBuild defines a function that gets a list of logs by build ID. ListLogsForBuild(*library.Build, int, int) ([]*library.Log, int64, error) // UpdateLog defines a function that updates an existing log. - UpdateLog(*library.Log) (*library.Log, error) + UpdateLog(*library.Log) error } diff --git a/database/log/list_build_test.go b/database/log/list_build_test.go index 7ffcc0f46..fb08236e9 100644 --- a/database/log/list_build_test.go +++ b/database/log/list_build_test.go @@ -54,12 +54,12 @@ func TestLog_Engine_ListLogsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_service) + err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - _, err = _sqlite.CreateLog(_step) + err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/list_test.go b/database/log/list_test.go index 343af9d5a..0cf420255 100644 --- a/database/log/list_test.go +++ b/database/log/list_test.go @@ -48,12 +48,12 @@ func TestLog_Engine_ListLogs(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_service) + err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - _, err = _sqlite.CreateLog(_step) + err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } diff --git a/database/log/update.go b/database/log/update.go index 62ba865bc..fb7165004 100644 --- a/database/log/update.go +++ b/database/log/update.go @@ -14,7 +14,7 @@ import ( ) // UpdateLog updates an existing log in the database. -func (e *engine) UpdateLog(l *library.Log) (*library.Log, error) { +func (e *engine) UpdateLog(l *library.Log) error { // check what the log entry is for switch { case l.GetServiceID() > 0: @@ -33,7 +33,7 @@ func (e *engine) UpdateLog(l *library.Log) (*library.Log, error) { // https://pkg.go.dev/github.com/go-vela/types/database#Log.Validate err := log.Validate() if err != nil { - return nil, err + return err } // compress log data for the resource @@ -43,14 +43,15 @@ func (e *engine) UpdateLog(l *library.Log) (*library.Log, error) { if err != nil { switch { case l.GetServiceID() > 0: - return nil, fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) + return fmt.Errorf("unable to compress log for service %d for build %d: %w", l.GetServiceID(), l.GetBuildID(), err) case l.GetStepID() > 0: - return nil, fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) + return fmt.Errorf("unable to compress log for step %d for build %d: %w", l.GetStepID(), l.GetBuildID(), err) } } // send query to the database - result := e.client.Table(constants.TableLog).Save(log) - - return log.ToLibrary(), result.Error + return e.client. + Table(constants.TableLog). + Save(log). + Error } diff --git a/database/log/update_test.go b/database/log/update_test.go index 9659cfb65..0b4e8e127 100644 --- a/database/log/update_test.go +++ b/database/log/update_test.go @@ -47,12 +47,12 @@ WHERE "id" = $6`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateLog(_service) + err := _sqlite.CreateLog(_service) if err != nil { t.Errorf("unable to create test service log for sqlite: %v", err) } - _, err = _sqlite.CreateLog(_step) + err = _sqlite.CreateLog(_step) if err != nil { t.Errorf("unable to create test step log for sqlite: %v", err) } @@ -82,7 +82,7 @@ WHERE "id" = $6`). for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, log := range test.logs { - _, err = test.database.UpdateLog(log) + err = test.database.UpdateLog(log) if test.failure { if err == nil { diff --git a/mock/server/log.go b/mock/server/log.go index 8a101c4d2..3becfff38 100644 --- a/mock/server/log.go +++ b/mock/server/log.go @@ -51,12 +51,7 @@ func getServiceLog(c *gin.Context) { // addServiceLog returns mock JSON for a http GET. func addServiceLog(c *gin.Context) { - data := []byte(LogResp) - - var body library.Log - _ = json.Unmarshal(data, &body) - - c.JSON(http.StatusCreated, body) + c.JSON(http.StatusCreated, nil) } // updateServiceLog has a param :service returns mock JSON for a http PUT. @@ -73,12 +68,7 @@ func updateServiceLog(c *gin.Context) { return } - data := []byte(LogResp) - - var body library.Log - _ = json.Unmarshal(data, &body) - - c.JSON(http.StatusOK, body) + c.JSON(http.StatusOK, nil) } // removeServiceLog has a param :service returns mock JSON for a http DELETE. @@ -122,12 +112,7 @@ func getStepLog(c *gin.Context) { // addStepLog returns mock JSON for a http GET. func addStepLog(c *gin.Context) { - data := []byte(LogResp) - - var body library.Log - _ = json.Unmarshal(data, &body) - - c.JSON(http.StatusCreated, body) + c.JSON(http.StatusCreated, nil) } // updateStepLog has a param :step returns mock JSON for a http PUT. @@ -144,12 +129,7 @@ func updateStepLog(c *gin.Context) { return } - data := []byte(LogResp) - - var body library.Log - _ = json.Unmarshal(data, &body) - - c.JSON(http.StatusOK, body) + c.JSON(http.StatusOK, nil) } // removeStepLog has a param :step returns mock JSON for a http DELETE. From e2e86a745c36cdb2e516a75d5eb1b9929894c6ea Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 9 Jun 2023 10:16:34 -0500 Subject: [PATCH 258/298] enhance(clone): upgrade target/vela-git to v0.8.0 (#876) --- cmd/vela-server/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index f9b160a8f..19463fe0b 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -84,7 +84,7 @@ func main() { EnvVars: []string{"VELA_CLONE_IMAGE"}, Name: "clone-image", Usage: "the clone image to use for the injected clone step", - Value: "target/vela-git:v0.7.0@sha256:c2e8794556d6debceeaa2c82ff3cc9e8e6ed045b723419e3ff050409f25cc258", + Value: "target/vela-git:v0.8.0@sha256:02de004ae9dbf184c70039cb9ce431c31d6e7580eb9e6ec64a97ebf108aa65cb", }, &cli.StringSliceFlag{ EnvVars: []string{"VELA_REPO_ALLOWLIST"}, From 0410f86a295d5b8bc2d79dd14ed0947bafcb5dae Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Fri, 9 Jun 2023 16:20:11 -0500 Subject: [PATCH 259/298] chore(database): remove unused packages (#880) * refactor(internal): sqlite.NewTest() -> database.NewTest() * refactor(router): sqlite.NewTest() -> database.NewTest() * refactor(secret): sqlite.NewTest() -> database.NewTest() * chore(database): add Close() to Interface{} * chore(database): remove unused postgres package * chore(database): remove unused sqlite package --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> --- database/postgres/doc.go | 11 - database/postgres/driver.go | 12 - database/postgres/driver_test.go | 32 --- database/postgres/opts.go | 107 -------- database/postgres/opts_test.go | 287 -------------------- database/postgres/ping.go | 45 ---- database/postgres/ping_test.go | 65 ----- database/postgres/postgres.go | 411 ----------------------------- database/postgres/postgres_test.go | 240 ----------------- database/sqlite/doc.go | 11 - database/sqlite/driver.go | 12 - database/sqlite/driver_test.go | 32 --- database/sqlite/opts.go | 107 -------- database/sqlite/opts_test.go | 287 -------------------- database/sqlite/ping.go | 45 ---- database/sqlite/ping_test.go | 62 ----- database/sqlite/sqlite.go | 367 -------------------------- database/sqlite/sqlite_test.go | 146 ---------- 18 files changed, 2279 deletions(-) delete mode 100644 database/postgres/doc.go delete mode 100644 database/postgres/driver.go delete mode 100644 database/postgres/driver_test.go delete mode 100644 database/postgres/opts.go delete mode 100644 database/postgres/opts_test.go delete mode 100644 database/postgres/ping.go delete mode 100644 database/postgres/ping_test.go delete mode 100644 database/postgres/postgres.go delete mode 100644 database/postgres/postgres_test.go delete mode 100644 database/sqlite/doc.go delete mode 100644 database/sqlite/driver.go delete mode 100644 database/sqlite/driver_test.go delete mode 100644 database/sqlite/opts.go delete mode 100644 database/sqlite/opts_test.go delete mode 100644 database/sqlite/ping.go delete mode 100644 database/sqlite/ping_test.go delete mode 100644 database/sqlite/sqlite.go delete mode 100644 database/sqlite/sqlite_test.go diff --git a/database/postgres/doc.go b/database/postgres/doc.go deleted file mode 100644 index 0fbbbd274..000000000 --- a/database/postgres/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package postgres provides the ability for Vela to -// integrate with Postgres as a SQL backend. -// -// Usage: -// -// import "github.com/go-vela/server/database/postgres" -package postgres diff --git a/database/postgres/driver.go b/database/postgres/driver.go deleted file mode 100644 index 2a61cae42..000000000 --- a/database/postgres/driver.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import "github.com/go-vela/types/constants" - -// Driver outputs the configured database driver. -func (c *client) Driver() string { - return constants.DriverPostgres -} diff --git a/database/postgres/driver_test.go b/database/postgres/driver_test.go deleted file mode 100644 index e54d0b0f5..000000000 --- a/database/postgres/driver_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/constants" -) - -func TestPostgres_Client_Driver(t *testing.T) { - // setup types - want := constants.DriverPostgres - - // setup the test database client - _database, _, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // run test - got := _database.Driver() - - if !reflect.DeepEqual(got, want) { - t.Errorf("Driver is %v, want %v", got, want) - } -} diff --git a/database/postgres/opts.go b/database/postgres/opts.go deleted file mode 100644 index 0564f4c0d..000000000 --- a/database/postgres/opts.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "fmt" - "time" -) - -// ClientOpt represents a configuration option to initialize the database client for Postgres. -type ClientOpt func(*client) error - -// WithAddress sets the address in the database client for Postgres. -func WithAddress(address string) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring address in postgres database client") - - // check if the Postgres address provided is empty - if len(address) == 0 { - return fmt.Errorf("no Postgres address provided") - } - - // set the address in the postgres client - c.config.Address = address - - return nil - } -} - -// WithCompressionLevel sets the compression level in the database client for Postgres. -func WithCompressionLevel(level int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring compression level in postgres database client") - - // set the compression level in the postgres client - c.config.CompressionLevel = level - - return nil - } -} - -// WithConnectionLife sets the connection duration in the database client for Postgres. -func WithConnectionLife(duration time.Duration) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring connection duration in postgres database client") - - // set the connection duration in the postgres client - c.config.ConnectionLife = duration - - return nil - } -} - -// WithConnectionIdle sets the maximum idle connections in the database client for Postgres. -func WithConnectionIdle(idle int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring maximum idle connections in postgres database client") - - // set the maximum idle connections in the postgres client - c.config.ConnectionIdle = idle - - return nil - } -} - -// WithConnectionOpen sets the maximum open connections in the database client for Postgres. -func WithConnectionOpen(open int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring maximum open connections in postgres database client") - - // set the maximum open connections in the postgres client - c.config.ConnectionOpen = open - - return nil - } -} - -// WithEncryptionKey sets the encryption key in the database client for Postgres. -func WithEncryptionKey(key string) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring encryption key in postgres database client") - - // check if the Postgres encryption key provided is empty - if len(key) == 0 { - return fmt.Errorf("no Postgres encryption key provided") - } - - // set the encryption key in the postgres client - c.config.EncryptionKey = key - - return nil - } -} - -// WithSkipCreation sets the skip creation logic in the database client for Postgres. -func WithSkipCreation(skipCreation bool) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring skip creating objects in postgres database client") - - // set to skip creating tables and indexes in the postgres client - c.config.SkipCreation = skipCreation - - return nil - } -} diff --git a/database/postgres/opts_test.go b/database/postgres/opts_test.go deleted file mode 100644 index cb3e687da..000000000 --- a/database/postgres/opts_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "reflect" - "testing" - "time" - - "github.com/sirupsen/logrus" -) - -func TestPostgres_ClientOpt_WithAddress(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - failure bool - address string - want string - }{ - { - failure: false, - address: "postgres://foo:bar@localhost:5432/vela", - want: "postgres://foo:bar@localhost:5432/vela", - }, - { - failure: true, - address: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - err := WithAddress(test.address)(c) - - if test.failure { - if err == nil { - t.Errorf("WithAddress should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("WithAddress returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.Address, test.want) { - t.Errorf("WithAddress is %v, want %v", c.config.Address, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithCompressionLevel(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - level int - want int - }{ - { - level: 3, - want: 3, - }, - { - level: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithCompressionLevel(test.level)(c) - - if err != nil { - t.Errorf("WithCompressionLevel returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.CompressionLevel, test.want) { - t.Errorf("WithCompressionLevel is %v, want %v", c.config.CompressionLevel, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithConnectionLife(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - duration time.Duration - want time.Duration - }{ - { - duration: 10 * time.Second, - want: 10 * time.Second, - }, - { - duration: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionLife(test.duration)(c) - - if err != nil { - t.Errorf("WithConnectionLife returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionLife, test.want) { - t.Errorf("WithConnectionLife is %v, want %v", c.config.ConnectionLife, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithConnectionIdle(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - idle int - want int - }{ - { - idle: 5, - want: 5, - }, - { - idle: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionIdle(test.idle)(c) - - if err != nil { - t.Errorf("WithConnectionIdle returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionIdle, test.want) { - t.Errorf("WithConnectionIdle is %v, want %v", c.config.ConnectionIdle, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithConnectionOpen(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - open int - want int - }{ - { - open: 10, - want: 10, - }, - { - open: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionOpen(test.open)(c) - - if err != nil { - t.Errorf("WithConnectionOpen returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionOpen, test.want) { - t.Errorf("WithConnectionOpen is %v, want %v", c.config.ConnectionOpen, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithEncryptionKey(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - failure bool - key string - want string - }{ - { - failure: false, - key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - }, - { - failure: true, - key: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - err := WithEncryptionKey(test.key)(c) - - if test.failure { - if err == nil { - t.Errorf("WithEncryptionKey should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("WithEncryptionKey returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.EncryptionKey, test.want) { - t.Errorf("WithEncryptionKey is %v, want %v", c.config.EncryptionKey, test.want) - } - } -} - -func TestPostgres_ClientOpt_WithSkipCreation(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - skipCreation bool - want bool - }{ - { - skipCreation: true, - want: true, - }, - { - skipCreation: false, - want: false, - }, - } - - // run tests - for _, test := range tests { - err := WithSkipCreation(test.skipCreation)(c) - - if err != nil { - t.Errorf("WithSkipCreation returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.SkipCreation, test.want) { - t.Errorf("WithSkipCreation is %v, want %v", c.config.SkipCreation, test.want) - } - } -} diff --git a/database/postgres/ping.go b/database/postgres/ping.go deleted file mode 100644 index acdc29782..000000000 --- a/database/postgres/ping.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "fmt" - "time" -) - -// Ping sends a "ping" request with backoff to the database. -func (c *client) Ping() error { - c.Logger.Trace("sending ping requests to the database") - - // create a loop to attempt ping requests 5 times - for i := 0; i < 5; i++ { - // capture database/sql database from gorm database - // - // https://pkg.go.dev/gorm.io/gorm#DB.DB - _sql, err := c.Postgres.DB() - if err != nil { - return err - } - - // send ping request to database - // - // https://pkg.go.dev/database/sql#DB.Ping - err = _sql.Ping() - if err != nil { - c.Logger.Debugf("unable to ping database - retrying in %v", time.Duration(i)*time.Second) - - // sleep for loop iteration in seconds - time.Sleep(time.Duration(i) * time.Second) - - // continue to next iteration of the loop - continue - } - - // able to ping database so return with no error - return nil - } - - return fmt.Errorf("unable to successfully ping database") -} diff --git a/database/postgres/ping_test.go b/database/postgres/ping_test.go deleted file mode 100644 index 563f41016..000000000 --- a/database/postgres/ping_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "testing" -) - -func TestPostgres_Client_Ping(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the ping - _mock.ExpectPing() - - // setup the closed test database client - _closed, _, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - // capture the closed test sql database - _sql, _ := _closed.Postgres.DB() - // close the test sql database to simulate failures to ping - _sql.Close() - - // setup tests - tests := []struct { - failure bool - database *client - }{ - { - failure: false, - database: _database, - }, - { - failure: true, - database: _closed, - }, - } - - // run tests - for _, test := range tests { - err = test.database.Ping() - - if test.failure { - if err == nil { - t.Errorf("Ping should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Ping returned err: %v", err) - } - } -} diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go deleted file mode 100644 index fea05037d..000000000 --- a/database/postgres/postgres.go +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "time" - - "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/server/database/build" - "github.com/go-vela/server/database/hook" - "github.com/go-vela/server/database/log" - "github.com/go-vela/server/database/pipeline" - "github.com/go-vela/server/database/repo" - "github.com/go-vela/server/database/schedule" - "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/user" - "github.com/go-vela/server/database/worker" - "github.com/sirupsen/logrus" - - "gorm.io/driver/postgres" - "gorm.io/gorm" -) - -type ( - config struct { - // specifies the address to use for the Postgres client - Address string - // specifies the level of compression to use for the Postgres client - CompressionLevel int - // specifies the connection duration to use for the Postgres client - ConnectionLife time.Duration - // specifies the maximum idle connections for the Postgres client - ConnectionIdle int - // specifies the maximum open connections for the Postgres client - ConnectionOpen int - // specifies the encryption key to use for the Postgres client - EncryptionKey string - // specifies to skip creating tables and indexes for the Postgres client - SkipCreation bool - } - - client struct { - config *config - // https://pkg.go.dev/gorm.io/gorm#DB - Postgres *gorm.DB - // https://pkg.go.dev/github.com/sirupsen/logrus#Entry - Logger *logrus.Entry - // https://pkg.go.dev/github.com/go-vela/server/database/build#BuildInterface - build.BuildInterface - // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface - hook.HookInterface - // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface - log.LogInterface - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineInterface - pipeline.PipelineInterface - // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface - repo.RepoInterface - // https://pkg.go.dev/github.com/go-vela/server/database/schedule#ScheduleInterface - schedule.ScheduleInterface - // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface - secret.SecretInterface - // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface - service.ServiceInterface - // https://pkg.go.dev/github.com/go-vela/server/database/step#StepInterface - step.StepInterface - // https://pkg.go.dev/github.com/go-vela/server/database/user#UserInterface - user.UserInterface - // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerInterface - worker.WorkerInterface - } -) - -// New returns a Database implementation that integrates with a Postgres instance. -// -//nolint:revive // ignore returning unexported client -func New(opts ...ClientOpt) (*client, error) { - // create new Postgres client - c := new(client) - - // create new fields - c.config = new(config) - c.Postgres = new(gorm.DB) - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#StandardLogger - logger := logrus.StandardLogger() - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) - - // apply all provided configuration options - for _, opt := range opts { - err := opt(c) - if err != nil { - return nil, err - } - } - - // create the new Postgres database client - // - // https://pkg.go.dev/gorm.io/gorm#Open - _postgres, err := gorm.Open(postgres.Open(c.config.Address), &gorm.Config{}) - if err != nil { - return nil, err - } - - // set the Postgres database client in the Postgres client - c.Postgres = _postgres - - // setup database with proper configuration - err = setupDatabase(c) - if err != nil { - return nil, err - } - - // create the services for the database - err = createServices(c) - if err != nil { - return nil, err - } - - return c, nil -} - -// NewTest returns a Database implementation that integrates with a fake Postgres instance. -// -// This function is intended for running tests only. -// -//nolint:revive // ignore returning unexported client -func NewTest() (*client, sqlmock.Sqlmock, error) { - // create new Postgres client - c := new(client) - - // create new fields - c.config = &config{ - CompressionLevel: 3, - ConnectionLife: 30 * time.Minute, - ConnectionIdle: 2, - ConnectionOpen: 0, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - c.Postgres = new(gorm.DB) - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#StandardLogger - logger := logrus.StandardLogger() - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) - - // create the new mock sql database - // - // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New - _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) - if err != nil { - return nil, nil, err - } - - // ensure the mock expects the build queries - _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the hook queries - _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the log queries - _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the pipeline queries - _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the repo queries - _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the schedule queries - _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the secret queries - _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the service queries - _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the step queries - _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the user queries - _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the worker queries - _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - - // create the new mock Postgres database client - // - // https://pkg.go.dev/gorm.io/gorm#Open - c.Postgres, err = gorm.Open( - postgres.New(postgres.Config{Conn: _sql}), - &gorm.Config{SkipDefaultTransaction: true}, - ) - if err != nil { - return nil, nil, err - } - - // setup database with proper configuration - err = createServices(c) - if err != nil { - return nil, nil, err - } - - return c, _mock, nil -} - -// setupDatabase is a helper function to setup -// the database with the proper configuration. -func setupDatabase(c *client) error { - // capture database/sql database from gorm database - // - // https://pkg.go.dev/gorm.io/gorm#DB.DB - _sql, err := c.Postgres.DB() - if err != nil { - return err - } - - // set the maximum amount of time a connection may be reused - // - // https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime - _sql.SetConnMaxLifetime(c.config.ConnectionLife) - - // set the maximum number of connections in the idle connection pool - // - // https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns - _sql.SetMaxIdleConns(c.config.ConnectionIdle) - - // set the maximum number of open connections to the database - // - // https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns - _sql.SetMaxOpenConns(c.config.ConnectionOpen) - - // verify connection to the database - err = c.Ping() - if err != nil { - return err - } - - // check if we should skip creating database objects - if c.config.SkipCreation { - c.Logger.Warning("skipping creation of data tables and indexes in the postgres database") - - return nil - } - - return nil -} - -// createServices is a helper function to create the database services. -func createServices(c *client) error { - var err error - - // create the database agnostic engine for builds - // - // https://pkg.go.dev/github.com/go-vela/server/database/build#New - c.BuildInterface, err = build.New( - build.WithClient(c.Postgres), - build.WithLogger(c.Logger), - build.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for hooks - // - // https://pkg.go.dev/github.com/go-vela/server/database/hook#New - c.HookInterface, err = hook.New( - hook.WithClient(c.Postgres), - hook.WithLogger(c.Logger), - hook.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for logs - // - // https://pkg.go.dev/github.com/go-vela/server/database/log#New - c.LogInterface, err = log.New( - log.WithClient(c.Postgres), - log.WithCompressionLevel(c.config.CompressionLevel), - log.WithLogger(c.Logger), - log.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for pipelines - // - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New - c.PipelineInterface, err = pipeline.New( - pipeline.WithClient(c.Postgres), - pipeline.WithCompressionLevel(c.config.CompressionLevel), - pipeline.WithLogger(c.Logger), - pipeline.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for repos - // - // https://pkg.go.dev/github.com/go-vela/server/database/repo#New - c.RepoInterface, err = repo.New( - repo.WithClient(c.Postgres), - repo.WithEncryptionKey(c.config.EncryptionKey), - repo.WithLogger(c.Logger), - repo.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for schedules - // - // https://pkg.go.dev/github.com/go-vela/server/database/schedule#New - c.ScheduleInterface, err = schedule.New( - schedule.WithClient(c.Postgres), - schedule.WithLogger(c.Logger), - schedule.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for secrets - // - // https://pkg.go.dev/github.com/go-vela/server/database/secret#New - c.SecretInterface, err = secret.New( - secret.WithClient(c.Postgres), - secret.WithEncryptionKey(c.config.EncryptionKey), - secret.WithLogger(c.Logger), - secret.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for services - // - // https://pkg.go.dev/github.com/go-vela/server/database/service#New - c.ServiceInterface, err = service.New( - service.WithClient(c.Postgres), - service.WithLogger(c.Logger), - service.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for steps - // - // https://pkg.go.dev/github.com/go-vela/server/database/step#New - c.StepInterface, err = step.New( - step.WithClient(c.Postgres), - step.WithLogger(c.Logger), - step.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for users - // - // https://pkg.go.dev/github.com/go-vela/server/database/user#New - c.UserInterface, err = user.New( - user.WithClient(c.Postgres), - user.WithEncryptionKey(c.config.EncryptionKey), - user.WithLogger(c.Logger), - user.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for workers - // - // https://pkg.go.dev/github.com/go-vela/server/database/worker#New - c.WorkerInterface, err = worker.New( - worker.WithClient(c.Postgres), - worker.WithLogger(c.Logger), - worker.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - return nil -} diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go deleted file mode 100644 index a8f74d1ff..000000000 --- a/database/postgres/postgres_test.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package postgres - -import ( - "testing" - "time" - - "github.com/go-vela/server/database/schedule" - - "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/server/database/build" - "github.com/go-vela/server/database/hook" - "github.com/go-vela/server/database/log" - "github.com/go-vela/server/database/pipeline" - "github.com/go-vela/server/database/repo" - "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/user" - "github.com/go-vela/server/database/worker" -) - -func TestPostgres_New(t *testing.T) { - // setup tests - tests := []struct { - failure bool - address string - want string - }{ - { - failure: true, - address: "postgres://foo:bar@localhost:5432/vela", - want: "postgres://foo:bar@localhost:5432/vela", - }, - { - failure: true, - address: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - _, err := New( - WithAddress(test.address), - WithCompressionLevel(3), - WithConnectionLife(10*time.Second), - WithConnectionIdle(5), - WithConnectionOpen(20), - WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), - WithSkipCreation(false), - ) - - if test.failure { - if err == nil { - t.Errorf("New should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("New returned err: %v", err) - } - } -} - -func TestPostgres_setupDatabase(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the ping - _mock.ExpectPing() - - // ensure the mock expects the build queries - _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the hook queries - _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the log queries - _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the pipeline queries - _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the repo queries - _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the schedule queries - _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the secret queries - _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the service queries - _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the step queries - _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the user queries - _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the worker queries - _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - - // setup the skip test database client - _skipDatabase, _skipMock, err := NewTest() - if err != nil { - t.Errorf("unable to create new skip postgres test database: %v", err) - } - - defer func() { _sql, _ := _skipDatabase.Postgres.DB(); _sql.Close() }() - - err = WithSkipCreation(true)(_skipDatabase) - if err != nil { - t.Errorf("unable to set SkipCreation for postgres test database: %v", err) - } - - // ensure the mock expects the ping - _skipMock.ExpectPing() - - tests := []struct { - failure bool - database *client - }{ - { - failure: false, - database: _database, - }, - { - failure: false, - database: _skipDatabase, - }, - } - - // run tests - for _, test := range tests { - err := setupDatabase(test.database) - - if test.failure { - if err == nil { - t.Errorf("setupDatabase should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("setupDatabase returned err: %v", err) - } - } -} - -func TestPostgres_createServices(t *testing.T) { - // setup types - // setup the test database client - _database, _mock, err := NewTest() - if err != nil { - t.Errorf("unable to create new postgres test database: %v", err) - } - - defer func() { _sql, _ := _database.Postgres.DB(); _sql.Close() }() - - // ensure the mock expects the build queries - _mock.ExpectExec(build.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateCreatedIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the hook queries - _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the log queries - _mock.ExpectExec(log.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(log.CreateBuildIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the pipeline queries - _mock.ExpectExec(pipeline.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(pipeline.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the repo queries - _mock.ExpectExec(repo.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(repo.CreateOrgNameIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the schedule queries - _mock.ExpectExec(schedule.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(schedule.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the secret queries - _mock.ExpectExec(secret.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgRepo).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrgTeam).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(secret.CreateTypeOrg).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the service queries - _mock.ExpectExec(service.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the step queries - _mock.ExpectExec(step.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the user queries - _mock.ExpectExec(user.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(user.CreateUserRefreshIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - // ensure the mock expects the worker queries - _mock.ExpectExec(worker.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) - _mock.ExpectExec(worker.CreateHostnameAddressIndex).WillReturnResult(sqlmock.NewResult(1, 1)) - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createServices(_database) - - if test.failure { - if err == nil { - t.Errorf("createServices should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createServices returned err: %v", err) - } - } -} diff --git a/database/sqlite/doc.go b/database/sqlite/doc.go deleted file mode 100644 index a27ddb46f..000000000 --- a/database/sqlite/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -// Package sqlite provides the ability for Vela to -// integrate with Sqlite as a SQL backend. -// -// Usage: -// -// import "github.com/go-vela/server/database/sqlite" -package sqlite diff --git a/database/sqlite/driver.go b/database/sqlite/driver.go deleted file mode 100644 index 208853dd5..000000000 --- a/database/sqlite/driver.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import "github.com/go-vela/types/constants" - -// Driver outputs the configured database driver. -func (c *client) Driver() string { - return constants.DriverSqlite -} diff --git a/database/sqlite/driver_test.go b/database/sqlite/driver_test.go deleted file mode 100644 index 83a2aae29..000000000 --- a/database/sqlite/driver_test.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - - "github.com/go-vela/types/constants" -) - -func TestSqlite_Client_Driver(t *testing.T) { - // setup types - want := constants.DriverSqlite - - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // run test - got := _database.Driver() - - if !reflect.DeepEqual(got, want) { - t.Errorf("Driver is %v, want %v", got, want) - } -} diff --git a/database/sqlite/opts.go b/database/sqlite/opts.go deleted file mode 100644 index 406dddcc8..000000000 --- a/database/sqlite/opts.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "fmt" - "time" -) - -// ClientOpt represents a configuration option to initialize the database client for Sqlite. -type ClientOpt func(*client) error - -// WithAddress sets the Sqlite address in the database client for Sqlite. -func WithAddress(address string) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring address in sqlite database client") - - // check if the Sqlite address provided is empty - if len(address) == 0 { - return fmt.Errorf("no Sqlite address provided") - } - - // set the address in the sqlite client - c.config.Address = address - - return nil - } -} - -// WithCompressionLevel sets the compression level in the database client for Sqlite. -func WithCompressionLevel(level int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring compression level in sqlite database client") - - // set the compression level in the sqlite client - c.config.CompressionLevel = level - - return nil - } -} - -// WithConnectionLife sets the connection duration in the database client for Sqlite. -func WithConnectionLife(duration time.Duration) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring connection duration in sqlite database client") - - // set the connection duration in the sqlite client - c.config.ConnectionLife = duration - - return nil - } -} - -// WithConnectionIdle sets the maximum idle connections in the database client for Sqlite. -func WithConnectionIdle(idle int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring maximum idle connections in sqlite database client") - - // set the maximum idle connections in the sqlite client - c.config.ConnectionIdle = idle - - return nil - } -} - -// WithConnectionOpen sets the maximum open connections in the database client for Sqlite. -func WithConnectionOpen(open int) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring maximum open connections in sqlite database client") - - // set the maximum open connections in the sqlite client - c.config.ConnectionOpen = open - - return nil - } -} - -// WithEncryptionKey sets the encryption key in the database client for Sqlite. -func WithEncryptionKey(key string) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring encryption key in sqlite database client") - - // check if the Sqlite encryption key provided is empty - if len(key) == 0 { - return fmt.Errorf("no Sqlite encryption key provided") - } - - // set the encryption key in the sqlite client - c.config.EncryptionKey = key - - return nil - } -} - -// WithSkipCreation sets the skip creation logic in the database client for Sqlite. -func WithSkipCreation(skipCreation bool) ClientOpt { - return func(c *client) error { - c.Logger.Trace("configuring skip creating objects in sqlite database client") - - // set to skip creating tables and indexes in the sqlite client - c.config.SkipCreation = skipCreation - - return nil - } -} diff --git a/database/sqlite/opts_test.go b/database/sqlite/opts_test.go deleted file mode 100644 index 42f70c58e..000000000 --- a/database/sqlite/opts_test.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "reflect" - "testing" - "time" - - "github.com/sirupsen/logrus" -) - -func TestSqlite_ClientOpt_WithAddress(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - failure bool - address string - want string - }{ - { - failure: false, - address: "sqlite://foo:bar@localhost:5432/vela", - want: "sqlite://foo:bar@localhost:5432/vela", - }, - { - failure: true, - address: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - err := WithAddress(test.address)(c) - - if test.failure { - if err == nil { - t.Errorf("WithAddress should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("WithAddress returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.Address, test.want) { - t.Errorf("WithAddress is %v, want %v", c.config.Address, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithCompressionLevel(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - level int - want int - }{ - { - level: 3, - want: 3, - }, - { - level: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithCompressionLevel(test.level)(c) - - if err != nil { - t.Errorf("WithCompressionLevel returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.CompressionLevel, test.want) { - t.Errorf("WithCompressionLevel is %v, want %v", c.config.CompressionLevel, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithConnectionLife(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - duration time.Duration - want time.Duration - }{ - { - duration: 10 * time.Second, - want: 10 * time.Second, - }, - { - duration: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionLife(test.duration)(c) - - if err != nil { - t.Errorf("WithConnectionLife returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionLife, test.want) { - t.Errorf("WithConnectionLife is %v, want %v", c.config.ConnectionLife, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithConnectionIdle(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - idle int - want int - }{ - { - idle: 5, - want: 5, - }, - { - idle: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionIdle(test.idle)(c) - - if err != nil { - t.Errorf("WithConnectionIdle returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionIdle, test.want) { - t.Errorf("WithConnectionIdle is %v, want %v", c.config.ConnectionIdle, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithConnectionOpen(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - open int - want int - }{ - { - open: 10, - want: 10, - }, - { - open: 0, - want: 0, - }, - } - - // run tests - for _, test := range tests { - err := WithConnectionOpen(test.open)(c) - - if err != nil { - t.Errorf("WithConnectionOpen returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.ConnectionOpen, test.want) { - t.Errorf("WithConnectionOpen is %v, want %v", c.config.ConnectionOpen, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithEncryptionKey(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - failure bool - key string - want string - }{ - { - failure: false, - key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - }, - { - failure: true, - key: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - err := WithEncryptionKey(test.key)(c) - - if test.failure { - if err == nil { - t.Errorf("WithEncryptionKey should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("WithEncryptionKey returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.EncryptionKey, test.want) { - t.Errorf("WithEncryptionKey is %v, want %v", c.config.EncryptionKey, test.want) - } - } -} - -func TestSqlite_ClientOpt_WithSkipCreation(t *testing.T) { - // setup types - c := new(client) - c.config = new(config) - logger := logrus.StandardLogger() - c.Logger = logrus.NewEntry(logger) - - // setup tests - tests := []struct { - skipCreation bool - want bool - }{ - { - skipCreation: true, - want: true, - }, - { - skipCreation: false, - want: false, - }, - } - - // run tests - for _, test := range tests { - err := WithSkipCreation(test.skipCreation)(c) - - if err != nil { - t.Errorf("WithSkipCreation returned err: %v", err) - } - - if !reflect.DeepEqual(c.config.SkipCreation, test.want) { - t.Errorf("WithSkipCreation is %v, want %v", c.config.SkipCreation, test.want) - } - } -} diff --git a/database/sqlite/ping.go b/database/sqlite/ping.go deleted file mode 100644 index a23b9f707..000000000 --- a/database/sqlite/ping.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "fmt" - "time" -) - -// Ping sends a "ping" request with backoff to the database. -func (c *client) Ping() error { - c.Logger.Trace("sending ping requests to the database") - - // create a loop to attempt ping requests 5 times - for i := 0; i < 5; i++ { - // capture database/sql database from gorm database - // - // https://pkg.go.dev/gorm.io/gorm#DB.DB - _sql, err := c.Sqlite.DB() - if err != nil { - return err - } - - // send ping request to database - // - // https://pkg.go.dev/database/sql#DB.Ping - err = _sql.Ping() - if err != nil { - c.Logger.Debugf("unable to ping database - retrying in %v", time.Duration(i)*time.Second) - - // sleep for loop iteration in seconds - time.Sleep(time.Duration(i) * time.Second) - - // continue to next iteration of the loop - continue - } - - // able to ping database so return with no error - return nil - } - - return fmt.Errorf("unable to successfully ping database") -} diff --git a/database/sqlite/ping_test.go b/database/sqlite/ping_test.go deleted file mode 100644 index 04c207bcd..000000000 --- a/database/sqlite/ping_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "testing" -) - -func TestSqlite_Client_Ping(t *testing.T) { - // setup types - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { - _sql, _ := _database.Sqlite.DB() - _sql.Close() - }() - - _bad, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - // close the bad database to simulate failures to ping - _sql, _ := _bad.Sqlite.DB() - _sql.Close() - - // setup tests - tests := []struct { - failure bool - database *client - }{ - { - failure: false, - database: _database, - }, - { - failure: true, - database: _bad, - }, - } - - // run tests - for _, test := range tests { - err = test.database.Ping() - - if test.failure { - if err == nil { - t.Errorf("Ping should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Ping returned err: %v", err) - } - } -} diff --git a/database/sqlite/sqlite.go b/database/sqlite/sqlite.go deleted file mode 100644 index 29f526643..000000000 --- a/database/sqlite/sqlite.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "time" - - "github.com/go-vela/server/database/build" - "github.com/go-vela/server/database/hook" - "github.com/go-vela/server/database/log" - "github.com/go-vela/server/database/pipeline" - "github.com/go-vela/server/database/repo" - "github.com/go-vela/server/database/schedule" - "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/user" - "github.com/go-vela/server/database/worker" - "github.com/sirupsen/logrus" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -type ( - config struct { - // specifies the address to use for the Sqlite client - Address string - // specifies the level of compression to use for the Sqlite client - CompressionLevel int - // specifies the connection duration to use for the Sqlite client - ConnectionLife time.Duration - // specifies the maximum idle connections for the Sqlite client - ConnectionIdle int - // specifies the maximum open connections for the Sqlite client - ConnectionOpen int - // specifies the encryption key to use for the Sqlite client - EncryptionKey string - // specifies to skip creating tables and indexes for the Sqlite client - SkipCreation bool - } - - client struct { - config *config - // https://pkg.go.dev/gorm.io/gorm#DB - Sqlite *gorm.DB - // https://pkg.go.dev/github.com/sirupsen/logrus#Entry - Logger *logrus.Entry - // https://pkg.go.dev/github.com/go-vela/server/database/build#BuildInterface - build.BuildInterface - // https://pkg.go.dev/github.com/go-vela/server/database/hook#HookInterface - hook.HookInterface - // https://pkg.go.dev/github.com/go-vela/server/database/log#LogInterface - log.LogInterface - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#PipelineInterface - pipeline.PipelineInterface - // https://pkg.go.dev/github.com/go-vela/server/database/repo#RepoInterface - repo.RepoInterface - // https://pkg.go.dev/github.com/go-vela/server/database/schedule#ScheduleInterface - schedule.ScheduleInterface - // https://pkg.go.dev/github.com/go-vela/server/database/secret#SecretInterface - secret.SecretInterface - // https://pkg.go.dev/github.com/go-vela/server/database/service#ServiceInterface - service.ServiceInterface - // https://pkg.go.dev/github.com/go-vela/server/database/step#StepInterface - step.StepInterface - // https://pkg.go.dev/github.com/go-vela/server/database/user#UserInterface - user.UserInterface - // https://pkg.go.dev/github.com/go-vela/server/database/worker#WorkerInterface - worker.WorkerInterface - } -) - -// New returns a Database implementation that integrates with a Sqlite instance. -// -//nolint:revive // ignore returning unexported client -func New(opts ...ClientOpt) (*client, error) { - // create new Sqlite client - c := new(client) - - // create new fields - c.config = new(config) - c.Sqlite = new(gorm.DB) - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#StandardLogger - logger := logrus.StandardLogger() - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) - - // apply all provided configuration options - for _, opt := range opts { - err := opt(c) - if err != nil { - return nil, err - } - } - - // create the new Sqlite database client - // - // https://pkg.go.dev/gorm.io/gorm#Open - _sqlite, err := gorm.Open(sqlite.Open(c.config.Address), &gorm.Config{}) - if err != nil { - return nil, err - } - - // set the Sqlite database client in the Sqlite client - c.Sqlite = _sqlite - - // setup database with proper configuration - err = setupDatabase(c) - if err != nil { - return nil, err - } - - // create the services for the database - err = createServices(c) - if err != nil { - return nil, err - } - - return c, nil -} - -// NewTest returns a Database implementation that integrates with a fake Sqlite instance. -// -// This function is intended for running tests only. -// -//nolint:revive // ignore returning unexported client -func NewTest() (*client, error) { - // create new Sqlite client - c := new(client) - - // create new fields - c.config = &config{ - CompressionLevel: 3, - ConnectionLife: 30 * time.Minute, - ConnectionIdle: 2, - ConnectionOpen: 0, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - c.Sqlite = new(gorm.DB) - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#StandardLogger - logger := logrus.StandardLogger() - - // create new logger for the client - // - // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#NewEntry - c.Logger = logrus.NewEntry(logger).WithField("database", c.Driver()) - - // create the new Sqlite database client - // - // https://pkg.go.dev/gorm.io/gorm#Open - _sqlite, err := gorm.Open( - sqlite.Open("file::memory:?cache=shared"), - &gorm.Config{SkipDefaultTransaction: true}, - ) - if err != nil { - return nil, err - } - - c.Sqlite = _sqlite - - // setup database with proper configuration - err = createServices(c) - if err != nil { - return nil, err - } - - return c, nil -} - -// setupDatabase is a helper function to setup -// the database with the proper configuration. -func setupDatabase(c *client) error { - // capture database/sql database from gorm database - // - // https://pkg.go.dev/gorm.io/gorm#DB.DB - _sql, err := c.Sqlite.DB() - if err != nil { - return err - } - - // set the maximum amount of time a connection may be reused - // - // https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime - _sql.SetConnMaxLifetime(c.config.ConnectionLife) - - // set the maximum number of connections in the idle connection pool - // - // https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns - _sql.SetMaxIdleConns(c.config.ConnectionIdle) - - // set the maximum number of open connections to the database - // - // https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns - _sql.SetMaxOpenConns(c.config.ConnectionOpen) - - // verify connection to the database - err = c.Ping() - if err != nil { - return err - } - - // check if we should skip creating database objects - if c.config.SkipCreation { - c.Logger.Warning("skipping creation of data tables and indexes in the sqlite database") - - return nil - } - - return nil -} - -// createServices is a helper function to create the database services. -func createServices(c *client) error { - var err error - - // create the database agnostic engine for builds - // - // https://pkg.go.dev/github.com/go-vela/server/database/build#New - c.BuildInterface, err = build.New( - build.WithClient(c.Sqlite), - build.WithLogger(c.Logger), - build.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for hooks - // - // https://pkg.go.dev/github.com/go-vela/server/database/hook#New - c.HookInterface, err = hook.New( - hook.WithClient(c.Sqlite), - hook.WithLogger(c.Logger), - hook.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for logs - // - // https://pkg.go.dev/github.com/go-vela/server/database/log#New - c.LogInterface, err = log.New( - log.WithClient(c.Sqlite), - log.WithCompressionLevel(c.config.CompressionLevel), - log.WithLogger(c.Logger), - log.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for pipelines - // - // https://pkg.go.dev/github.com/go-vela/server/database/pipeline#New - c.PipelineInterface, err = pipeline.New( - pipeline.WithClient(c.Sqlite), - pipeline.WithCompressionLevel(c.config.CompressionLevel), - pipeline.WithLogger(c.Logger), - pipeline.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for repos - // - // https://pkg.go.dev/github.com/go-vela/server/database/repo#New - c.RepoInterface, err = repo.New( - repo.WithClient(c.Sqlite), - repo.WithEncryptionKey(c.config.EncryptionKey), - repo.WithLogger(c.Logger), - repo.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for schedules - // - // https://pkg.go.dev/github.com/go-vela/server/database/schedule#New - c.ScheduleInterface, err = schedule.New( - schedule.WithClient(c.Sqlite), - schedule.WithLogger(c.Logger), - schedule.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for secrets - // - // https://pkg.go.dev/github.com/go-vela/server/database/secret#New - c.SecretInterface, err = secret.New( - secret.WithClient(c.Sqlite), - secret.WithEncryptionKey(c.config.EncryptionKey), - secret.WithLogger(c.Logger), - secret.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for services - // - // https://pkg.go.dev/github.com/go-vela/server/database/service#New - c.ServiceInterface, err = service.New( - service.WithClient(c.Sqlite), - service.WithLogger(c.Logger), - service.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for steps - // - // https://pkg.go.dev/github.com/go-vela/server/database/step#New - c.StepInterface, err = step.New( - step.WithClient(c.Sqlite), - step.WithLogger(c.Logger), - step.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for users - // - // https://pkg.go.dev/github.com/go-vela/server/database/user#New - c.UserInterface, err = user.New( - user.WithClient(c.Sqlite), - user.WithEncryptionKey(c.config.EncryptionKey), - user.WithLogger(c.Logger), - user.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - // create the database agnostic engine for workers - // - // https://pkg.go.dev/github.com/go-vela/server/database/worker#New - c.WorkerInterface, err = worker.New( - worker.WithClient(c.Sqlite), - worker.WithLogger(c.Logger), - worker.WithSkipCreation(c.config.SkipCreation), - ) - if err != nil { - return err - } - - return nil -} diff --git a/database/sqlite/sqlite_test.go b/database/sqlite/sqlite_test.go deleted file mode 100644 index 55c6940d0..000000000 --- a/database/sqlite/sqlite_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package sqlite - -import ( - "testing" - "time" -) - -func TestSqlite_New(t *testing.T) { - // setup tests - tests := []struct { - failure bool - address string - want string - }{ - { - failure: false, - address: ":memory:", - want: ":memory:", - }, - { - failure: true, - address: "", - want: "", - }, - } - - // run tests - for _, test := range tests { - _, err := New( - WithAddress(test.address), - WithCompressionLevel(3), - WithConnectionLife(10*time.Second), - WithConnectionIdle(5), - WithConnectionOpen(20), - WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), - WithSkipCreation(false), - ) - - if test.failure { - if err == nil { - t.Errorf("New should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("New returned err: %v", err) - } - } -} - -func TestSqlite_setupDatabase(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - // setup the skip test database client - _skipDatabase, err := NewTest() - if err != nil { - t.Errorf("unable to create new skip sqlite test database: %v", err) - } - - defer func() { _sql, _ := _skipDatabase.Sqlite.DB(); _sql.Close() }() - - err = WithSkipCreation(true)(_skipDatabase) - if err != nil { - t.Errorf("unable to set SkipCreation for sqlite test database: %v", err) - } - - tests := []struct { - failure bool - database *client - }{ - { - failure: false, - database: _database, - }, - { - failure: false, - database: _skipDatabase, - }, - } - - // run tests - for _, test := range tests { - err := setupDatabase(test.database) - - if test.failure { - if err == nil { - t.Errorf("setupDatabase should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("setupDatabase returned err: %v", err) - } - } -} - -func TestSqlite_createServices(t *testing.T) { - // setup types - // setup the test database client - _database, err := NewTest() - if err != nil { - t.Errorf("unable to create new sqlite test database: %v", err) - } - - defer func() { _sql, _ := _database.Sqlite.DB(); _sql.Close() }() - - tests := []struct { - failure bool - }{ - { - failure: false, - }, - } - - // run tests - for _, test := range tests { - err := createServices(_database) - - if test.failure { - if err == nil { - t.Errorf("createServices should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("createServices returned err: %v", err) - } - } -} From d51b1c33e4b0ca2e1b940a0c8a2dc5797d7ad8c9 Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Mon, 12 Jun 2023 09:38:25 -0500 Subject: [PATCH 260/298] refactor(templates): use yaml for tests instead of base64 encoded json (#881) * refactor(templates): use yaml for tests instead of base64 encoded json * remove duplicative file --- compiler/native/compile_test.go | 40 +++++---- compiler/native/expand_test.go | 86 ++++++++++--------- compiler/native/testdata/gradle.yml | 70 +++++++++++++++ compiler/native/testdata/long_template.yml | 59 +++++++++++++ compiler/native/testdata/maven.yml | 70 +++++++++++++++ .../testdata/stages_pipeline_template.yml | 2 +- .../testdata/steps_pipeline_template.yml | 2 +- .../testdata/template-calls-itself.json | 18 ---- .../testdata/template-calls-template.json | 18 ---- compiler/native/testdata/template-gradle.json | 18 ---- compiler/native/testdata/template-maven.json | 18 ---- .../native/testdata/template-starlark.json | 18 ---- compiler/native/testdata/template.json | 18 ---- compiler/native/testdata/template.star | 6 +- .../native/testdata/template_calls_itself.yml | 11 +++ .../testdata/template_calls_template.yml | 15 ++++ 16 files changed, 300 insertions(+), 169 deletions(-) create mode 100644 compiler/native/testdata/gradle.yml create mode 100644 compiler/native/testdata/long_template.yml create mode 100644 compiler/native/testdata/maven.yml delete mode 100644 compiler/native/testdata/template-calls-itself.json delete mode 100644 compiler/native/testdata/template-calls-template.json delete mode 100644 compiler/native/testdata/template-gradle.json delete mode 100644 compiler/native/testdata/template-maven.json delete mode 100644 compiler/native/testdata/template-starlark.json delete mode 100644 compiler/native/testdata/template.json create mode 100644 compiler/native/testdata/template_calls_itself.yml create mode 100644 compiler/native/testdata/template_calls_template.yml diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 67c89f3a2..07b420dde 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -606,10 +606,12 @@ func TestNative_Compile_StagesPipelineTemplate(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/:org/:name/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -871,10 +873,12 @@ func TestNative_Compile_StepsPipelineTemplate(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -1338,10 +1342,12 @@ func TestNative_Compile_InvalidType(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -1886,10 +1892,12 @@ func Test_client_modifyConfig(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) m := &types.Metadata{ diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index a32a2286d..d2a8a92b6 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -29,10 +29,12 @@ func TestNative_ExpandStages(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -49,7 +51,7 @@ func TestNative_ExpandStages(t *testing.T) { tmpls := map[string]*yaml.Template{ "gradle": { Name: "gradle", - Source: "github.example.com/foo/bar/template.yml", + Source: "github.example.com/foo/bar/long_template.yml", Type: "github", }, } @@ -177,10 +179,12 @@ func TestNative_ExpandSteps(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -209,7 +213,7 @@ func TestNative_ExpandSteps(t *testing.T) { tmpls: map[string]*yaml.Template{ "gradle": { Name: "gradle", - Source: "github.example.com/foo/bar/template.yml", + Source: "github.example.com/foo/bar/long_template.yml", Type: "github", }, }, @@ -219,7 +223,7 @@ func TestNative_ExpandSteps(t *testing.T) { tmpls: map[string]*yaml.Template{ "gradle": { Name: "gradle", - Source: "template.yml", + Source: "long_template.yml", Type: "file", }, }, @@ -351,15 +355,12 @@ func TestNative_ExpandStepsMulti(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template-gradle.json") - }) - engine.GET("/api/v3/repos/bar/foo/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template-maven.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -538,7 +539,7 @@ func TestNative_ExpandStepsMulti(t *testing.T) { "auth_method": "token", "username": "octocat", "items": []interface{}{ - map[interface{}]interface{}{string("path"): string("docker"), string("source"): string("secret/docker")}, + map[interface{}]interface{}{"path": "docker", "source": "secret/docker"}, }, }, }, @@ -559,7 +560,7 @@ func TestNative_ExpandStepsMulti(t *testing.T) { "auth_method": "token", "username": "octocat", "items": []interface{}{ - map[interface{}]interface{}{string("path"): string("docker"), string("source"): string("secret/docker")}, + map[interface{}]interface{}{"path": "docker", "source": "secret/docker"}, }, }, }, @@ -615,10 +616,12 @@ func TestNative_ExpandStepsStarlark(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template-starlark.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -703,16 +706,12 @@ func TestNative_ExpandSteps_TemplateCallTemplate(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/api/v3/repos/foo/bar/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template.json") - }) - - engine.GET("/api/v3/repos/faz/baz/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template-calls-template.json") + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -746,7 +745,7 @@ func TestNative_ExpandSteps_TemplateCallTemplate(t *testing.T) { tmpls: map[string]*yaml.Template{ "chain": { Name: "chain", - Source: "github.example.com/faz/baz/template.yml", + Source: "github.example.com/faz/baz/template_calls_template.yml", Type: "github", }, }, @@ -872,10 +871,13 @@ func TestNative_ExpandSteps_TemplateCallTemplate_CircularFail(t *testing.T) { resp := httptest.NewRecorder() _, engine := gin.CreateTestContext(resp) - engine.GET("/api/v3/repos/bad/design/contents/:path", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/template-calls-itself.json") + // setup mock server + engine.GET("/api/v3/repos/:org/:repo/contents/:path", func(c *gin.Context) { + body, err := convertFileToGithubResponse(c.Param("path")) + if err != nil { + t.Error(err) + } + c.JSON(http.StatusOK, body) }) s := httptest.NewServer(engine) @@ -909,7 +911,7 @@ func TestNative_ExpandSteps_TemplateCallTemplate_CircularFail(t *testing.T) { tmpls: map[string]*yaml.Template{ "circle": { Name: "circle", - Source: "github.example.com/bad/design/template.yml", + Source: "github.example.com/bad/design/template_calls_itself.yml", Type: "github", }, }, diff --git a/compiler/native/testdata/gradle.yml b/compiler/native/testdata/gradle.yml new file mode 100644 index 000000000..ed1e8e0d1 --- /dev/null +++ b/compiler/native/testdata/gradle.yml @@ -0,0 +1,70 @@ +metadata: + template: true + +steps: + - name: install + commands: + - ./gradlew downloadDependencies + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: test + commands: + - ./gradlew check + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: build + commands: + - ./gradlew build + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + +secrets: + - name: docker_username + key: org/repo/foo/bar + engine: native + type: repo + + - name: foo_password + key: org/repo/foo/password + engine: vault + type: repo + + - name: vault_token + + - origin: + name: private vault + image: target/secret-vault:latest + pull: always + secrets: [ vault_token ] + parameters: + addr: vault.example.com + auth_method: token + username: octocat + items: + - source: secret/docker + path: docker + + {{ if .secret }} + +- name: bar_password + key: org/repo/bar/password + engine: vault + type: repo + + {{ end }} + +services: + - name: postgres + image: postgres:12 + + {{ if .service }} + + - name: redis + key: redis:6 + + {{ end }} diff --git a/compiler/native/testdata/long_template.yml b/compiler/native/testdata/long_template.yml new file mode 100644 index 000000000..c9f92ee44 --- /dev/null +++ b/compiler/native/testdata/long_template.yml @@ -0,0 +1,59 @@ +environment: + star: "test3" + bar: "test4" + +metadata: + template: true + +steps: + - name: install + commands: + - ./gradlew downloadDependencies + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: test + commands: + - ./gradlew check + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: build + commands: + - ./gradlew build + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + +secrets: + - name: docker_username + key: org/repo/foo/bar + engine: native + type: repo + + - name: foo_password + key: org/repo/foo/password + engine: vault + type: repo + + {{ if .secret }} + + - name: bar_password + key: org/repo/bar/password + engine: vault + type: repo + + {{ end }} + +services: + - name: postgres + image: postgres:12 + + {{ if .service }} + + - name: redis + key: redis:6 + + {{ end }} diff --git a/compiler/native/testdata/maven.yml b/compiler/native/testdata/maven.yml new file mode 100644 index 000000000..fd6ff73b1 --- /dev/null +++ b/compiler/native/testdata/maven.yml @@ -0,0 +1,70 @@ +metadata: + template: true + +steps: + - name: install + commands: + - mvn downloadDependencies + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: test + commands: + - mvn check + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + + - name: build + commands: + - mvn build + environment: {{ .environment }} + image: {{ .image }} + {{ .pull_policy }} + +secrets: + - name: docker_username + key: org/repo/foo/bar + engine: native + type: repo + + - name: foo_password + key: org/repo/foo/password + engine: vault + type: repo + + - name: vault_token + + - origin: + name: private vault + image: target/secret-vault:latest + pull: always + secrets: [ vault_token ] + parameters: + addr: vault.example.com + auth_method: token + username: octocat + items: + - source: secret/docker + path: docker + + {{ if .secret }} + +- name: bar_password + key: org/repo/bar/password + engine: vault + type: repo + + {{ end }} + +services: + - name: postgres + image: postgres:12 + + {{ if .service }} + + - name: redis + key: redis:6 + + {{ end }} diff --git a/compiler/native/testdata/stages_pipeline_template.yml b/compiler/native/testdata/stages_pipeline_template.yml index 0354ec737..25189ed73 100644 --- a/compiler/native/testdata/stages_pipeline_template.yml +++ b/compiler/native/testdata/stages_pipeline_template.yml @@ -6,7 +6,7 @@ metadata: templates: - name: gradle - source: github.example.com/github/octocat/template.yml + source: github.example.com/github/octocat/long_template.yml type: github stages: diff --git a/compiler/native/testdata/steps_pipeline_template.yml b/compiler/native/testdata/steps_pipeline_template.yml index 9e8402e8e..7d8e8db28 100644 --- a/compiler/native/testdata/steps_pipeline_template.yml +++ b/compiler/native/testdata/steps_pipeline_template.yml @@ -5,7 +5,7 @@ metadata: templates: - name: gradle - source: github.example.com/foo/bar/template.yml + source: github.example.com/foo/bar/long_template.yml type: github steps: diff --git a/compiler/native/testdata/template-calls-itself.json b/compiler/native/testdata/template-calls-itself.json deleted file mode 100644 index a930d6780..000000000 --- a/compiler/native/testdata/template-calls-itself.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "template.yml", - "path": "template.yml", - "content": "dmVyc2lvbjogIjEiCgp0ZW1wbGF0ZXM6CiAgLSBuYW1lOiB0ZXN0CiAgICBzb3VyY2U6IGdpdGh1Yi5leGFtcGxlLmNvbS9iYWQvZGVzaWduL3RlbXBsYXRlLnltbAogICAgdHlwZTogZ2l0aHViCgpzdGVwczoKICAtIG5hbWU6IGNhbGwgdGVtcGxhdGUKICAgIHRlbXBsYXRlOgogICAgICBuYW1lOiB0ZXN0Cg==", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.yml", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.yml", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "html": "https://github.com/octokit/octokit.rb/blob/master/template.yml" - } -} \ No newline at end of file diff --git a/compiler/native/testdata/template-calls-template.json b/compiler/native/testdata/template-calls-template.json deleted file mode 100644 index 6fb0be303..000000000 --- a/compiler/native/testdata/template-calls-template.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "template.yml", - "path": "template.yml", - "content": "dmVyc2lvbjogIjEiCgp0ZW1wbGF0ZXM6CiAgLSBuYW1lOiB0ZXN0CiAgICBzb3VyY2U6IGdpdGh1Yi5leGFtcGxlLmNvbS9mb28vYmFyL3RlbXBsYXRlLnltbAogICAgdHlwZTogZ2l0aHViCgpzdGVwczoKICAtIG5hbWU6IGNhbGwgdGVtcGxhdGUKICAgIHRlbXBsYXRlOgogICAgICBuYW1lOiB0ZXN0CiAgICAgIHZhcnM6CiAgICAgICAgaW1hZ2U6IG9wZW5qZGs6bGF0ZXN0CiAgICAgICAgZW52aXJvbm1lbnQ6ICJ7IEdSQURMRV9VU0VSX0hPTUU6IC5ncmFkbGUsIEdSQURMRV9PUFRTOiAtRG9yZy5ncmFkbGUuZGFlbW9uPWZhbHNlIC1Eb3JnLmdyYWRsZS53b3JrZXJzLm1heD0xIC1Eb3JnLmdyYWRsZS5wYXJhbGxlbD1mYWxzZSB9IgogICAgICAgIHB1bGxfcG9saWN5OiAicHVsbDogdHJ1ZSIK", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.yml", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.yml", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "html": "https://github.com/octokit/octokit.rb/blob/master/template.yml" - } -} \ No newline at end of file diff --git a/compiler/native/testdata/template-gradle.json b/compiler/native/testdata/template-gradle.json deleted file mode 100644 index 8ad5f9091..000000000 --- a/compiler/native/testdata/template-gradle.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "gradle.yml", - "path": "gradle.yml", - "content": "bWV0YWRhdGE6CiAgdGVtcGxhdGU6IHRydWUKCnN0ZXBzOgogIC0gbmFtZTogaW5zdGFsbAogICAgY29tbWFuZHM6CiAgICAgIC0gLi9ncmFkbGV3IGRvd25sb2FkRGVwZW5kZW5jaWVzCiAgICBlbnZpcm9ubWVudDoge3sgLmVudmlyb25tZW50IH19CiAgICBpbWFnZToge3sgLmltYWdlIH19CiAgICB7eyAucHVsbF9wb2xpY3kgfX0KCiAgLSBuYW1lOiB0ZXN0CiAgICBjb21tYW5kczoKICAgICAgLSAuL2dyYWRsZXcgY2hlY2sKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKICAtIG5hbWU6IGJ1aWxkCiAgICBjb21tYW5kczoKICAgICAgLSAuL2dyYWRsZXcgYnVpbGQKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKc2VjcmV0czoKICAtIG5hbWU6IGRvY2tlcl91c2VybmFtZQogICAga2V5OiBvcmcvcmVwby9mb28vYmFyCiAgICBlbmdpbmU6IG5hdGl2ZQogICAgdHlwZTogcmVwbwoKICAtIG5hbWU6IGZvb19wYXNzd29yZAogICAga2V5OiBvcmcvcmVwby9mb28vcGFzc3dvcmQKICAgIGVuZ2luZTogdmF1bHQKICAgIHR5cGU6IHJlcG8KCiAgLSBuYW1lOiB2YXVsdF90b2tlbgoKICAtIG9yaWdpbjoKICAgICAgbmFtZTogcHJpdmF0ZSB2YXVsdAogICAgICBpbWFnZTogdGFyZ2V0L3NlY3JldC12YXVsdDpsYXRlc3QKICAgICAgcHVsbDogYWx3YXlzCiAgICAgIHNlY3JldHM6IFsgdmF1bHRfdG9rZW4gXQogICAgICBwYXJhbWV0ZXJzOgogICAgICAgIGFkZHI6IHZhdWx0LmV4YW1wbGUuY29tCiAgICAgICAgYXV0aF9tZXRob2Q6IHRva2VuCiAgICAgICAgdXNlcm5hbWU6IG9jdG9jYXQKICAgICAgICBpdGVtczoKICAgICAgICAgIC0gc291cmNlOiBzZWNyZXQvZG9ja2VyCiAgICAgICAgICAgIHBhdGg6IGRvY2tlcgoKe3sgaWYgLnNlY3JldCB9fQoKICAtIG5hbWU6IGJhcl9wYXNzd29yZAogICAga2V5OiBvcmcvcmVwby9iYXIvcGFzc3dvcmQKICAgIGVuZ2luZTogdmF1bHQKICAgIHR5cGU6IHJlcG8KCnt7IGVuZCB9fQoKc2VydmljZXM6CiAgIC0gbmFtZTogcG9zdGdyZXMKICAgICBpbWFnZTogcG9zdGdyZXM6MTIKCiB7eyBpZiAuc2VydmljZSB9fQoKICAgLSBuYW1lOiByZWRpcwogICAgIGtleTogcmVkaXM6NgoKIHt7IGVuZCB9fQo=", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/gradle.yml", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/gradle.yml", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/gradle.yml", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/gradle.yml", - "html": "https://github.com/octokit/octokit.rb/blob/master/gradle.yml" - } -} diff --git a/compiler/native/testdata/template-maven.json b/compiler/native/testdata/template-maven.json deleted file mode 100644 index afc763414..000000000 --- a/compiler/native/testdata/template-maven.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "maven.yml", - "path": "maven.yml", - "content": "bWV0YWRhdGE6CiAgdGVtcGxhdGU6IHRydWUKCnN0ZXBzOgogIC0gbmFtZTogaW5zdGFsbAogICAgY29tbWFuZHM6CiAgICAgIC0gbXZuIGRvd25sb2FkRGVwZW5kZW5jaWVzCiAgICBlbnZpcm9ubWVudDoge3sgLmVudmlyb25tZW50IH19CiAgICBpbWFnZToge3sgLmltYWdlIH19CiAgICB7eyAucHVsbF9wb2xpY3kgfX0KCiAgLSBuYW1lOiB0ZXN0CiAgICBjb21tYW5kczoKICAgICAgLSBtdm4gY2hlY2sKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKICAtIG5hbWU6IGJ1aWxkCiAgICBjb21tYW5kczoKICAgICAgLSBtdm4gYnVpbGQKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKc2VjcmV0czoKICAtIG5hbWU6IGRvY2tlcl91c2VybmFtZQogICAga2V5OiBvcmcvcmVwby9mb28vYmFyCiAgICBlbmdpbmU6IG5hdGl2ZQogICAgdHlwZTogcmVwbwoKICAtIG5hbWU6IGZvb19wYXNzd29yZAogICAga2V5OiBvcmcvcmVwby9mb28vcGFzc3dvcmQKICAgIGVuZ2luZTogdmF1bHQKICAgIHR5cGU6IHJlcG8KCiAgLSBuYW1lOiB2YXVsdF90b2tlbgoKICAtIG9yaWdpbjoKICAgICAgbmFtZTogcHJpdmF0ZSB2YXVsdAogICAgICBpbWFnZTogdGFyZ2V0L3NlY3JldC12YXVsdDpsYXRlc3QKICAgICAgcHVsbDogYWx3YXlzCiAgICAgIHNlY3JldHM6IFsgdmF1bHRfdG9rZW4gXQogICAgICBwYXJhbWV0ZXJzOgogICAgICAgIGFkZHI6IHZhdWx0LmV4YW1wbGUuY29tCiAgICAgICAgYXV0aF9tZXRob2Q6IHRva2VuCiAgICAgICAgdXNlcm5hbWU6IG9jdG9jYXQKICAgICAgICBpdGVtczoKICAgICAgICAgIC0gc291cmNlOiBzZWNyZXQvZG9ja2VyCiAgICAgICAgICAgIHBhdGg6IGRvY2tlcgoKe3sgaWYgLnNlY3JldCB9fQoKICAtIG5hbWU6IGJhcl9wYXNzd29yZAogICAga2V5OiBvcmcvcmVwby9iYXIvcGFzc3dvcmQKICAgIGVuZ2luZTogdmF1bHQKICAgIHR5cGU6IHJlcG8KCnt7IGVuZCB9fQoKc2VydmljZXM6CiAgIC0gbmFtZTogcG9zdGdyZXMKICAgICBpbWFnZTogcG9zdGdyZXM6MTIKCiB7eyBpZiAuc2VydmljZSB9fQoKICAgLSBuYW1lOiByZWRpcwogICAgIGtleTogcmVkaXM6NgoKIHt7IGVuZCB9fQo=", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/maven.yml", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/maven.yml", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/maven.yml", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/maven.yml", - "html": "https://github.com/octokit/octokit.rb/blob/master/maven.yml" - } -} diff --git a/compiler/native/testdata/template-starlark.json b/compiler/native/testdata/template-starlark.json deleted file mode 100644 index 5a29da9df..000000000 --- a/compiler/native/testdata/template-starlark.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "template.star", - "path": "template.star", - "content": "ZGVmIG1haW4oY3R4KToKICByZXR1cm4gewogICAgJ3ZlcnNpb24nOiAnMScsCiAgICAnZW52aXJvbm1lbnQnOiB7CiAgICAgICdzdGFyJzogJ3Rlc3QzJywKICAgICAgJ2Jhcic6ICd0ZXN0NCcsCiAgICB9LAogICAgJ3N0ZXBzJzogWwogICAgICB7CiAgICAgICAgJ25hbWUnOiAnYnVpbGQnLAogICAgICAgICdpbWFnZSc6ICdnb2xhbmc6bGF0ZXN0JywKICAgICAgICAnY29tbWFuZHMnOiBbCiAgICAgICAgICAnZ28gYnVpbGQnLAogICAgICAgICAgJ2dvIHRlc3QnLAogICAgICAgIF0KICAgICAgfSwKICAgIF0sCn0K\n", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.star", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.star", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.star", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.star", - "html": "https://github.com/octokit/octokit.rb/blob/master/template.star" - } -} diff --git a/compiler/native/testdata/template.json b/compiler/native/testdata/template.json deleted file mode 100644 index f65b38008..000000000 --- a/compiler/native/testdata/template.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "file", - "encoding": "base64", - "size": 5362, - "name": "template.yml", - "path": "template.yml", - "content": "ZW52aXJvbm1lbnQ6CiAgc3RhcjogInRlc3QzIgogIGJhcjogInRlc3Q0IgoKbWV0YWRhdGE6CiAgdGVtcGxhdGU6IHRydWUKCnN0ZXBzOgogIC0gbmFtZTogaW5zdGFsbAogICAgY29tbWFuZHM6CiAgICAgIC0gLi9ncmFkbGV3IGRvd25sb2FkRGVwZW5kZW5jaWVzCiAgICBlbnZpcm9ubWVudDoge3sgLmVudmlyb25tZW50IH19CiAgICBpbWFnZToge3sgLmltYWdlIH19CiAgICB7eyAucHVsbF9wb2xpY3kgfX0KCiAgLSBuYW1lOiB0ZXN0CiAgICBjb21tYW5kczoKICAgICAgLSAuL2dyYWRsZXcgY2hlY2sKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKICAtIG5hbWU6IGJ1aWxkCiAgICBjb21tYW5kczoKICAgICAgLSAuL2dyYWRsZXcgYnVpbGQKICAgIGVudmlyb25tZW50OiB7eyAuZW52aXJvbm1lbnQgfX0KICAgIGltYWdlOiB7eyAuaW1hZ2UgfX0KICAgIHt7IC5wdWxsX3BvbGljeSB9fQoKc2VjcmV0czoKICAtIG5hbWU6IGRvY2tlcl91c2VybmFtZQogICAga2V5OiBvcmcvcmVwby9mb28vYmFyCiAgICBlbmdpbmU6IG5hdGl2ZQogICAgdHlwZTogcmVwbwoKICAtIG5hbWU6IGZvb19wYXNzd29yZAogICAga2V5OiBvcmcvcmVwby9mb28vcGFzc3dvcmQKICAgIGVuZ2luZTogdmF1bHQKICAgIHR5cGU6IHJlcG8KCnt7IGlmIC5zZWNyZXQgfX0KCiAgLSBuYW1lOiBiYXJfcGFzc3dvcmQKICAgIGtleTogb3JnL3JlcG8vYmFyL3Bhc3N3b3JkCiAgICBlbmdpbmU6IHZhdWx0CiAgICB0eXBlOiByZXBvCgp7eyBlbmQgfX0KCnNlcnZpY2VzOgogICAtIG5hbWU6IHBvc3RncmVzCiAgICAgaW1hZ2U6IHBvc3RncmVzOjEyCgoge3sgaWYgLnNlcnZpY2UgfX0KCiAgIC0gbmFtZTogcmVkaXMKICAgICBrZXk6IHJlZGlzOjYKCiB7eyBlbmQgfX0K", - "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", - "url": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "html_url": "https://github.com/octokit/octokit.rb/blob/master/template.yml", - "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/template.yml", - "_links": { - "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", - "self": "https://api.github.com/repos/octokit/octokit.rb/contents/template.yml", - "html": "https://github.com/octokit/octokit.rb/blob/master/template.yml" - } -} diff --git a/compiler/native/testdata/template.star b/compiler/native/testdata/template.star index 079d70943..9c2815791 100644 --- a/compiler/native/testdata/template.star +++ b/compiler/native/testdata/template.star @@ -1,6 +1,10 @@ def main(ctx): return { 'version': '1', + 'environment': { + 'star': 'test3', + 'bar': 'test4', + }, 'steps': [ { 'name': 'build', @@ -11,4 +15,4 @@ def main(ctx): ] }, ], -} \ No newline at end of file +} diff --git a/compiler/native/testdata/template_calls_itself.yml b/compiler/native/testdata/template_calls_itself.yml new file mode 100644 index 000000000..9b467a675 --- /dev/null +++ b/compiler/native/testdata/template_calls_itself.yml @@ -0,0 +1,11 @@ +version: "1" + +templates: + - name: test + source: github.example.com/bad/design/template_calls_itself.yml + type: github + +steps: + - name: call template + template: + name: test diff --git a/compiler/native/testdata/template_calls_template.yml b/compiler/native/testdata/template_calls_template.yml new file mode 100644 index 000000000..b6197169d --- /dev/null +++ b/compiler/native/testdata/template_calls_template.yml @@ -0,0 +1,15 @@ +version: "1" + +templates: + - name: test + source: github.example.com/foo/bar/long_template.yml + type: github + +steps: + - name: call template + template: + name: test + vars: + image: openjdk:latest + environment: "{ GRADLE_USER_HOME: .gradle, GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.workers.max=1 -Dorg.gradle.parallel=false }" + pull_policy: "pull: true" From ca3e1e3f8cf72017f4eb38f928de611bd20291d3 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:39:49 -0600 Subject: [PATCH 261/298] refactor(database): return pipeline on created and updated (#882) * refactor(database): return pipeline on created and updated * fix weird error handling --- api/build/create.go | 13 +----------- api/build/restart.go | 13 +----------- api/pipeline/create.go | 12 +---------- api/pipeline/update.go | 12 +---------- api/webhook/post.go | 15 +------------- cmd/vela-server/schedule.go | 8 +------- database/pipeline/count_repo_test.go | 4 ++-- database/pipeline/count_test.go | 4 ++-- database/pipeline/create.go | 21 +++++++++++++------- database/pipeline/create_test.go | 8 +++++++- database/pipeline/delete_test.go | 2 +- database/pipeline/get_repo_test.go | 2 +- database/pipeline/get_test.go | 2 +- database/pipeline/interface.go | 4 ++-- database/pipeline/list_repo_test.go | 4 ++-- database/pipeline/list_test.go | 4 ++-- database/pipeline/update.go | 22 ++++++++++++++------- database/pipeline/update_test.go | 10 ++++++++-- router/middleware/pipeline/pipeline_test.go | 2 +- 19 files changed, 64 insertions(+), 98 deletions(-) diff --git a/api/build/create.go b/api/build/create.go index 3f695d791..38a8867c2 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -308,7 +308,7 @@ func CreateBuild(c *gin.Context) { pipeline.SetRef(input.GetRef()) // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(pipeline) if err != nil { retErr := fmt.Errorf("unable to create new build: failed to create pipeline for %s: %w", r.GetFullName(), err) @@ -316,17 +316,6 @@ func CreateBuild(c *gin.Context) { return } - - // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to create new build: failed to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } } input.SetPipelineID(pipeline.GetID()) diff --git a/api/build/restart.go b/api/build/restart.go index 302090a9c..8bb85e798 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -299,7 +299,7 @@ func RestartBuild(c *gin.Context) { pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(pipeline) if err != nil { retErr := fmt.Errorf("unable to create pipeline for %s: %w", r.GetFullName(), err) @@ -307,17 +307,6 @@ func RestartBuild(c *gin.Context) { return } - - // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), r) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } } b.SetPipelineID(pipeline.GetID()) diff --git a/api/pipeline/create.go b/api/pipeline/create.go index 2b8bbfaf0..f6a4938bc 100644 --- a/api/pipeline/create.go +++ b/api/pipeline/create.go @@ -98,7 +98,7 @@ func CreatePipeline(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(input) + p, err := database.FromContext(c).CreatePipeline(input) if err != nil { retErr := fmt.Errorf("unable to create pipeline %s/%s: %w", r.GetFullName(), input.GetCommit(), err) @@ -107,15 +107,5 @@ func CreatePipeline(c *gin.Context) { return } - // send API call to capture the created pipeline - p, err := database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) - if err != nil { - retErr := fmt.Errorf("unable to capture pipeline %s/%s: %w", r.GetFullName(), input.GetCommit(), err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - c.JSON(http.StatusCreated, p) } diff --git a/api/pipeline/update.go b/api/pipeline/update.go index c769cfb7b..9c10d40b6 100644 --- a/api/pipeline/update.go +++ b/api/pipeline/update.go @@ -170,7 +170,7 @@ func UpdatePipeline(c *gin.Context) { } // send API call to update the pipeline - err = database.FromContext(c).UpdatePipeline(p) + p, err = database.FromContext(c).UpdatePipeline(p) if err != nil { retErr := fmt.Errorf("unable to update pipeline %s: %w", entry, err) @@ -179,15 +179,5 @@ func UpdatePipeline(c *gin.Context) { return } - // send API call to capture the updated pipeline - p, err = database.FromContext(c).GetPipelineForRepo(p.GetCommit(), r) - if err != nil { - retErr := fmt.Errorf("unable to capture pipeline %s: %w", entry, err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - c.JSON(http.StatusOK, p) } diff --git a/api/webhook/post.go b/api/webhook/post.go index c25abb634..2832941dc 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -561,7 +561,7 @@ func PostWebhook(c *gin.Context) { pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(pipeline) if err != nil { retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, repo.GetFullName(), err) @@ -580,19 +580,6 @@ func PostWebhook(c *gin.Context) { return } - - // send API call to capture the created pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(pipeline.GetCommit(), repo) - if err != nil { - //nolint:lll // ignore long line length due to error message - retErr := fmt.Errorf("%s: failed to get new pipeline %s/%s: %w", baseErr, repo.GetFullName(), pipeline.GetCommit(), err) - util.HandleError(c, http.StatusInternalServerError, retErr) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return - } } b.SetPipelineID(pipeline.GetID()) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 532dd65b7..ab0a56b90 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -294,7 +294,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - err = database.CreatePipeline(pipeline) + pipeline, err = database.CreatePipeline(pipeline) if err != nil { err = fmt.Errorf("failed to create pipeline for %s: %w", r.GetFullName(), err) @@ -308,12 +308,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat return err } - - // send API call to capture the created pipeline - pipeline, err = database.GetPipelineForRepo(pipeline.GetCommit(), r) - if err != nil { - return fmt.Errorf("unable to get new pipeline %s/%s: %w", r.GetFullName(), pipeline.GetCommit(), err) - } } b.SetPipelineID(pipeline.GetID()) diff --git a/database/pipeline/count_repo_test.go b/database/pipeline/count_repo_test.go index 9cb91b72b..cc3650d12 100644 --- a/database/pipeline/count_repo_test.go +++ b/database/pipeline/count_repo_test.go @@ -42,12 +42,12 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(_pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(_pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/count_test.go b/database/pipeline/count_test.go index a811b01df..bbc654fb5 100644 --- a/database/pipeline/count_test.go +++ b/database/pipeline/count_test.go @@ -41,12 +41,12 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(_pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(_pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/create.go b/database/pipeline/create.go index 5d6e4771f..424c24c23 100644 --- a/database/pipeline/create.go +++ b/database/pipeline/create.go @@ -12,7 +12,7 @@ import ( ) // CreatePipeline creates a new pipeline in the database. -func (e *engine) CreatePipeline(p *library.Pipeline) error { +func (e *engine) CreatePipeline(p *library.Pipeline) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "pipeline": p.GetCommit(), }).Tracef("creating pipeline %s in the database", p.GetCommit()) @@ -27,7 +27,7 @@ func (e *engine) CreatePipeline(p *library.Pipeline) error { // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Validate err := pipeline.Validate() if err != nil { - return err + return nil, err } // compress data for the pipeline @@ -35,12 +35,19 @@ func (e *engine) CreatePipeline(p *library.Pipeline) error { // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Compress err = pipeline.Compress(e.config.CompressionLevel) if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TablePipeline). - Create(pipeline). - Error + err = e.client.Table(constants.TablePipeline).Create(pipeline).Error + if err != nil { + return nil, err + } + + err = pipeline.Decompress() + if err != nil { + return nil, err + } + + return pipeline.ToLibrary(), nil } diff --git a/database/pipeline/create_test.go b/database/pipeline/create_test.go index be29ad8fd..5a19c7e84 100644 --- a/database/pipeline/create_test.go +++ b/database/pipeline/create_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -19,6 +20,7 @@ func TestPipeline_Engine_CreatePipeline(t *testing.T) { _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") + _pipeline.SetData([]byte{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -57,7 +59,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreatePipeline(_pipeline) + got, err := test.database.CreatePipeline(_pipeline) if test.failure { if err == nil { @@ -70,6 +72,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). if err != nil { t.Errorf("CreatePipeline for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _pipeline) { + t.Errorf("CreatePipeline for %s returned %s, want %s", test.name, got, _pipeline) + } }) } } diff --git a/database/pipeline/delete_test.go b/database/pipeline/delete_test.go index ff3e7f892..6bef174c7 100644 --- a/database/pipeline/delete_test.go +++ b/database/pipeline/delete_test.go @@ -31,7 +31,7 @@ func TestPipeline_Engine_DeletePipeline(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(_pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/get_repo_test.go b/database/pipeline/get_repo_test.go index bb956d469..ab810ba5f 100644 --- a/database/pipeline/get_repo_test.go +++ b/database/pipeline/get_repo_test.go @@ -37,7 +37,7 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(_pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/get_test.go b/database/pipeline/get_test.go index 050a06c3d..f7c3565d3 100644 --- a/database/pipeline/get_test.go +++ b/database/pipeline/get_test.go @@ -37,7 +37,7 @@ func TestPipeline_Engine_GetPipeline(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(_pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/interface.go b/database/pipeline/interface.go index eaafa59fe..c28c30da8 100644 --- a/database/pipeline/interface.go +++ b/database/pipeline/interface.go @@ -31,7 +31,7 @@ type PipelineInterface interface { // CountPipelinesForRepo defines a function that gets the count of pipelines by repo ID. CountPipelinesForRepo(*library.Repo) (int64, error) // CreatePipeline defines a function that creates a new pipeline. - CreatePipeline(*library.Pipeline) error + CreatePipeline(*library.Pipeline) (*library.Pipeline, error) // DeletePipeline defines a function that deletes an existing pipeline. DeletePipeline(*library.Pipeline) error // GetPipeline defines a function that gets a pipeline by ID. @@ -43,5 +43,5 @@ type PipelineInterface interface { // ListPipelinesForRepo defines a function that gets a list of pipelines by repo ID. ListPipelinesForRepo(*library.Repo, int, int) ([]*library.Pipeline, int64, error) // UpdatePipeline defines a function that updates an existing pipeline. - UpdatePipeline(*library.Pipeline) error + UpdatePipeline(*library.Pipeline) (*library.Pipeline, error) } diff --git a/database/pipeline/list_repo_test.go b/database/pipeline/list_repo_test.go index c1eaef193..dc64e8a0f 100644 --- a/database/pipeline/list_repo_test.go +++ b/database/pipeline/list_repo_test.go @@ -53,12 +53,12 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(_pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(_pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/list_test.go b/database/pipeline/list_test.go index bcd5dcef5..36f65199d 100644 --- a/database/pipeline/list_test.go +++ b/database/pipeline/list_test.go @@ -53,12 +53,12 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(_pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(_pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } diff --git a/database/pipeline/update.go b/database/pipeline/update.go index 85add5411..59b552164 100644 --- a/database/pipeline/update.go +++ b/database/pipeline/update.go @@ -12,7 +12,7 @@ import ( ) // UpdatePipeline updates an existing pipeline in the database. -func (e *engine) UpdatePipeline(p *library.Pipeline) error { +func (e *engine) UpdatePipeline(p *library.Pipeline) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "pipeline": p.GetCommit(), }).Tracef("updating pipeline %s in the database", p.GetCommit()) @@ -27,7 +27,7 @@ func (e *engine) UpdatePipeline(p *library.Pipeline) error { // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Validate err := pipeline.Validate() if err != nil { - return err + return nil, err } // compress data for the pipeline @@ -35,12 +35,20 @@ func (e *engine) UpdatePipeline(p *library.Pipeline) error { // https://pkg.go.dev/github.com/go-vela/types/database#Pipeline.Compress err = pipeline.Compress(e.config.CompressionLevel) if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TablePipeline). - Save(pipeline). - Error + err = e.client.Table(constants.TablePipeline).Save(pipeline).Error + if err != nil { + return nil, err + } + + // decompress pipeline to return + err = pipeline.Decompress() + if err != nil { + return nil, err + } + + return pipeline.ToLibrary(), nil } diff --git a/database/pipeline/update_test.go b/database/pipeline/update_test.go index 33e18d738..d321d63b5 100644 --- a/database/pipeline/update_test.go +++ b/database/pipeline/update_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -19,6 +20,7 @@ func TestPipeline_Engine_UpdatePipeline(t *testing.T) { _pipeline.SetRef("refs/heads/master") _pipeline.SetType("yaml") _pipeline.SetVersion("1") + _pipeline.SetData([]byte{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -33,7 +35,7 @@ WHERE "id" = $15`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(_pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -59,7 +61,7 @@ WHERE "id" = $15`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdatePipeline(_pipeline) + got, err := test.database.UpdatePipeline(_pipeline) if test.failure { if err == nil { @@ -72,6 +74,10 @@ WHERE "id" = $15`). if err != nil { t.Errorf("UpdatePipeline for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _pipeline) { + t.Errorf("UpdatePipeline for %s returned %s, want %s", test.name, got, _pipeline) + } }) } } diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index 4618524fd..a7c76c892 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -108,7 +108,7 @@ func TestPipeline_Establish(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreatePipeline(want) + _, _ = db.CreatePipeline(want) // setup context gin.SetMode(gin.TestMode) From e06d557dd12cb1c6477b7403d7815f091cf25e51 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:56:55 -0500 Subject: [PATCH 262/298] fix(deps): update deps (patch) (#835) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 29 +++++++++++------------ go.sum | 72 +++++++++++++++++++++++++--------------------------------- 2 files changed, 46 insertions(+), 55 deletions(-) diff --git a/go.mod b/go.mod index be974371f..445f5c13c 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/adhocore/gronx v1.6.2 - github.com/alicebob/miniredis/v2 v2.30.2 - github.com/aws/aws-sdk-go v1.44.248 + github.com/adhocore/gronx v1.6.3 + github.com/alicebob/miniredis/v2 v2.30.3 + github.com/aws/aws-sdk-go v1.44.281 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 @@ -22,23 +22,23 @@ require ( github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-retryablehttp v0.7.2 - github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/hashicorp/vault/api v1.9.2 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.15.0 - github.com/redis/go-redis/v9 v9.0.3 - github.com/sirupsen/logrus v1.9.0 + github.com/prometheus/client_golang v1.15.1 + github.com/redis/go-redis/v9 v9.0.5 + github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 - github.com/urfave/cli/v2 v2.25.1 + github.com/urfave/cli/v2 v2.25.6 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 golang.org/x/oauth2 v0.7.0 golang.org/x/sync v0.1.0 gopkg.in/square/go-jose.v2 v2.6.0 - gorm.io/driver/postgres v1.5.0 + gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.4.4 - gorm.io/gorm v1.25.0 - k8s.io/apimachinery v0.27.1 + gorm.io/gorm v1.25.1 + k8s.io/apimachinery v0.27.2 ) require ( @@ -59,6 +59,7 @@ require ( github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -80,7 +81,7 @@ require ( github.com/imdario/mergo v0.3.11 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.3.0 // indirect + github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -113,7 +114,7 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.8.0 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect diff --git a/go.sum b/go.sum index 3b4b80685..e705f7c03 100644 --- a/go.sum +++ b/go.sum @@ -57,17 +57,17 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/adhocore/gronx v1.6.2 h1:/Pg6cuHFJmUGRIYWhRFjb6iL9fdzNmoMPj+/r6L01KU= -github.com/adhocore/gronx v1.6.2/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= +github.com/adhocore/gronx v1.6.3 h1:bnm5vieTrY3QQPpsfB0hrAaeaHDpuZTUC2LLCVMLe9c= +github.com/adhocore/gronx v1.6.3/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.30.2 h1:lc1UAUT9ZA7h4srlfBmBt2aorm5Yftk9nBjxz7EyY9I= -github.com/alicebob/miniredis/v2 v2.30.2/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= +github.com/alicebob/miniredis/v2 v2.30.3 h1:hrqDB4cHFSHQf4gO3xu6YKQg8PqJpNjLYsQAFYHstqw= +github.com/alicebob/miniredis/v2 v2.30.3/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.248 h1:GvkxpgsxqNc03LmhXiaxKpzbyxndnex7V+OThLx4g5M= -github.com/aws/aws-sdk-go v1.44.248/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.281 h1:z/ptheJvINaIAsKXthxONM+toTKw2pxyk700Hfm6yUw= +github.com/aws/aws-sdk-go v1.44.281/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -100,7 +100,6 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -126,6 +125,8 @@ github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH8 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -233,8 +234,8 @@ github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= @@ -248,8 +249,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= -github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= +github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -260,9 +261,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA= -github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= -github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -284,13 +284,10 @@ github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBF github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= @@ -336,8 +333,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= -github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= @@ -345,10 +342,9 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/redis/go-redis/v9 v9.0.3 h1:+7mmR26M0IvyLxGZUHxu4GiBkJkVDid0Un+j4ScYu4k= -github.com/redis/go-redis/v9 v9.0.3/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -358,8 +354,8 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= @@ -381,8 +377,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw= -github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.25.6 h1:yuSkgDSZfH3L1CjF2/5fNNg2KbM47pY2EvjBq4ESQnU= +github.com/urfave/cli/v2 v2.25.6/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -407,15 +403,15 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -485,7 +481,6 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -557,7 +552,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -565,7 +559,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -575,7 +568,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -733,7 +725,6 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -745,14 +736,13 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= -gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.0 h1:+KtYtb2roDz14EQe4bla8CbQlmb9dN3VejSai3lprfU= -gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= +gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -760,8 +750,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= -k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= +k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= +k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= From e17c9710cc42276759564c40f894c318738fa460 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 15 Jun 2023 10:07:37 -0600 Subject: [PATCH 263/298] refactor(database): return build object on created and updated (#884) * refactor(database): return build object on created and updated * address feedback --- api/admin/build.go | 4 ++-- api/build/cancel.go | 2 +- api/build/clean.go | 2 +- api/build/plan.go | 11 +---------- api/build/publish.go | 2 +- api/build/update.go | 5 +---- api/webhook/post.go | 2 +- database/build/clean_test.go | 8 ++++---- database/build/count_deployment_test.go | 4 ++-- database/build/count_org_test.go | 4 ++-- database/build/count_repo_test.go | 4 ++-- database/build/count_status_test.go | 4 ++-- database/build/count_test.go | 4 ++-- database/build/create.go | 14 ++++++++------ database/build/create_test.go | 7 ++++++- database/build/delete_test.go | 2 +- database/build/get_repo_test.go | 2 +- database/build/get_test.go | 2 +- database/build/interface.go | 4 ++-- database/build/last_repo_test.go | 2 +- database/build/list_deployment_test.go | 4 ++-- database/build/list_org_test.go | 4 ++-- database/build/list_pending_running_test.go | 4 ++-- database/build/list_repo_test.go | 4 ++-- database/build/list_test.go | 4 ++-- database/build/update.go | 14 ++++++++------ database/build/update_test.go | 9 +++++++-- router/middleware/build/build_test.go | 2 +- router/middleware/perm/perm_test.go | 14 +++++++------- router/middleware/service/service_test.go | 8 ++++---- router/middleware/step/step_test.go | 8 ++++---- 31 files changed, 83 insertions(+), 81 deletions(-) diff --git a/api/admin/build.go b/api/admin/build.go index 71a343e88..0666c2fad 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -116,7 +116,7 @@ func UpdateBuild(c *gin.Context) { } // send API call to update the build - err = database.FromContext(c).UpdateBuild(input) + b, err := database.FromContext(c).UpdateBuild(input) if err != nil { retErr := fmt.Errorf("unable to update build %d: %w", input.GetID(), err) @@ -125,5 +125,5 @@ func UpdateBuild(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, b) } diff --git a/api/build/cancel.go b/api/build/cancel.go index ff63a698d..350573911 100644 --- a/api/build/cancel.go +++ b/api/build/cancel.go @@ -190,7 +190,7 @@ func CancelBuild(c *gin.Context) { // update the status in the build table b.SetStatus(constants.StatusCanceled) - err := database.FromContext(c).UpdateBuild(b) + b, err := database.FromContext(c).UpdateBuild(b) if err != nil { retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/api/build/clean.go b/api/build/clean.go index 02c37550c..6fc0ba10b 100644 --- a/api/build/clean.go +++ b/api/build/clean.go @@ -25,7 +25,7 @@ func CleanBuild(database database.Interface, b *library.Build, services []*libra b.SetFinished(time.Now().UTC().Unix()) // send API call to update the build - err := database.UpdateBuild(b) + b, err := database.UpdateBuild(b) if err != nil { logrus.Errorf("unable to kill build %d: %v", b.GetNumber(), err) } diff --git a/api/build/plan.go b/api/build/plan.go index 5790ce4a5..eff7aa630 100644 --- a/api/build/plan.go +++ b/api/build/plan.go @@ -26,11 +26,10 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, // send API call to create the build // TODO: return created build and error instead of just error - err := database.CreateBuild(b) + b, err := database.CreateBuild(b) if err != nil { // clean up the objects from the pipeline in the database // TODO: - // - return build in CreateBuild // - even if it was created, we need to get the new build id // otherwise it will be 0, which attempts to INSERT instead // of UPDATE-ing the existing build - which results in @@ -41,14 +40,6 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) } - // send API call to capture the created build - // TODO: this can be dropped once we return - // the created build above - b, err = database.GetBuildForRepo(r, b.GetNumber()) - if err != nil { - return fmt.Errorf("unable to get new build for %s: %w", r.GetFullName(), err) - } - // plan all services for the build services, err := service.PlanServices(database, p, b) if err != nil { diff --git a/api/build/publish.go b/api/build/publish.go index f126b8471..a74bc265c 100644 --- a/api/build/publish.go +++ b/api/build/publish.go @@ -67,7 +67,7 @@ func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Buil b.SetEnqueued(time.Now().UTC().Unix()) // update the build in the db to reflect the time it was enqueued - err = db.UpdateBuild(b) + _, err = db.UpdateBuild(b) if err != nil { logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", b.GetNumber(), r.GetFullName(), err) } diff --git a/api/build/update.go b/api/build/update.go index f9d3341fa..8dde2cd77 100644 --- a/api/build/update.go +++ b/api/build/update.go @@ -151,7 +151,7 @@ func UpdateBuild(c *gin.Context) { } // send API call to update the build - err = database.FromContext(c).UpdateBuild(b) + b, err = database.FromContext(c).UpdateBuild(b) if err != nil { retErr := fmt.Errorf("unable to update build %s: %w", entry, err) @@ -160,9 +160,6 @@ func UpdateBuild(c *gin.Context) { return } - // send API call to capture the updated build - b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) - c.JSON(http.StatusOK, b) // check if the build is in a "final" state diff --git a/api/webhook/post.go b/api/webhook/post.go index 2832941dc..c4670d8ea 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -893,7 +893,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, dbR.GetFullName(), build.GetNumber()), ) - err = database.FromContext(c).UpdateBuild(build) + _, err = database.FromContext(c).UpdateBuild(build) if err != nil { return nil, fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err) } diff --git a/database/build/clean_test.go b/database/build/clean_test.go index ab91da075..05b606b3f 100644 --- a/database/build/clean_test.go +++ b/database/build/clean_test.go @@ -54,22 +54,22 @@ func TestBuild_Engine_CleanBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildThree) + _, err = _sqlite.CreateBuild(_buildThree) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildFour) + _, err = _sqlite.CreateBuild(_buildFour) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/count_deployment_test.go b/database/build/count_deployment_test.go index 53c0c1df6..611ca6247 100644 --- a/database/build/count_deployment_test.go +++ b/database/build/count_deployment_test.go @@ -44,12 +44,12 @@ func TestBuild_Engine_CountBuildsForDeployment(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/count_org_test.go b/database/build/count_org_test.go index 429149e54..d2c2b2c4d 100644 --- a/database/build/count_org_test.go +++ b/database/build/count_org_test.go @@ -67,12 +67,12 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/count_repo_test.go b/database/build/count_repo_test.go index 673887183..313dcba70 100644 --- a/database/build/count_repo_test.go +++ b/database/build/count_repo_test.go @@ -46,12 +46,12 @@ func TestBuild_Engine_CountBuildsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/count_status_test.go b/database/build/count_status_test.go index f88759d1c..34c7ce525 100644 --- a/database/build/count_status_test.go +++ b/database/build/count_status_test.go @@ -39,12 +39,12 @@ func TestBuild_Engine_CountBuildsForStatus(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/count_test.go b/database/build/count_test.go index 6254648ee..f63e1430b 100644 --- a/database/build/count_test.go +++ b/database/build/count_test.go @@ -37,12 +37,12 @@ func TestBuild_Engine_CountBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/create.go b/database/build/create.go index 911c6f148..52c425e9f 100644 --- a/database/build/create.go +++ b/database/build/create.go @@ -13,7 +13,7 @@ import ( ) // CreateBuild creates a new build in the database. -func (e *engine) CreateBuild(b *library.Build) error { +func (e *engine) CreateBuild(b *library.Build) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("creating build %d in the database", b.GetNumber()) @@ -28,12 +28,14 @@ func (e *engine) CreateBuild(b *library.Build) error { // https://pkg.go.dev/github.com/go-vela/types/database#Build.Validate err := build.Validate() if err != nil { - return err + return nil, err } + // crop build if any columns are too large + build = build.Crop() + // send query to the database - return e.client. - Table(constants.TableBuild). - Create(build.Crop()). - Error + result := e.client.Table(constants.TableBuild).Create(build) + + return build.ToLibrary(), result.Error } diff --git a/database/build/create_test.go b/database/build/create_test.go index 3cfe1fdf9..d6051c2dd 100644 --- a/database/build/create_test.go +++ b/database/build/create_test.go @@ -5,6 +5,7 @@ package build import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -55,7 +56,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateBuild(_build) + got, err := test.database.CreateBuild(_build) if test.failure { if err == nil { @@ -68,6 +69,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ if err != nil { t.Errorf("CreateBuild for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _build) { + t.Errorf("CreateBuild for %s returned %s, want %s", test.name, got, _build) + } }) } } diff --git a/database/build/delete_test.go b/database/build/delete_test.go index 91dd1c9c7..252912b23 100644 --- a/database/build/delete_test.go +++ b/database/build/delete_test.go @@ -29,7 +29,7 @@ func TestBuild_Engine_DeleteBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(_build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/get_repo_test.go b/database/build/get_repo_test.go index f1341d960..92f86bd0c 100644 --- a/database/build/get_repo_test.go +++ b/database/build/get_repo_test.go @@ -43,7 +43,7 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(_build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/get_test.go b/database/build/get_test.go index 7aec15f13..21ea19f94 100644 --- a/database/build/get_test.go +++ b/database/build/get_test.go @@ -34,7 +34,7 @@ func TestBuild_Engine_GetBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(_build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/interface.go b/database/build/interface.go index 6a14ad4f8..6d05fa48b 100644 --- a/database/build/interface.go +++ b/database/build/interface.go @@ -39,7 +39,7 @@ type BuildInterface interface { // CountBuildsForStatus defines a function that gets the count of builds by status. CountBuildsForStatus(string, map[string]interface{}) (int64, error) // CreateBuild defines a function that creates a new build. - CreateBuild(*library.Build) error + CreateBuild(*library.Build) (*library.Build, error) // DeleteBuild defines a function that deletes an existing build. DeleteBuild(*library.Build) error // GetBuild defines a function that gets a build by ID. @@ -59,5 +59,5 @@ type BuildInterface interface { // ListPendingAndRunningBuilds defines a function that gets a list of pending and running builds. ListPendingAndRunningBuilds(string) ([]*library.BuildQueue, error) // UpdateBuild defines a function that updates an existing build. - UpdateBuild(*library.Build) error + UpdateBuild(*library.Build) (*library.Build, error) } diff --git a/database/build/last_repo_test.go b/database/build/last_repo_test.go index 48cb32c01..853c21711 100644 --- a/database/build/last_repo_test.go +++ b/database/build/last_repo_test.go @@ -44,7 +44,7 @@ func TestBuild_Engine_LastBuildForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(_build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/list_deployment_test.go b/database/build/list_deployment_test.go index 94983c56e..53b984bba 100644 --- a/database/build/list_deployment_test.go +++ b/database/build/list_deployment_test.go @@ -54,12 +54,12 @@ func TestBuild_Engine_ListBuildsForDeployment(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/list_org_test.go b/database/build/list_org_test.go index e9121e024..4e2ac91aa 100644 --- a/database/build/list_org_test.go +++ b/database/build/list_org_test.go @@ -94,12 +94,12 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/list_pending_running_test.go b/database/build/list_pending_running_test.go index 8d47dc63b..3b3aa4d3e 100644 --- a/database/build/list_pending_running_test.go +++ b/database/build/list_pending_running_test.go @@ -65,12 +65,12 @@ func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/list_repo_test.go b/database/build/list_repo_test.go index ac367e414..f2ccbbe9e 100644 --- a/database/build/list_repo_test.go +++ b/database/build/list_repo_test.go @@ -59,12 +59,12 @@ func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/list_test.go b/database/build/list_test.go index b0e441387..958025b09 100644 --- a/database/build/list_test.go +++ b/database/build/list_test.go @@ -47,12 +47,12 @@ func TestBuild_Engine_ListBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(_buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(_buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } diff --git a/database/build/update.go b/database/build/update.go index d16329419..ad5c6087f 100644 --- a/database/build/update.go +++ b/database/build/update.go @@ -13,7 +13,7 @@ import ( ) // UpdateBuild updates an existing build in the database. -func (e *engine) UpdateBuild(b *library.Build) error { +func (e *engine) UpdateBuild(b *library.Build) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("updating build %d in the database", b.GetNumber()) @@ -28,12 +28,14 @@ func (e *engine) UpdateBuild(b *library.Build) error { // https://pkg.go.dev/github.com/go-vela/types/database#Build.Validate err := build.Validate() if err != nil { - return err + return nil, err } + // crop build if any columns are too large + build = build.Crop() + // send query to the database - return e.client. - Table(constants.TableBuild). - Save(build.Crop()). - Error + result := e.client.Table(constants.TableBuild).Save(build) + + return build.ToLibrary(), result.Error } diff --git a/database/build/update_test.go b/database/build/update_test.go index 98ac9ae16..21b2d1d5a 100644 --- a/database/build/update_test.go +++ b/database/build/update_test.go @@ -5,6 +5,7 @@ package build import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -31,7 +32,7 @@ WHERE "id" = $31`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(_build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -57,7 +58,7 @@ WHERE "id" = $31`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateBuild(_build) + got, err := test.database.UpdateBuild(_build) if test.failure { if err == nil { @@ -70,6 +71,10 @@ WHERE "id" = $31`). if err != nil { t.Errorf("UpdateBuild for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _build) { + t.Errorf("UpdateBuild for %s returned %s, want %s", test.name, got, _build) + } }) } } diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 10af76ab7..d8a540b9c 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -95,7 +95,7 @@ func TestBuild_Establish(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(want) + _, _ = db.CreateBuild(want) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 34498d21d..70a88fbf8 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -448,7 +448,7 @@ func TestPerm_MustBuildAccess(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -538,7 +538,7 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -623,7 +623,7 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -707,7 +707,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/repo/foo/bar/baz", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -788,7 +788,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/org/foo/*/baz", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -869,7 +869,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/shared/foo/*/*", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -1831,7 +1831,7 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { db.Close() }() - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) _ = db.CreateRepo(r) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index 091a3e170..cd057b471 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -85,7 +85,7 @@ func TestService_Establish(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) _ = db.CreateService(want) // setup context @@ -226,7 +226,7 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) @@ -282,7 +282,7 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) @@ -338,7 +338,7 @@ func TestService_Establish_NoService(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index 2d9e7ac12..d0ad740c4 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -87,7 +87,7 @@ func TestStep_Establish(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) _ = db.CreateStep(want) // setup context @@ -228,7 +228,7 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) @@ -284,7 +284,7 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) @@ -340,7 +340,7 @@ func TestStep_Establish_NoStep(t *testing.T) { }() _ = db.CreateRepo(r) - _ = db.CreateBuild(b) + _, _ = db.CreateBuild(b) // setup context gin.SetMode(gin.TestMode) From 4e5d484be2bd4c1b9dac5303ceaace33dcf6fb39 Mon Sep 17 00:00:00 2001 From: Kelly Merrick Date: Fri, 16 Jun 2023 13:10:03 -0500 Subject: [PATCH 264/298] feat(worker-visibility): extend worker table with 5 fields (#772) --- api/metrics.go | 84 +++++++++++++++++++++++-- api/worker/update.go | 25 ++++++++ database/worker/create_test.go | 6 +- database/worker/get_hostname_test.go | 4 +- database/worker/list_test.go | 6 +- database/worker/table.go | 39 +++++++----- database/worker/update_test.go | 6 +- database/worker/worker_test.go | 19 +++--- go.mod | 10 +-- go.sum | 20 +++--- router/middleware/perm/perm.go | 9 +++ router/middleware/worker/worker_test.go | 5 ++ router/worker.go | 2 +- 13 files changed, 181 insertions(+), 54 deletions(-) diff --git a/api/metrics.go b/api/metrics.go index d005481b3..fc1a7f04f 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-vela/server/database" "github.com/go-vela/server/queue" + "github.com/go-vela/types/constants" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -56,6 +57,18 @@ type MetricsQueryParameters struct { ActiveWorkerCount bool `form:"active_worker_count"` // InactiveWorkerCount represents total number of inactive workers InactiveWorkerCount bool `form:"inactive_worker_count"` + + // IdleWorkerCount represents total number of workers with a status of idle + // where worker RunningBuildIDs.length = 0 + IdleWorkerCount bool `form:"idle_worker_count"` + // AvailableWorkerCount represents total number of workers with a status of available, + // where worker RunningBuildIDs.length > 0 and < worker BuildLimit + AvailableWorkerCount bool `form:"available_worker_count"` + // BusyWorkerCount represents total number of workers with a status of busy, + // where worker BuildLimit == worker RunningBuildIDs.length + BusyWorkerCount bool `form:"busy_worker_count"` + // ErrorWorkerCount represents total number of workers with a status of error + ErrorWorkerCount bool `form:"error_worker_count"` } // predefine Prometheus metrics else they will be regenerated @@ -180,6 +193,26 @@ var ( // description: Indicates a request for inactive worker count // type: boolean // default: false +// - in: query +// name: idle_worker_count +// description: Indicates a request for idle worker count +// type: boolean +// default: false +// - in: query +// name: available_worker_count +// description: Indicates a request for available worker count +// type: boolean +// default: false +// - in: query +// name: busy_worker_count +// description: Indicates a request for busy worker count +// type: boolean +// default: false +// - in: query +// name: error_worker_count +// description: Indicates a request for error worker count +// type: boolean +// default: false // responses: // '200': // description: Successfully retrieved the Vela metrics @@ -375,14 +408,18 @@ func recordGauges(c *gin.Context) { // add worker metrics var ( - buildLimit int64 - activeWorkers int64 - inactiveWorkers int64 + buildLimit int64 + activeWorkers int64 + inactiveWorkers int64 + idleWorkers int64 + availableWorkers int64 + busyWorkers int64 + errorWorkers int64 ) // get worker metrics based on request query parameters - // worker_build_limit, active_worker_count, inactive_worker_count - if q.WorkerBuildLimit || q.ActiveWorkerCount || q.InactiveWorkerCount { + // worker_build_limit, active_worker_count, inactive_worker_count, idle_worker_count, available_worker_count, busy_worker_count, error_worker_count + if q.WorkerBuildLimit || q.ActiveWorkerCount || q.InactiveWorkerCount || q.IdleWorkerCount || q.AvailableWorkerCount || q.BusyWorkerCount || q.ErrorWorkerCount { // send API call to capture the workers workers, err := database.FromContext(c).ListWorkers() if err != nil { @@ -391,6 +428,9 @@ func recordGauges(c *gin.Context) { // get the unix time from worker_active_interval ago before := time.Now().UTC().Add(-c.Value("worker_active_interval").(time.Duration)).Unix() + + // active, inactive counts + // idle, available, busy, error counts for _, worker := range workers { // check if the worker checked in within the last worker_active_interval if worker.GetLastCheckedIn() >= before { @@ -399,6 +439,20 @@ func recordGauges(c *gin.Context) { } else { inactiveWorkers++ } + // check if the worker checked in within the last worker_active_interval + if worker.GetLastCheckedIn() >= before { + + switch worker.GetStatus() { + case constants.WorkerStatusIdle: + idleWorkers++ + case constants.WorkerStatusAvailable: + availableWorkers++ + case constants.WorkerStatusBusy: + busyWorkers++ + case constants.WorkerStatusError: + errorWorkers++ + } + } } // apply metrics based on request query parameters @@ -416,5 +470,25 @@ func recordGauges(c *gin.Context) { if q.InactiveWorkerCount { totals.WithLabelValues("worker", "count", "inactive").Set(float64(inactiveWorkers)) } + + // idle_worker_count + if q.IdleWorkerCount { + totals.WithLabelValues("worker", "count", "idle").Set(float64(idleWorkers)) + } + + // available_worker_count + if q.AvailableWorkerCount { + totals.WithLabelValues("worker", "count", "available").Set(float64(availableWorkers)) + } + + // busy_worker_count + if q.BusyWorkerCount { + totals.WithLabelValues("worker", "count", "busy").Set(float64(busyWorkers)) + } + + // error_worker_count + if q.ErrorWorkerCount { + totals.WithLabelValues("worker", "count", "error").Set(float64(errorWorkers)) + } } } diff --git a/api/worker/update.go b/api/worker/update.go index 16d34f686..b3a8d5130 100644 --- a/api/worker/update.go +++ b/api/worker/update.go @@ -98,6 +98,31 @@ func UpdateWorker(c *gin.Context) { w.SetActive(input.GetActive()) } + if input.RunningBuildIDs != nil { + // update runningBuildIDs if set + w.SetRunningBuildIDs(input.GetRunningBuildIDs()) + } + + if len(input.GetStatus()) > 0 { + // update status if set + w.SetStatus(input.GetStatus()) + } + + if input.GetLastStatusUpdateAt() > 0 { + // update lastStatusUpdateAt if set + w.SetLastStatusUpdateAt(input.GetLastStatusUpdateAt()) + } + + if input.GetLastBuildStartedAt() > 0 { + // update lastBuildStartedAt if set + w.SetLastBuildStartedAt(input.GetLastBuildStartedAt()) + } + + if input.GetLastBuildFinishedAt() > 0 { + // update lastBuildFinishedAt if set + w.SetLastBuildFinishedAt(input.GetLastBuildFinishedAt()) + } + // send API call to update the worker err = database.FromContext(c).UpdateWorker(w) if err != nil { diff --git a/database/worker/create_test.go b/database/worker/create_test.go index 38c276d83..e4c4dc9cb 100644 --- a/database/worker/create_test.go +++ b/database/worker/create_test.go @@ -26,9 +26,9 @@ func TestWorker_Engine_CreateWorker(t *testing.T) { // ensure the mock expects the query _mock.ExpectQuery(`INSERT INTO "workers" -("hostname","address","routes","active","last_checked_in","build_limit","id") -VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`). - WithArgs("worker_0", "localhost", nil, true, nil, nil, 1). +("hostname","address","routes","active","status","last_status_update_at","running_build_ids","last_build_started_at","last_build_finished_at","last_checked_in","build_limit","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) RETURNING "id"`). + WithArgs("worker_0", "localhost", nil, true, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnRows(_rows) _sqlite := testSqlite(t) diff --git a/database/worker/get_hostname_test.go b/database/worker/get_hostname_test.go index 833afdc15..3dd1d4fe6 100644 --- a/database/worker/get_hostname_test.go +++ b/database/worker/get_hostname_test.go @@ -25,8 +25,8 @@ func TestWorker_Engine_GetWorkerForName(t *testing.T) { // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}). - AddRow(1, "worker_0", "localhost", nil, true, 0, 0) + []string{"id", "hostname", "address", "routes", "active", "status", "last_status_update_at", "running_build_ids", "last_build_started_at", "last_build_finished_at", "last_checked_in", "build_limit"}). + AddRow(1, "worker_0", "localhost", nil, true, nil, 0, nil, 0, 0, 0, 0) // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "workers" WHERE hostname = $1 LIMIT 1`).WithArgs("worker_0").WillReturnRows(_rows) diff --git a/database/worker/list_test.go b/database/worker/list_test.go index b44c9c3d9..5eed3f94f 100644 --- a/database/worker/list_test.go +++ b/database/worker/list_test.go @@ -37,9 +37,9 @@ func TestWorker_Engine_ListWorkers(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "hostname", "address", "routes", "active", "last_checked_in", "build_limit"}). - AddRow(1, "worker_0", "localhost", nil, true, 0, 0). - AddRow(2, "worker_1", "localhost", nil, true, 0, 0) + []string{"id", "hostname", "address", "routes", "active", "status", "last_status_update_at", "running_build_ids", "last_build_started_at", "last_build_finished_at", "last_checked_in", "build_limit"}). + AddRow(1, "worker_0", "localhost", nil, true, nil, 0, nil, 0, 0, 0, 0). + AddRow(2, "worker_1", "localhost", nil, true, nil, 0, nil, 0, 0, 0, 0) // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "workers"`).WillReturnRows(_rows) diff --git a/database/worker/table.go b/database/worker/table.go index 5cecf109d..1d704674a 100644 --- a/database/worker/table.go +++ b/database/worker/table.go @@ -14,29 +14,38 @@ const ( CREATE TABLE IF NOT EXISTS workers ( - id SERIAL PRIMARY KEY, - hostname VARCHAR(250), - address VARCHAR(250), - routes VARCHAR(1000), - active BOOLEAN, - last_checked_in INTEGER, - build_limit INTEGER, + id SERIAL PRIMARY KEY, + hostname VARCHAR(250), + address VARCHAR(250), + routes VARCHAR(1000), + active BOOLEAN, + status VARCHAR(50), + last_status_update_at INTEGER, + running_build_ids VARCHAR(500), + last_build_started_at INTEGER, + last_build_finished_at INTEGER, + last_checked_in INTEGER, + build_limit INTEGER, UNIQUE(hostname) ); ` - // CreateSqliteTable represents a query to create the Sqlite workers table. CreateSqliteTable = ` CREATE TABLE IF NOT EXISTS workers ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - hostname TEXT, - address TEXT, - routes TEXT, - active BOOLEAN, - last_checked_in INTEGER, - build_limit INTEGER, + id INTEGER PRIMARY KEY AUTOINCREMENT, + hostname TEXT, + address TEXT, + routes TEXT, + active BOOLEAN, + status VARCHAR(50), + last_status_update_at INTEGER, + running_build_ids VARCHAR(500), + last_build_started_at INTEGER, + last_build_finished_at INTEGER, + last_checked_in INTEGER, + build_limit INTEGER, UNIQUE(hostname) ); ` diff --git a/database/worker/update_test.go b/database/worker/update_test.go index 88644678a..0beeafa47 100644 --- a/database/worker/update_test.go +++ b/database/worker/update_test.go @@ -23,9 +23,9 @@ func TestWorker_Engine_UpdateWorker(t *testing.T) { // ensure the mock expects the query _mock.ExpectExec(`UPDATE "workers" -SET "hostname"=$1,"address"=$2,"routes"=$3,"active"=$4,"last_checked_in"=$5,"build_limit"=$6 -WHERE "id" = $7`). - WithArgs("worker_0", "localhost", nil, true, nil, nil, 1). +SET "hostname"=$1,"address"=$2,"routes"=$3,"active"=$4,"status"=$5,"last_status_update_at"=$6,"running_build_ids"=$7,"last_build_started_at"=$8,"last_build_finished_at"=$9,"last_checked_in"=$10,"build_limit"=$11 +WHERE "id" = $12`). + WithArgs("worker_0", "localhost", nil, true, nil, nil, nil, nil, nil, nil, nil, 1). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) diff --git a/database/worker/worker_test.go b/database/worker/worker_test.go index 48deabe54..00096c2a9 100644 --- a/database/worker/worker_test.go +++ b/database/worker/worker_test.go @@ -170,12 +170,17 @@ func testSqlite(t *testing.T) *engine { // Worker type with all fields set to their zero values. func testWorker() *library.Worker { return &library.Worker{ - ID: new(int64), - Hostname: new(string), - Address: new(string), - Routes: new([]string), - Active: new(bool), - BuildLimit: new(int64), - LastCheckedIn: new(int64), + ID: new(int64), + Hostname: new(string), + Address: new(string), + Routes: new([]string), + Active: new(bool), + Status: new(string), + LastStatusUpdateAt: new(int64), + RunningBuildIDs: new([]string), + LastBuildStartedAt: new(int64), + LastBuildFinishedAt: new(int64), + LastCheckedIn: new(int64), + BuildLimit: new(int64), } } diff --git a/go.mod b/go.mod index 445f5c13c..1e284d4f4 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.0 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c + github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v52 v52.0.0 @@ -88,12 +88,12 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.8 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microcosm-cc/bluemonday v1.0.23 // indirect + github.com/microcosm-cc/bluemonday v1.0.24 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -115,8 +115,8 @@ require ( github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/crypto v0.8.0 // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index e705f7c03..3f90f092b 100644 --- a/go.sum +++ b/go.sum @@ -139,8 +139,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c h1:eAApIK5e5MxFF8RzZAFsvTSdwq/AzdUrdhJHOGQ0ILc= -github.com/go-vela/types v0.19.3-0.20230523200921-35a0d5fc088c/go.mod h1:0lsuPfGyVyTWJSi2h3NS6uaEW6DgnFvIzaZu1sXYKrs= +github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af h1:Ixsa6Ha0j9Edq4v3IooDgyUoGSp08fk9FgrYKuZSML8= +github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -290,8 +290,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= -github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -306,8 +306,8 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= -github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= +github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw= +github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -481,8 +481,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -552,8 +552,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index 812c9a8fd..da4c18013 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -100,6 +100,15 @@ func MustWorkerAuthToken() gin.HandlerFunc { "worker": cl.Subject, }).Debugf("verifying worker %s has a valid auth token", cl.Subject) + // global permissions bypass + if cl.IsAdmin { + logrus.WithFields(logrus.Fields{ + "user": cl.Subject, + }).Debugf("user %s has platform admin permissions", cl.Subject) + + return + } + switch cl.TokenType { case constants.WorkerAuthTokenType, constants.WorkerRegisterTokenType: return diff --git a/router/middleware/worker/worker_test.go b/router/middleware/worker/worker_test.go index 1cfeadfc7..58d090825 100644 --- a/router/middleware/worker/worker_test.go +++ b/router/middleware/worker/worker_test.go @@ -41,6 +41,11 @@ func TestWorker_Establish(t *testing.T) { want.SetAddress("localhost") want.SetRoutes([]string{"foo", "bar", "baz"}) want.SetActive(true) + want.SetStatus("available") + want.SetLastStatusUpdateAt(12345) + want.SetRunningBuildIDs([]string{}) + want.SetLastBuildStartedAt(12345) + want.SetLastBuildFinishedAt(12345) want.SetLastCheckedIn(12345) want.SetBuildLimit(0) diff --git a/router/worker.go b/router/worker.go index 7bb114c69..f85a84c45 100644 --- a/router/worker.go +++ b/router/worker.go @@ -32,7 +32,7 @@ func WorkerHandlers(base *gin.RouterGroup) { _worker := _workers.Group("/:worker") { _worker.GET("", wmiddleware.Establish(), worker.GetWorker) - _worker.PUT("", perm.MustPlatformAdmin(), wmiddleware.Establish(), worker.UpdateWorker) + _worker.PUT("", perm.MustWorkerAuthToken(), wmiddleware.Establish(), worker.UpdateWorker) _worker.POST("/refresh", perm.MustWorkerAuthToken(), wmiddleware.Establish(), worker.Refresh) _worker.DELETE("", perm.MustPlatformAdmin(), wmiddleware.Establish(), worker.DeleteWorker) } // end of worker endpoints From ef7d338bd36a9792f8aa7ea7023830026af2540a Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Tue, 20 Jun 2023 11:09:57 -0500 Subject: [PATCH 265/298] feat(database): add engine options (#886) --- database/close.go | 4 +- database/close_test.go | 6 +- database/context.go | 20 +- database/database.go | 79 +++++--- database/database_test.go | 35 ++-- database/driver.go | 2 +- database/opts.go | 90 +++++++++ database/opts_test.go | 409 ++++++++++++++++++++++++++++++++++++++ database/ping.go | 6 +- database/ping_test.go | 6 +- database/resource.go | 76 +++---- database/validate.go | 2 +- database/validate_test.go | 20 +- 13 files changed, 639 insertions(+), 116 deletions(-) create mode 100644 database/opts.go create mode 100644 database/opts_test.go diff --git a/database/close.go b/database/close.go index 0596b972e..0aff8e51d 100644 --- a/database/close.go +++ b/database/close.go @@ -6,10 +6,10 @@ package database // Close stops and terminates the connection to the database. func (e *engine) Close() error { - e.Logger.Tracef("closing connection to the %s database", e.Driver()) + e.logger.Tracef("closing connection to the %s database", e.Driver()) // capture database/sql database from gorm.io/gorm database - _sql, err := e.Database.DB() + _sql, err := e.client.DB() if err != nil { return err } diff --git a/database/close_test.go b/database/close_test.go index b555e78d5..fe0c55b00 100644 --- a/database/close_test.go +++ b/database/close_test.go @@ -49,15 +49,15 @@ func TestDatabase_Engine_Close(t *testing.T) { name: "failure with invalid gorm database", failure: true, database: &engine{ - Config: &Config{ + config: &config{ Driver: "invalid", }, - Database: &gorm.DB{ + client: &gorm.DB{ Config: &gorm.Config{ ConnPool: nil, }, }, - Logger: logrus.NewEntry(logrus.StandardLogger()), + logger: logrus.NewEntry(logrus.StandardLogger()), }, }, } diff --git a/database/context.go b/database/context.go index d27d73550..fd08cc371 100644 --- a/database/context.go +++ b/database/context.go @@ -43,14 +43,14 @@ func ToContext(c Setter, d Interface) { func FromCLIContext(c *cli.Context) (Interface, error) { logrus.Debug("creating database engine from CLI configuration") - return New(&Config{ - Address: c.String("database.addr"), - CompressionLevel: c.Int("database.compression.level"), - ConnectionLife: c.Duration("database.connection.life"), - ConnectionIdle: c.Int("database.connection.idle"), - ConnectionOpen: c.Int("database.connection.open"), - Driver: c.String("database.driver"), - EncryptionKey: c.String("database.encryption.key"), - SkipCreation: c.Bool("database.skip_creation"), - }) + return New( + WithAddress(c.String("database.addr")), + WithCompressionLevel(c.Int("database.compression.level")), + WithConnectionLife(c.Duration("database.connection.life")), + WithConnectionIdle(c.Int("database.connection.idle")), + WithConnectionOpen(c.Int("database.connection.open")), + WithDriver(c.String("database.driver")), + WithEncryptionKey(c.String("database.encryption.key")), + WithSkipCreation(c.Bool("database.skip_creation")), + ) } diff --git a/database/database.go b/database/database.go index 5fe3de951..c612ba3aa 100644 --- a/database/database.go +++ b/database/database.go @@ -28,8 +28,8 @@ import ( ) type ( - // Config represents the settings required to create the engine that implements the Interface. - Config struct { + // config represents the settings required to create the engine that implements the Interface. + config struct { // specifies the address to use for the database engine Address string // specifies the level of compression to use for the database engine @@ -50,9 +50,12 @@ type ( // engine represents the functionality that implements the Interface. engine struct { - Config *Config - Database *gorm.DB - Logger *logrus.Entry + // gorm.io/gorm database client used in database functions + client *gorm.DB + // engine configuration settings used in database functions + config *config + // sirupsen/logrus logger used in database functions + logger *logrus.Entry build.BuildInterface hook.HookInterface @@ -74,52 +77,64 @@ type ( // // * postgres // * sqlite3 -func New(c *Config) (Interface, error) { +func New(opts ...EngineOpt) (Interface, error) { + // create new database engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + // validate the configuration being provided - err := c.Validate() + err := e.config.Validate() if err != nil { return nil, err } - // create new database engine - e := &engine{ - Config: c, - Database: new(gorm.DB), - Logger: logrus.NewEntry(logrus.StandardLogger()).WithField("database", c.Driver), - } + // update the logger with additional metadata + e.logger = logrus.NewEntry(logrus.StandardLogger()).WithField("database", e.Driver()) - e.Logger.Trace("creating database engine from configuration") + e.logger.Trace("creating database engine from configuration") // process the database driver being provided - switch c.Driver { + switch e.config.Driver { case constants.DriverPostgres: // create the new Postgres database client - e.Database, err = gorm.Open(postgres.Open(e.Config.Address), &gorm.Config{}) + e.client, err = gorm.Open(postgres.Open(e.config.Address), &gorm.Config{}) if err != nil { return nil, err } case constants.DriverSqlite: // create the new Sqlite database client - e.Database, err = gorm.Open(sqlite.Open(e.Config.Address), &gorm.Config{}) + e.client, err = gorm.Open(sqlite.Open(e.config.Address), &gorm.Config{}) if err != nil { return nil, err } default: // handle an invalid database driver being provided - return nil, fmt.Errorf("invalid database driver provided: %s", c.Driver) + return nil, fmt.Errorf("invalid database driver provided: %s", e.Driver()) } // capture database/sql database from gorm.io/gorm database - db, err := e.Database.DB() + db, err := e.client.DB() if err != nil { return nil, err } // set the maximum amount of time a connection may be reused - db.SetConnMaxLifetime(e.Config.ConnectionLife) + db.SetConnMaxLifetime(e.config.ConnectionLife) // set the maximum number of connections in the idle connection pool - db.SetMaxIdleConns(e.Config.ConnectionIdle) + db.SetMaxIdleConns(e.config.ConnectionIdle) // set the maximum number of open connections to the database - db.SetMaxOpenConns(e.Config.ConnectionOpen) + db.SetMaxOpenConns(e.config.ConnectionOpen) // verify connection to the database err = e.Ping() @@ -140,14 +155,14 @@ func New(c *Config) (Interface, error) { // // This function is ONLY intended to be used for testing purposes. func NewTest() (Interface, error) { - return New(&Config{ - Address: "file::memory:?cache=shared", - CompressionLevel: 3, - ConnectionLife: 30 * time.Minute, - ConnectionIdle: 2, - ConnectionOpen: 0, - Driver: "sqlite3", - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }) + return New( + WithAddress("file::memory:?cache=shared"), + WithCompressionLevel(3), + WithConnectionLife(30*time.Minute), + WithConnectionIdle(2), + WithConnectionOpen(0), + WithDriver("sqlite3"), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithSkipCreation(false), + ) } diff --git a/database/database_test.go b/database/database_test.go index 6d18421bc..a1cfecc8a 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -21,12 +21,12 @@ func TestDatabase_New(t *testing.T) { tests := []struct { failure bool name string - config *Config + config *config }{ { name: "failure with postgres", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -40,7 +40,7 @@ func TestDatabase_New(t *testing.T) { { name: "success with sqlite3", failure: false, - config: &Config{ + config: &config{ Driver: "sqlite3", Address: "file::memory:?cache=shared", CompressionLevel: 3, @@ -54,7 +54,7 @@ func TestDatabase_New(t *testing.T) { { name: "failure with invalid config", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "", CompressionLevel: 3, @@ -68,7 +68,7 @@ func TestDatabase_New(t *testing.T) { { name: "failure with invalid driver", failure: true, - config: &Config{ + config: &config{ Driver: "mysql", Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local", CompressionLevel: 3, @@ -84,7 +84,16 @@ func TestDatabase_New(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - _, err := New(test.config) + _, err := New( + WithAddress(test.config.Address), + WithCompressionLevel(test.config.CompressionLevel), + WithConnectionLife(test.config.ConnectionLife), + WithConnectionIdle(test.config.ConnectionIdle), + WithConnectionOpen(test.config.ConnectionOpen), + WithDriver(test.config.Driver), + WithEncryptionKey(test.config.EncryptionKey), + WithSkipCreation(test.config.SkipCreation), + ) if test.failure { if err == nil { @@ -105,7 +114,7 @@ func TestDatabase_New(t *testing.T) { func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { // create the engine with test configuration _engine := &engine{ - Config: &Config{ + config: &config{ CompressionLevel: 3, ConnectionLife: 30 * time.Minute, ConnectionIdle: 2, @@ -114,7 +123,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false, }, - Logger: logrus.NewEntry(logrus.StandardLogger()), + logger: logrus.NewEntry(logrus.StandardLogger()), } // create the new mock sql database @@ -129,7 +138,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { _mock.ExpectPing() // create the new mock Postgres database client - _engine.Database, err = gorm.Open( + _engine.client, err = gorm.Open( postgres.New(postgres.Config{Conn: _sql}), &gorm.Config{SkipDefaultTransaction: true}, ) @@ -146,7 +155,7 @@ func testSqlite(t *testing.T) *engine { // create the engine with test configuration _engine := &engine{ - Config: &Config{ + config: &config{ Address: "file::memory:?cache=shared", CompressionLevel: 3, ConnectionLife: 30 * time.Minute, @@ -156,12 +165,12 @@ func testSqlite(t *testing.T) *engine { EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", SkipCreation: false, }, - Logger: logrus.NewEntry(logrus.StandardLogger()), + logger: logrus.NewEntry(logrus.StandardLogger()), } // create the new mock Sqlite database client - _engine.Database, err = gorm.Open( - sqlite.Open(_engine.Config.Address), + _engine.client, err = gorm.Open( + sqlite.Open(_engine.config.Address), &gorm.Config{SkipDefaultTransaction: true}, ) if err != nil { diff --git a/database/driver.go b/database/driver.go index a81662846..1c3130094 100644 --- a/database/driver.go +++ b/database/driver.go @@ -6,5 +6,5 @@ package database // Driver outputs the configured database driver. func (e *engine) Driver() string { - return e.Config.Driver + return e.config.Driver } diff --git a/database/opts.go b/database/opts.go new file mode 100644 index 000000000..3714989c5 --- /dev/null +++ b/database/opts.go @@ -0,0 +1,90 @@ +// 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 "time" + +// EngineOpt represents a configuration option to initialize the database engine. +type EngineOpt func(*engine) error + +// WithAddress sets the address in the database engine. +func WithAddress(address string) EngineOpt { + return func(e *engine) error { + // set the fully qualified connection string in the database engine + e.config.Address = address + + return nil + } +} + +// WithCompressionLevel sets the compression level in the database engine. +func WithCompressionLevel(level int) EngineOpt { + return func(e *engine) error { + // set the level of compression for resources in the database engine + e.config.CompressionLevel = level + + return nil + } +} + +// WithConnectionLife sets the life of connections in the database engine. +func WithConnectionLife(connectionLife time.Duration) EngineOpt { + return func(e *engine) error { + // set the maximum duration of time for connection in the database engine + e.config.ConnectionLife = connectionLife + + return nil + } +} + +// WithConnectionIdle sets the idle connections in the database engine. +func WithConnectionIdle(connectionIdle int) EngineOpt { + return func(e *engine) error { + // set the maximum allowed idle connections in the database engine + e.config.ConnectionIdle = connectionIdle + + return nil + } +} + +// WithConnectionOpen sets the open connections in the database engine. +func WithConnectionOpen(connectionOpen int) EngineOpt { + return func(e *engine) error { + // set the maximum allowed open connections in the database engine + e.config.ConnectionOpen = connectionOpen + + return nil + } +} + +// WithDriver sets the driver in the database engine. +func WithDriver(driver string) EngineOpt { + return func(e *engine) error { + // set the database type to interact with in the database engine + e.config.Driver = driver + + return nil + } +} + +// WithEncryptionKey sets the encryption key in the database engine. +func WithEncryptionKey(encryptionKey string) EngineOpt { + return func(e *engine) error { + // set the key for encrypting resources in the database engine + e.config.EncryptionKey = encryptionKey + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the database engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/opts_test.go b/database/opts_test.go new file mode 100644 index 000000000..446fd5903 --- /dev/null +++ b/database/opts_test.go @@ -0,0 +1,409 @@ +// 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 ( + "reflect" + "testing" + "time" +) + +func TestDatabase_EngineOpt_WithAddress(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + address string + want string + }{ + { + failure: false, + name: "address set", + address: "file::memory:?cache=shared", + want: "file::memory:?cache=shared", + }, + { + failure: false, + name: "address not set", + address: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithAddress(test.address)(e) + + if test.failure { + if err == nil { + t.Errorf("WithAddress for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithAddress for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.Address, test.want) { + t.Errorf("WithAddress for %s is %v, want %v", test.name, e.config.Address, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithCompressionLevel(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + level int + want int + }{ + { + failure: false, + name: "compression level set to -1", + level: -1, + want: -1, + }, + { + failure: false, + name: "compression level set to 0", + level: 0, + want: 0, + }, + { + failure: false, + name: "compression level set to 1", + level: 1, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithCompressionLevel(test.level)(e) + + if test.failure { + if err == nil { + t.Errorf("WithCompressionLevel for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithCompressionLevel for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.CompressionLevel, test.want) { + t.Errorf("WithCompressionLevel for %s is %v, want %v", test.name, e.config.CompressionLevel, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithConnectionLife(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + life time.Duration + want time.Duration + }{ + { + failure: false, + name: "life of connections set", + life: 30 * time.Minute, + want: 30 * time.Minute, + }, + { + failure: false, + name: "life of connections not set", + life: 0, + want: 0, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithConnectionLife(test.life)(e) + + if test.failure { + if err == nil { + t.Errorf("WithConnectionLife for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithConnectionLife for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.ConnectionLife, test.want) { + t.Errorf("WithConnectionLife for %s is %v, want %v", test.name, e.config.ConnectionLife, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithConnectionIdle(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + open int + want int + }{ + { + failure: false, + name: "idle connections set", + open: 2, + want: 2, + }, + { + failure: false, + name: "idle connections not set", + open: 0, + want: 0, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithConnectionIdle(test.open)(e) + + if test.failure { + if err == nil { + t.Errorf("WithConnectionIdle for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithConnectionIdle for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.ConnectionIdle, test.want) { + t.Errorf("WithConnectionIdle for %s is %v, want %v", test.name, e.config.ConnectionIdle, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithConnectionOpen(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + open int + want int + }{ + { + failure: false, + name: "open connections set", + open: 2, + want: 2, + }, + { + failure: false, + name: "open connections not set", + open: 0, + want: 0, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithConnectionOpen(test.open)(e) + + if test.failure { + if err == nil { + t.Errorf("WithConnectionOpen for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithConnectionOpen for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.ConnectionOpen, test.want) { + t.Errorf("WithConnectionOpen for %s is %v, want %v", test.name, e.config.ConnectionOpen, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithDriver(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + driver string + want string + }{ + { + failure: false, + name: "driver set", + driver: "sqlite3", + want: "sqlite3", + }, + { + failure: false, + name: "driver not set", + driver: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithDriver(test.driver)(e) + + if test.failure { + if err == nil { + t.Errorf("WithDriver for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithDriver for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.Driver, test.want) { + t.Errorf("WithDriver for %s is %v, want %v", test.name, e.config.Driver, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithEncryptionKey(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + key string + want string + }{ + { + failure: false, + name: "encryption key set", + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + }, + { + failure: false, + name: "encryption key not set", + key: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithEncryptionKey(test.key)(e) + + if test.failure { + if err == nil { + t.Errorf("WithEncryptionKey for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithEncryptionKey for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(e.config.EncryptionKey, test.want) { + t.Errorf("WithEncryptionKey for %s is %v, want %v", test.name, e.config.EncryptionKey, test.want) + } + }) + } +} + +func TestDatabase_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skip bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skip: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skip: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skip)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/ping.go b/database/ping.go index 7ac1a09c2..80968c152 100644 --- a/database/ping.go +++ b/database/ping.go @@ -11,12 +11,12 @@ import ( // Ping sends a "ping" request with backoff to the database. func (e *engine) Ping() error { - e.Logger.Tracef("sending ping request to the %s database", e.Driver()) + e.logger.Tracef("sending ping request to the %s database", e.Driver()) // create a loop to attempt ping requests 5 times for i := 0; i < 5; i++ { // capture database/sql database from gorm.io/gorm database - _sql, err := e.Database.DB() + _sql, err := e.client.DB() if err != nil { return err } @@ -27,7 +27,7 @@ func (e *engine) Ping() error { // create the duration of time to sleep for before attempting to retry duration := time.Duration(i+1) * time.Second - e.Logger.Warnf("unable to ping %s database - retrying in %v", e.Driver(), duration) + e.logger.Warnf("unable to ping %s database - retrying in %v", e.Driver(), duration) // sleep for loop iteration in seconds time.Sleep(duration) diff --git a/database/ping_test.go b/database/ping_test.go index 7a34ad122..5b2fdb0c9 100644 --- a/database/ping_test.go +++ b/database/ping_test.go @@ -48,15 +48,15 @@ func TestDatabase_Engine_Ping(t *testing.T) { name: "failure with invalid gorm database", failure: true, database: &engine{ - Config: &Config{ + config: &config{ Driver: "invalid", }, - Database: &gorm.DB{ + client: &gorm.DB{ Config: &gorm.Config{ ConnPool: nil, }, }, - Logger: logrus.NewEntry(logrus.StandardLogger()), + logger: logrus.NewEntry(logrus.StandardLogger()), }, }, } diff --git a/database/resource.go b/database/resource.go index 93122eadc..1ff9c929c 100644 --- a/database/resource.go +++ b/database/resource.go @@ -24,9 +24,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for builds e.BuildInterface, err = build.New( - build.WithClient(e.Database), - build.WithLogger(e.Logger), - build.WithSkipCreation(e.Config.SkipCreation), + build.WithClient(e.client), + build.WithLogger(e.logger), + build.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -34,9 +34,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for hooks e.HookInterface, err = hook.New( - hook.WithClient(e.Database), - hook.WithLogger(e.Logger), - hook.WithSkipCreation(e.Config.SkipCreation), + hook.WithClient(e.client), + hook.WithLogger(e.logger), + hook.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -44,10 +44,10 @@ func (e *engine) NewResources() error { // create the database agnostic engine for logs e.LogInterface, err = log.New( - log.WithClient(e.Database), - log.WithCompressionLevel(e.Config.CompressionLevel), - log.WithLogger(e.Logger), - log.WithSkipCreation(e.Config.SkipCreation), + log.WithClient(e.client), + log.WithCompressionLevel(e.config.CompressionLevel), + log.WithLogger(e.logger), + log.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -55,10 +55,10 @@ func (e *engine) NewResources() error { // create the database agnostic engine for pipelines e.PipelineInterface, err = pipeline.New( - pipeline.WithClient(e.Database), - pipeline.WithCompressionLevel(e.Config.CompressionLevel), - pipeline.WithLogger(e.Logger), - pipeline.WithSkipCreation(e.Config.SkipCreation), + pipeline.WithClient(e.client), + pipeline.WithCompressionLevel(e.config.CompressionLevel), + pipeline.WithLogger(e.logger), + pipeline.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -66,10 +66,10 @@ func (e *engine) NewResources() error { // create the database agnostic engine for repos e.RepoInterface, err = repo.New( - repo.WithClient(e.Database), - repo.WithEncryptionKey(e.Config.EncryptionKey), - repo.WithLogger(e.Logger), - repo.WithSkipCreation(e.Config.SkipCreation), + repo.WithClient(e.client), + repo.WithEncryptionKey(e.config.EncryptionKey), + repo.WithLogger(e.logger), + repo.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -77,9 +77,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for schedules e.ScheduleInterface, err = schedule.New( - schedule.WithClient(e.Database), - schedule.WithLogger(e.Logger), - schedule.WithSkipCreation(e.Config.SkipCreation), + schedule.WithClient(e.client), + schedule.WithLogger(e.logger), + schedule.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -89,10 +89,10 @@ func (e *engine) NewResources() error { // // https://pkg.go.dev/github.com/go-vela/server/database/secret#New e.SecretInterface, err = secret.New( - secret.WithClient(e.Database), - secret.WithEncryptionKey(e.Config.EncryptionKey), - secret.WithLogger(e.Logger), - secret.WithSkipCreation(e.Config.SkipCreation), + secret.WithClient(e.client), + secret.WithEncryptionKey(e.config.EncryptionKey), + secret.WithLogger(e.logger), + secret.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -100,9 +100,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for services e.ServiceInterface, err = service.New( - service.WithClient(e.Database), - service.WithLogger(e.Logger), - service.WithSkipCreation(e.Config.SkipCreation), + service.WithClient(e.client), + service.WithLogger(e.logger), + service.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -110,9 +110,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for steps e.StepInterface, err = step.New( - step.WithClient(e.Database), - step.WithLogger(e.Logger), - step.WithSkipCreation(e.Config.SkipCreation), + step.WithClient(e.client), + step.WithLogger(e.logger), + step.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -120,10 +120,10 @@ func (e *engine) NewResources() error { // create the database agnostic engine for users e.UserInterface, err = user.New( - user.WithClient(e.Database), - user.WithEncryptionKey(e.Config.EncryptionKey), - user.WithLogger(e.Logger), - user.WithSkipCreation(e.Config.SkipCreation), + user.WithClient(e.client), + user.WithEncryptionKey(e.config.EncryptionKey), + user.WithLogger(e.logger), + user.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err @@ -131,9 +131,9 @@ func (e *engine) NewResources() error { // create the database agnostic engine for workers e.WorkerInterface, err = worker.New( - worker.WithClient(e.Database), - worker.WithLogger(e.Logger), - worker.WithSkipCreation(e.Config.SkipCreation), + worker.WithClient(e.client), + worker.WithLogger(e.logger), + worker.WithSkipCreation(e.config.SkipCreation), ) if err != nil { return err diff --git a/database/validate.go b/database/validate.go index c16c07cd2..18f07cb84 100644 --- a/database/validate.go +++ b/database/validate.go @@ -13,7 +13,7 @@ import ( ) // Validate verifies the required fields from the provided configuration are populated correctly. -func (c *Config) Validate() error { +func (c *config) Validate() error { logrus.Trace("validating database configuration for engine") // verify a database driver was provided diff --git a/database/validate_test.go b/database/validate_test.go index 356705fe2..60761e215 100644 --- a/database/validate_test.go +++ b/database/validate_test.go @@ -14,12 +14,12 @@ func TestDatabase_Config_Validate(t *testing.T) { tests := []struct { failure bool name string - config *Config + config *config }{ { name: "success with postgres", failure: false, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -33,7 +33,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "success with sqlite3", failure: false, - config: &Config{ + config: &config{ Driver: "sqlite3", Address: "file::memory:?cache=shared", CompressionLevel: 3, @@ -47,7 +47,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "success with negative compression level", failure: false, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: -1, @@ -61,7 +61,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with empty driver", failure: true, - config: &Config{ + config: &config{ Driver: "", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -75,7 +75,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with empty address", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "", CompressionLevel: 3, @@ -89,7 +89,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with invalid address", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela/", CompressionLevel: 3, @@ -103,7 +103,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with invalid compression level", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 10, @@ -117,7 +117,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with empty encryption key", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -131,7 +131,7 @@ func TestDatabase_Config_Validate(t *testing.T) { { name: "failure with invalid encryption key", failure: true, - config: &Config{ + config: &config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, From 3b439fccd31f746cf23d6f6a9a1e251da18c2eb5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 20 Jun 2023 14:48:39 -0600 Subject: [PATCH 266/298] enhance(webhook): handle repository transfer events (#883) * enhance(webhook): handle repsository transfer events * use constant for transferred action * increase log level for renaming repo --------- Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- api/webhook/post.go | 61 +++---- router/middleware/perm/perm.go | 9 +- .../hooks/repository_transferred.json | 159 ++++++++++++++++++ scm/github/webhook.go | 15 +- scm/github/webhook_test.go | 67 +++++++- util/util.go | 14 ++ 6 files changed, 285 insertions(+), 40 deletions(-) create mode 100644 scm/github/testdata/hooks/repository_transferred.json diff --git a/api/webhook/post.go b/api/webhook/post.go index c4670d8ea..7eab225f5 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -701,7 +701,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r switch h.GetEventAction() { // if action is rename, go through rename routine - case constants.ActionRenamed: + case constants.ActionRenamed, constants.ActionTransferred: r, err := renameRepository(h, r, c, m) if err != nil { h.SetStatus(constants.StatusFailure) @@ -779,34 +779,16 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r // renameRepository is a helper function that takes the old name of the repo, // queries the database for the repo that matches that name and org, and updates // that repo to its new name in order to preserve it. It also updates the secrets -// associated with that repo. +// associated with that repo as well as build links for the UI. func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) (*library.Repo, error) { - logrus.Debugf("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) + logrus.Infof("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) // get the old name of the repo - previousName := r.GetPreviousName() - // get the repo from the database that matches the old name - dbR, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), previousName) - if err != nil { - retErr := fmt.Errorf("%s: failed to get repo %s/%s from database", baseErr, r.GetOrg(), previousName) - util.HandleError(c, http.StatusBadRequest, retErr) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return nil, retErr - } + prevOrg, prevRepo := util.SplitFullName(r.GetPreviousName()) - // update the repo name information - dbR.SetName(r.GetName()) - dbR.SetFullName(r.GetFullName()) - dbR.SetClone(r.GetClone()) - dbR.SetLink(r.GetLink()) - dbR.SetPreviousName(previousName) - - // update the repo in the database - err = database.FromContext(c).UpdateRepo(dbR) + // get the repo from the database that matches the old name + dbR, err := database.FromContext(c).GetRepoForOrg(prevOrg, prevRepo) if err != nil { - retErr := fmt.Errorf("%s: failed to update repo %s/%s in database", baseErr, r.GetOrg(), previousName) + retErr := fmt.Errorf("%s: failed to get repo %s/%s from database", baseErr, prevOrg, prevRepo) util.HandleError(c, http.StatusBadRequest, retErr) h.SetStatus(constants.StatusFailure) @@ -840,7 +822,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types // get total number of secrets associated with repository t, err := database.FromContext(c).CountSecretsForRepo(dbR, map[string]interface{}{}) if err != nil { - return nil, fmt.Errorf("unable to get secret count for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to get secret count for repo %s/%s: %w", prevOrg, prevRepo, err) } secrets := []*library.Secret{} @@ -849,7 +831,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types for repoSecrets := int64(0); repoSecrets < t; repoSecrets += 100 { s, _, err := database.FromContext(c).ListSecretsForRepo(dbR, map[string]interface{}{}, page, 100) if err != nil { - return nil, fmt.Errorf("unable to get secret list for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to get secret list for repo %s/%s: %w", prevOrg, prevRepo, err) } secrets = append(secrets, s...) @@ -859,11 +841,12 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types // update secrets to point to the new repository name for _, secret := range secrets { + secret.SetOrg(r.GetOrg()) secret.SetRepo(r.GetName()) err = database.FromContext(c).UpdateSecret(secret) if err != nil { - return nil, fmt.Errorf("unable to update secret for repo %s/%s: %w", r.GetOrg(), previousName, err) + return nil, fmt.Errorf("unable to update secret for repo %s/%s: %w", prevOrg, prevRepo, err) } } @@ -890,7 +873,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types // update build link to route to proper repo name for _, build := range builds { build.SetLink( - fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, dbR.GetFullName(), build.GetNumber()), + fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), build.GetNumber()), ) _, err = database.FromContext(c).UpdateBuild(build) @@ -899,5 +882,25 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types } } + // update the repo name information + dbR.SetName(r.GetName()) + dbR.SetOrg(r.GetOrg()) + dbR.SetFullName(r.GetFullName()) + dbR.SetClone(r.GetClone()) + dbR.SetLink(r.GetLink()) + dbR.SetPreviousName(r.GetPreviousName()) + + // update the repo in the database + err = database.FromContext(c).UpdateRepo(dbR) + if err != nil { + retErr := fmt.Errorf("%s: failed to update repo %s/%s in database", baseErr, prevOrg, prevRepo) + util.HandleError(c, http.StatusBadRequest, retErr) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return nil, retErr + } + return dbR, nil } diff --git a/router/middleware/perm/perm.go b/router/middleware/perm/perm.go index da4c18013..8028275ae 100644 --- a/router/middleware/perm/perm.go +++ b/router/middleware/perm/perm.go @@ -221,14 +221,7 @@ func MustSecretAdmin() gin.HandlerFunc { // if caller is worker with build token, verify it has access to requested secret if strings.EqualFold(cl.TokenType, constants.WorkerBuildTokenType) { - // split repo full name into org and repo - repoSlice := strings.Split(cl.Repo, "/") - if len(repoSlice) != 2 { - logger.Errorf("unable to parse repo claim in build token") - } - - org := repoSlice[0] - repo := repoSlice[1] + org, repo := util.SplitFullName(cl.Repo) switch t { case constants.SecretShared: diff --git a/scm/github/testdata/hooks/repository_transferred.json b/scm/github/testdata/hooks/repository_transferred.json new file mode 100644 index 000000000..2fdea23f6 --- /dev/null +++ b/scm/github/testdata/hooks/repository_transferred.json @@ -0,0 +1,159 @@ +{ + "action": "transferred", + "changes": { + "owner": { + "from": { + "user": { + "login": "Old-Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + } + } + } + }, + "repository": { + "id": 118, + "node_id": "MDEwOlJlcG9zaXRvcnkxMTg=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://octocoders.github.io/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World", + "forks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/forks", + "keys_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/events", + "assignees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/merges", + "archive_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://octocoders.github.io/api/v3/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T19:37:07Z", + "updated_at": "2019-05-15T19:38:25Z", + "pushed_at": "2019-05-15T19:38:23Z", + "git_url": "git://octocoders.github.io/Codertocat/Hello-World.git", + "ssh_url": "git@octocoders.github.io:Codertocat/Hello-World.git", + "clone_url": "https://octocoders.github.io/Codertocat/Hello-World.git", + "svn_url": "https://octocoders.github.io/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Ruby", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "master" + }, + "enterprise": { + "id": 1, + "slug": "github", + "name": "GitHub", + "node_id": "MDg6QnVzaW5lc3Mx", + "avatar_url": "https://octocoders.github.io/avatars/b/1?", + "description": null, + "website_url": null, + "html_url": "https://octocoders.github.io/businesses/github", + "created_at": "2019-05-14T19:31:12Z", + "updated_at": "2019-05-14T19:31:12Z" + }, + "sender": { + "login": "Codertocat", + "id": 4, + "node_id": "MDQ6VXNlcjQ=", + "avatar_url": "https://octocoders.github.io/avatars/u/4?", + "gravatar_id": "", + "url": "https://octocoders.github.io/api/v3/users/Codertocat", + "html_url": "https://octocoders.github.io/Codertocat", + "followers_url": "https://octocoders.github.io/api/v3/users/Codertocat/followers", + "following_url": "https://octocoders.github.io/api/v3/users/Codertocat/following{/other_user}", + "gists_url": "https://octocoders.github.io/api/v3/users/Codertocat/gists{/gist_id}", + "starred_url": "https://octocoders.github.io/api/v3/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://octocoders.github.io/api/v3/users/Codertocat/subscriptions", + "organizations_url": "https://octocoders.github.io/api/v3/users/Codertocat/orgs", + "repos_url": "https://octocoders.github.io/api/v3/users/Codertocat/repos", + "events_url": "https://octocoders.github.io/api/v3/users/Codertocat/events{/privacy}", + "received_events_url": "https://octocoders.github.io/api/v3/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 5, + "node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uNQ==" + } + } \ No newline at end of file diff --git a/scm/github/webhook.go b/scm/github/webhook.go index ad4eda5e6..ceaa5b35d 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -465,8 +465,19 @@ func (c *client) processRepositoryEvent(h *library.Hook, payload *github.Reposit r.SetTopics(repo.Topics) // if action is renamed, then get the previous name from payload - if payload.GetAction() == "renamed" { - r.SetPreviousName(payload.GetChanges().GetRepo().GetName().GetFrom()) + if payload.GetAction() == constants.ActionRenamed { + r.SetPreviousName(repo.GetOwner().GetLogin() + "/" + payload.GetChanges().GetRepo().GetName().GetFrom()) + } + + // if action is transferred, then get the previous owner from payload + // could be a user or an org, but both are User structs + if payload.GetAction() == constants.ActionTransferred { + org := payload.GetChanges().GetOwner().GetOwnerInfo().GetOrg() + if org == nil { + org = payload.GetChanges().GetOwner().GetOwnerInfo().GetUser() + } + + r.SetPreviousName(org.GetLogin() + "/" + repo.GetName()) } h.SetEvent(constants.EventRepository) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index b1f3a1f0e..1bef4c0ca 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -982,7 +982,72 @@ func TestGitHub_ProcessWebhook_RepositoryRename(t *testing.T) { wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") wantRepo.SetBranch("master") wantRepo.SetPrivate(false) - wantRepo.SetPreviousName("Hello-Old-World") + wantRepo.SetPreviousName("Codertocat/Hello-Old-World") + wantRepo.SetTopics(nil) + + want := &types.Webhook{ + Comment: "", + Hook: wantHook, + Repo: wantRepo, + } + + got, err := client.ProcessWebhook(request) + + if err != nil { + t.Errorf("ProcessWebhook returned err: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("ProcessWebhook is %v, want %v", got, want) + } +} + +func TestGitHub_ProcessWebhook_RepositoryTransfer(t *testing.T) { + // setup router + s := httptest.NewServer(http.NotFoundHandler()) + defer s.Close() + + // setup request + body, err := os.Open("testdata/hooks/repository_transferred.json") + if err != nil { + t.Errorf("unable to open file: %v", err) + } + + defer body.Close() + + request, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "/test", body) + request.Header.Set("Content-Type", "application/json") + request.Header.Set("User-Agent", "GitHub-Hookshot/a22606a") + request.Header.Set("X-GitHub-Delivery", "7bd477e4-4415-11e9-9359-0d41fdf9567e") + request.Header.Set("X-GitHub-Hook-ID", "123456") + request.Header.Set("X-GitHub-Event", "repository") + + // setup client + client, _ := NewTest(s.URL) + + // run test + wantHook := new(library.Hook) + wantHook.SetNumber(1) + wantHook.SetSourceID("7bd477e4-4415-11e9-9359-0d41fdf9567e") + wantHook.SetWebhookID(123456) + wantHook.SetCreated(time.Now().UTC().Unix()) + wantHook.SetHost("github.com") + wantHook.SetEvent(constants.EventRepository) + wantHook.SetEventAction(constants.ActionTransferred) + wantHook.SetBranch("master") + wantHook.SetStatus(constants.StatusSuccess) + wantHook.SetLink("https://github.com/Codertocat/Hello-World/settings/hooks") + + wantRepo := new(library.Repo) + wantRepo.SetActive(true) + wantRepo.SetOrg("Codertocat") + wantRepo.SetName("Hello-World") + wantRepo.SetFullName("Codertocat/Hello-World") + wantRepo.SetLink("https://octocoders.github.io/Codertocat/Hello-World") + wantRepo.SetClone("https://octocoders.github.io/Codertocat/Hello-World.git") + wantRepo.SetBranch("master") + wantRepo.SetPrivate(false) + wantRepo.SetPreviousName("Old-Codertocat/Hello-World") wantRepo.SetTopics(nil) want := &types.Webhook{ diff --git a/util/util.go b/util/util.go index 667653fbe..31cdd1104 100644 --- a/util/util.go +++ b/util/util.go @@ -64,6 +64,20 @@ func PathParameter(c *gin.Context, parameter string) string { return EscapeValue(c.Param(parameter)) } +// SplitFullName safely splits the repo.FullName field into an org and name. +func SplitFullName(value string) (string, string) { + // split repo full name into org and repo + repoSlice := strings.Split(value, "/") + if len(repoSlice) != 2 { + return "", "" + } + + org := repoSlice[0] + repo := repoSlice[1] + + return org, repo +} + // EscapeValue safely escapes any string by removing any new lines and HTML escaping it. func EscapeValue(value string) string { // replace all new lines in the value From 6f9f29e0d6b4547339c2dd1641a8629cb2f9972d Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 21 Jun 2023 08:36:08 -0600 Subject: [PATCH 267/298] chore(deps): bulk deps update (#888) --- compiler/native/compile_test.go | 2 +- compiler/registry/github/github.go | 2 +- compiler/registry/github/github_test.go | 2 +- compiler/registry/github/template.go | 2 +- go.mod | 28 ++++++------ go.sum | 58 ++++++++++++------------- scm/github/access.go | 2 +- scm/github/authentication.go | 2 +- scm/github/changeset.go | 2 +- scm/github/deployment.go | 2 +- scm/github/github.go | 2 +- scm/github/github_test.go | 2 +- scm/github/repo.go | 2 +- scm/github/webhook.go | 2 +- 14 files changed, 54 insertions(+), 56 deletions(-) diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 07b420dde..5281dccd1 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/raw" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" "testing" "time" diff --git a/compiler/registry/github/github.go b/compiler/registry/github/github.go index 11bc9594a..7fb6f22b7 100644 --- a/compiler/registry/github/github.go +++ b/compiler/registry/github/github.go @@ -9,7 +9,7 @@ import ( "net/url" "strings" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/github_test.go b/compiler/registry/github/github_test.go index 08145430e..530b8f644 100644 --- a/compiler/registry/github/github_test.go +++ b/compiler/registry/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" "golang.org/x/oauth2" ) diff --git a/compiler/registry/github/template.go b/compiler/registry/github/template.go index 59dde2708..956a7608d 100644 --- a/compiler/registry/github/template.go +++ b/compiler/registry/github/template.go @@ -13,7 +13,7 @@ import ( "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // Template captures the templated pipeline configuration from the GitHub repo. diff --git a/go.mod b/go.mod index 1e284d4f4..58439b9bc 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 - github.com/google/go-github/v52 v52.0.0 + github.com/google/go-github/v53 v53.2.0 github.com/google/uuid v1.3.0 github.com/goware/urlx v0.3.2 github.com/hashicorp/go-cleanhttp v0.5.2 @@ -26,18 +26,18 @@ require ( github.com/hashicorp/vault/api v1.9.2 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.15.1 + github.com/prometheus/client_golang v1.16.0 github.com/redis/go-redis/v9 v9.0.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.25.6 - go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 - golang.org/x/oauth2 v0.7.0 - golang.org/x/sync v0.1.0 + go.starlark.net v0.0.0-20230612165344-9532f5667272 + golang.org/x/oauth2 v0.9.0 + golang.org/x/sync v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gorm.io/driver/postgres v1.5.2 - gorm.io/driver/sqlite v1.4.4 - gorm.io/gorm v1.25.1 + gorm.io/driver/sqlite v1.5.2 + gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 k8s.io/apimachinery v0.27.2 ) @@ -53,7 +53,7 @@ require ( github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cloudflare/circl v1.1.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect @@ -91,7 +91,7 @@ require ( github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/microcosm-cc/bluemonday v1.0.24 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect @@ -103,7 +103,7 @@ require ( github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect @@ -114,10 +114,10 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.8.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.10.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index 3f90f092b..aab85f958 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,9 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -192,8 +193,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M= -github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4= +github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= +github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -265,7 +266,6 @@ github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -301,9 +301,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= -github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw= @@ -333,15 +332,15 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= -github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= -github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -396,8 +395,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg= -go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20230612165344-9532f5667272 h1:2/wtqS591wZyD2OsClsVBKRPEvBsQt/Js+fsCiYhwu8= +go.starlark.net v0.0.0-20230612165344-9532f5667272/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -410,8 +409,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -481,8 +480,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -492,8 +491,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= +golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -505,8 +504,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -552,8 +551,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -568,8 +567,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -738,11 +737,10 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= -gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= -gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= -gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= +gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/scm/github/access.go b/scm/github/access.go index e70693ccb..ee47cf3d1 100644 --- a/scm/github/access.go +++ b/scm/github/access.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // OrgAccess captures the user's access level for an org. diff --git a/scm/github/authentication.go b/scm/github/authentication.go index 9efe41579..3b4ccf14b 100644 --- a/scm/github/authentication.go +++ b/scm/github/authentication.go @@ -14,7 +14,7 @@ import ( "github.com/go-vela/server/random" "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // Authorize uses the given access token to authorize the user. diff --git a/scm/github/changeset.go b/scm/github/changeset.go index 4d41dd2e2..da8ca221a 100644 --- a/scm/github/changeset.go +++ b/scm/github/changeset.go @@ -10,7 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // Changeset captures the list of files changed for a commit. diff --git a/scm/github/deployment.go b/scm/github/deployment.go index 9945c6303..fea3f8d03 100644 --- a/scm/github/deployment.go +++ b/scm/github/deployment.go @@ -11,7 +11,7 @@ import ( "github.com/go-vela/types/library" "github.com/go-vela/types/raw" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // GetDeployment gets a deployment from the GitHub repo. diff --git a/scm/github/github.go b/scm/github/github.go index 75b1df60a..ebae7ec76 100644 --- a/scm/github/github.go +++ b/scm/github/github.go @@ -9,7 +9,7 @@ import ( "fmt" "net/url" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" "github.com/sirupsen/logrus" "golang.org/x/oauth2" diff --git a/scm/github/github_test.go b/scm/github/github_test.go index 2e4b5f398..1c10db60a 100644 --- a/scm/github/github_test.go +++ b/scm/github/github_test.go @@ -12,7 +12,7 @@ import ( "reflect" "testing" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" "golang.org/x/oauth2" ) diff --git a/scm/github/repo.go b/scm/github/repo.go index b8fa31c3f..682a2db94 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -15,7 +15,7 @@ import ( "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // ConfigBackoff is a wrapper for Config that will retry five times if the function diff --git a/scm/github/webhook.go b/scm/github/webhook.go index ceaa5b35d..43615e8cb 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -20,7 +20,7 @@ import ( "github.com/go-vela/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" - "github.com/google/go-github/v52/github" + "github.com/google/go-github/v53/github" ) // ProcessWebhook parses the webhook from a repo. From 7e3fda66309ef4aa2afeeb0e0e2d1261fe8496f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 10:16:48 -0500 Subject: [PATCH 268/298] fix(deps): update module github.com/gin-gonic/gin to v1.9.1 [security] (#872) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 21 +++++++++++---------- go.sum | 49 ++++++++++++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 58439b9bc..72d36c3c7 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/aws/aws-sdk-go v1.44.281 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 - github.com/gin-gonic/gin v1.9.0 + github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af github.com/golang-jwt/jwt/v5 v5.0.0 @@ -49,7 +49,7 @@ require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bytedance/sonic v1.8.0 // indirect + github.com/bytedance/sonic v1.9.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect @@ -57,14 +57,15 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.10.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.11.2 // indirect - github.com/goccy/go-json v0.10.0 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect @@ -86,11 +87,11 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/microcosm-cc/bluemonday v1.0.24 // indirect @@ -100,7 +101,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect @@ -110,10 +111,10 @@ require ( github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.9 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.10.0 // indirect golang.org/x/net v0.11.0 // indirect golang.org/x/sys v0.9.0 // indirect diff --git a/go.sum b/go.sum index aab85f958..740315384 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,8 @@ github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVud github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= -github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -117,12 +117,14 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= -github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -137,13 +139,13 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= -github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af h1:Ixsa6Ha0j9Edq4v3IooDgyUoGSp08fk9FgrYKuZSML8= github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= -github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= -github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= @@ -280,16 +282,17 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= @@ -299,8 +302,8 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= @@ -324,8 +327,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -370,12 +373,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= -github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.25.6 h1:yuSkgDSZfH3L1CjF2/5fNNg2KbM47pY2EvjBq4ESQnU= github.com/urfave/cli/v2 v2.25.6/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= @@ -397,8 +402,9 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.starlark.net v0.0.0-20230612165344-9532f5667272 h1:2/wtqS591wZyD2OsClsVBKRPEvBsQt/Js+fsCiYhwu8= go.starlark.net v0.0.0-20230612165344-9532f5667272/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -546,11 +552,12 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From 45c60077dba14925d71a58a961c2e6ab85fc5951 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:55:14 -0600 Subject: [PATCH 269/298] chore(release): upgrade types to v0.20.0-rc1 (#890) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 72d36c3c7..dea6f6204 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af + github.com/go-vela/types v0.20.0-rc1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index 740315384..2465b7cca 100644 --- a/go.sum +++ b/go.sum @@ -142,8 +142,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af h1:Ixsa6Ha0j9Edq4v3IooDgyUoGSp08fk9FgrYKuZSML8= -github.com/go-vela/types v0.19.3-0.20230614134928-b1b57c0b34af/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= +github.com/go-vela/types v0.20.0-rc1 h1:t4tz9YjExtrFMFTq6w+0xWens8b0UPC1kcI642Ta3yc= +github.com/go-vela/types v0.20.0-rc1/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= From 9f92c243082e8a4f599cc8991dd7772a9ce3ccbb Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:17:45 -0600 Subject: [PATCH 270/298] fix(schedules): updated_at automatically updates to any change to row (#894) * fix(schedules): updated_at automatically updates to any change to row * revert docker compose * change config to fields and improve comment * what is your why --- api/schedule/create.go | 2 +- api/schedule/update.go | 2 +- cmd/vela-server/schedule.go | 2 +- database/schedule/interface.go | 2 +- database/schedule/update.go | 19 +++++--- database/schedule/update_test.go | 76 +++++++++++++++++++++++++++++++- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/api/schedule/create.go b/api/schedule/create.go index c8eb92741..365df170e 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.go @@ -170,7 +170,7 @@ func CreateSchedule(c *gin.Context) { dbSchedule.SetActive(true) // send API call to update the schedule - err = database.FromContext(c).UpdateSchedule(dbSchedule) + err = database.FromContext(c).UpdateSchedule(dbSchedule, true) if err != nil { retErr := fmt.Errorf("unable to set schedule %s to active: %w", dbSchedule.GetName(), err) diff --git a/api/schedule/update.go b/api/schedule/update.go index 646e55fc2..b0862132a 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -123,7 +123,7 @@ func UpdateSchedule(c *gin.Context) { } // update the schedule within the database - err = database.FromContext(c).UpdateSchedule(s) + err = database.FromContext(c).UpdateSchedule(s, true) if err != nil { retErr := fmt.Errorf("unable to update scheduled %s: %w", scheduleName, err) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index ab0a56b90..a9fd38234 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -350,7 +350,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // send API call to update schedule for ensuring scheduled_at field is set - err = database.UpdateSchedule(s) + err = database.UpdateSchedule(s, false) if err != nil { return fmt.Errorf("unable to update schedule %s/%s: %w", r.GetFullName(), s.GetName(), err) } diff --git a/database/schedule/interface.go b/database/schedule/interface.go index 8aa14efb5..afa163063 100644 --- a/database/schedule/interface.go +++ b/database/schedule/interface.go @@ -45,5 +45,5 @@ type ScheduleInterface interface { // ListSchedulesForRepo defines a function that gets a list of schedules by repo ID. ListSchedulesForRepo(*library.Repo, int, int) ([]*library.Schedule, int64, error) // UpdateSchedule defines a function that updates an existing schedule. - UpdateSchedule(*library.Schedule) error + UpdateSchedule(*library.Schedule, bool) error } diff --git a/database/schedule/update.go b/database/schedule/update.go index b69f8eff0..dd03f62c5 100644 --- a/database/schedule/update.go +++ b/database/schedule/update.go @@ -2,7 +2,6 @@ // // Use of this source code is governed by the LICENSE file in this repository. -//nolint:dupl // ignore similar code with create.go package schedule import ( @@ -13,7 +12,7 @@ import ( ) // UpdateSchedule updates an existing schedule in the database. -func (e *engine) UpdateSchedule(s *library.Schedule) error { +func (e *engine) UpdateSchedule(s *library.Schedule, fields bool) error { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("updating schedule %s in the database", s.GetName()) @@ -27,9 +26,15 @@ func (e *engine) UpdateSchedule(s *library.Schedule) error { return err } - // send query to the database - return e.client. - Table(constants.TableSchedule). - Save(schedule). - Error + // If "fields" is true, update entire record; otherwise, just update scheduled_at (part of processSchedule) + // + // we do this because Gorm will automatically set `updated_at` with the Save function + // and the `updated_at` field should reflect the last time a user updated the record, rather than the scheduler + if fields { + err = e.client.Table(constants.TableSchedule).Save(schedule).Error + } else { + err = e.client.Table(constants.TableSchedule).Model(schedule).UpdateColumn("scheduled_at", s.GetScheduledAt()).Error + } + + return err } diff --git a/database/schedule/update_test.go b/database/schedule/update_test.go index 05fff4286..2554cefdc 100644 --- a/database/schedule/update_test.go +++ b/database/schedule/update_test.go @@ -11,7 +11,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" ) -func TestSchedule_Engine_UpdateSchedule(t *testing.T) { +func TestSchedule_Engine_UpdateSchedule_Config(t *testing.T) { _repo := testRepo() _repo.SetID(1) _repo.SetOrg("foo") @@ -67,7 +67,79 @@ WHERE "id" = $10`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSchedule(_schedule) + err = test.database.UpdateSchedule(_schedule, true) + + if test.failure { + if err == nil { + t.Errorf("UpdateSchedule for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("UpdateSchedule for %s returned err: %v", test.name, err) + } + }) + } +} + +func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { + _repo := testRepo() + _repo.SetID(1) + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + + _schedule := testSchedule() + _schedule.SetID(1) + _schedule.SetRepoID(1) + _schedule.SetName("nightly") + _schedule.SetEntry("0 0 * * *") + _schedule.SetCreatedAt(1) + _schedule.SetCreatedBy("user1") + _schedule.SetUpdatedAt(1) + _schedule.SetUpdatedBy("user2") + _schedule.SetScheduledAt(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // ensure the mock expects the query + _mock.ExpectExec(`UPDATE "schedules" SET "scheduled_at"=$1 WHERE "id" = $2`). + WithArgs(1, 1). + WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateSchedule(_schedule) + if err != nil { + t.Errorf("unable to create test schedule for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err = test.database.UpdateSchedule(_schedule, false) if test.failure { if err == nil { From a6277aba3c8b09f7d8b2539e84594a6eeb491255 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 29 Jun 2023 09:37:29 -0600 Subject: [PATCH 271/298] fix(compose): use hashicorp/vault docker repo (#897) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index d030743e6..09e729ee8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -143,7 +143,7 @@ services: # # https://www.vaultproject.io/ vault: - image: vault:latest + image: hashicorp/vault:latest container_name: vault command: server -dev networks: From 900608b940587c979297c018d831a7df361818b2 Mon Sep 17 00:00:00 2001 From: David May <49894298+wass3rw3rk@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:31:44 -0500 Subject: [PATCH 272/298] fix(api): support schedule in filter (#900) --- api/build/list_org.go | 29 ++++++++++++++++++++++++++++- api/build/list_repo.go | 9 +++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/api/build/list_org.go b/api/build/list_org.go index 1ccd8b45b..9758bbc6a 100644 --- a/api/build/list_org.go +++ b/api/build/list_org.go @@ -35,6 +35,33 @@ import ( // required: true // type: string // - in: query +// name: event +// description: Filter by build event +// type: string +// enum: +// - comment +// - deployment +// - pull_request +// - push +// - schedule +// - tag +// - in: query +// name: branch +// description: Filter builds by branch +// type: string +// - in: query +// name: status +// description: Filter by build status +// type: string +// enum: +// - canceled +// - error +// - failure +// - killed +// - pending +// - running +// - success +// - in: query // name: page // description: The page of results to retrieve // type: integer @@ -109,7 +136,7 @@ func ListBuildsForOrg(c *gin.Context) { // verify the event provided is a valid event type if event != constants.EventComment && event != constants.EventDeploy && event != constants.EventPush && event != constants.EventPull && - event != constants.EventTag { + event != constants.EventTag && event != constants.EventSchedule { retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/api/build/list_repo.go b/api/build/list_repo.go index 2dd71fc1a..f11d35b0b 100644 --- a/api/build/list_repo.go +++ b/api/build/list_repo.go @@ -45,11 +45,12 @@ import ( // description: Filter by build event // type: string // enum: -// - push +// - comment +// - deployment // - pull_request +// - push +// - schedule // - tag -// - deployment -// - comment // - in: query // name: commit // description: Filter builds based on the commit hash @@ -159,7 +160,7 @@ func ListBuildsForRepo(c *gin.Context) { // verify the event provided is a valid event type if event != constants.EventComment && event != constants.EventDeploy && event != constants.EventPush && event != constants.EventPull && - event != constants.EventTag { + event != constants.EventTag && event != constants.EventSchedule { retErr := fmt.Errorf("unable to process event %s: invalid event type provided", event) util.HandleError(c, http.StatusBadRequest, retErr) From 71a484dd236d606a9f72643b0a6881137f45d620 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:21:41 -0600 Subject: [PATCH 273/298] fix(api/schedule): make validateEntry more strict and set updated_by using claims (#901) * fix(api/schedule): make validateEntry more strict and set updated_by using claims * rm docker compose update * add test cases to validateEntry --- api/schedule/create.go | 36 +++++++++++++++++++++++------------- api/schedule/create_test.go | 16 ++++++++++++++++ api/schedule/update.go | 5 +++++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/api/schedule/create.go b/api/schedule/create.go index 365df170e..f03fa0cea 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.go @@ -209,21 +209,31 @@ func validateEntry(minimum time.Duration, entry string) error { return fmt.Errorf("invalid entry of %s", entry) } - // check the previous occurrence of the entry - prevTime, err := gronx.PrevTick(entry, true) - if err != nil { - return err - } + // iterate 5 times through ticks in an effort to catch scalene entries + tickForward := 5 - // check the next occurrence of the entry - nextTime, err := gronx.NextTick(entry, true) - if err != nil { - return err - } + // start with now + t := time.Now().UTC() + + for i := 0; i < tickForward; i++ { + // check the previous occurrence of the entry + prevTime, err := gronx.PrevTickBefore(entry, t, true) + if err != nil { + return err + } + + // check the next occurrence of the entry + nextTime, err := gronx.NextTickAfter(entry, t, false) + if err != nil { + return err + } + + // ensure the time between previous and next schedule exceeds the minimum duration + if nextTime.Sub(prevTime) < minimum { + return fmt.Errorf("entry needs to occur less frequently than every %s", minimum) + } - // ensure the time between previous and next schedule exceeds the minimum duration - if nextTime.Sub(prevTime) < minimum { - return fmt.Errorf("entry needs to occur less frequently than every %s", minimum) + t = nextTime } return nil diff --git a/api/schedule/create_test.go b/api/schedule/create_test.go index 0ca425e32..a2956f6ca 100644 --- a/api/schedule/create_test.go +++ b/api/schedule/create_test.go @@ -35,6 +35,14 @@ func Test_validateEntry(t *testing.T) { }, wantErr: true, }, + { + name: "exceeds minimum frequency with scalene entry pattern", + args: args{ + minimum: 30 * time.Minute, + entry: "1,2,45 * * * *", + }, + wantErr: true, + }, { name: "meets minimum frequency", args: args{ @@ -51,6 +59,14 @@ func Test_validateEntry(t *testing.T) { }, wantErr: false, }, + { + name: "meets minimum frequency with comma entry pattern", + args: args{ + minimum: 15 * time.Minute, + entry: "0,15,30,45 * * * *", + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/api/schedule/update.go b/api/schedule/update.go index b0862132a..5221d222c 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -13,6 +13,7 @@ import ( "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/schedule" + "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/util" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" @@ -73,6 +74,7 @@ func UpdateSchedule(c *gin.Context) { // capture middleware values r := repo.Retrieve(c) s := schedule.Retrieve(c) + u := user.Retrieve(c) scheduleName := util.PathParameter(c, "schedule") minimumFrequency := c.Value("scheduleminimumfrequency").(time.Duration) @@ -122,6 +124,9 @@ func UpdateSchedule(c *gin.Context) { s.SetEntry(input.GetEntry()) } + // set the updated by field using claims + s.SetUpdatedBy(u.GetName()) + // update the schedule within the database err = database.FromContext(c).UpdateSchedule(s, true) if err != nil { From 563f22636bea9c6e70e8d8980a4de7da1d0d1567 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 10 Jul 2023 09:29:41 -0500 Subject: [PATCH 274/298] fix(schedules): criteria for triggering a build (#893) * fix(schedules): ignore trigger for first time schedule * fix(schedules): determine trigger off current UTC time * chore: save work * cleanup: ignore inactive schedules * feat: add interval for schedules * chore: address slack feedback * chore: fix typos * fix: processing timed schedules * fix: processing schedules * fix: typo in comment * chore: address review feedback * temp: add test docker compose * fix: finalize * revert: add test docker compose --------- Co-authored-by: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- cmd/vela-server/main.go | 8 ++- cmd/vela-server/schedule.go | 123 +++++++++++++++++++++--------------- cmd/vela-server/server.go | 29 +++++---- 3 files changed, 98 insertions(+), 62 deletions(-) diff --git a/cmd/vela-server/main.go b/cmd/vela-server/main.go index 19463fe0b..788f6c26b 100644 --- a/cmd/vela-server/main.go +++ b/cmd/vela-server/main.go @@ -213,9 +213,15 @@ func main() { &cli.DurationFlag{ EnvVars: []string{"VELA_SCHEDULE_MINIMUM_FREQUENCY", "SCHEDULE_MINIMUM_FREQUENCY"}, Name: "schedule-minimum-frequency", - Usage: "minimum time between each schedule entry", + Usage: "minimum time allowed between each build triggered for a schedule", Value: 1 * time.Hour, }, + &cli.DurationFlag{ + EnvVars: []string{"VELA_SCHEDULE_INTERVAL", "SCHEDULE_INTERVAL"}, + Name: "schedule-interval", + Usage: "interval at which schedules will be processed by the server to trigger builds", + Value: 5 * time.Minute, + }, &cli.StringSliceFlag{ EnvVars: []string{"VELA_SCHEDULE_ALLOWLIST"}, Name: "vela-schedule-allowlist", diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index a9fd38234..08e7867cc 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -24,9 +24,13 @@ import ( "k8s.io/apimachinery/pkg/util/wait" ) -const baseErr = "unable to schedule build" +const ( + scheduleErr = "unable to trigger build for schedule" -func processSchedules(compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { + scheduleWait = "waiting to trigger build for schedule" +) + +func processSchedules(start time.Time, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { logrus.Infof("processing active schedules to create builds") // send API call to capture the list of active schedules @@ -37,6 +41,13 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met // iterate through the list of active schedules for _, s := range schedules { + // sleep for 1s - 2s before processing the active schedule + // + // This should prevent multiple servers from processing a schedule at the same time by + // leveraging a base duration along with a standard deviation of randomness a.k.a. + // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 1.0. + time.Sleep(wait.Jitter(time.Second, 1.0)) + // send API call to capture the schedule // // This is needed to ensure we are not dealing with a stale schedule since we fetch @@ -44,52 +55,79 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met // amount of time to get to the end of the list. schedule, err := database.GetSchedule(s.GetID()) if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) continue } - // create a variable to track if a build should be triggered based off the schedule - trigger := false + // ignore triggering a build if the schedule is no longer active + if !schedule.GetActive() { + logrus.Tracef("skipping to trigger build for inactive schedule %s", schedule.GetName()) - // check if a build has already been triggered for the schedule - if schedule.GetScheduledAt() == 0 { - // trigger a build for the schedule since one has not already been scheduled - trigger = true - } else { - // parse the previous occurrence of the entry for the schedule - prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + continue + } - continue - } + // capture the last time a build was triggered for the schedule in UTC + scheduled := time.Unix(schedule.GetScheduledAt(), 0).UTC() - // parse the next occurrence of the entry for the schedule - nextTime, err := gronx.NextTick(schedule.GetEntry(), true) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // capture the previous occurrence of the entry rounded to the nearest whole interval + // + // i.e. if it's 4:02 on five minute intervals, this will be 4:00 + prevTime, err := gronx.PrevTick(schedule.GetEntry(), true) + if err != nil { + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) - continue - } + continue + } - // parse the UNIX timestamp from when the last build was triggered for the schedule - t := time.Unix(schedule.GetScheduledAt(), 0).UTC() + // capture the next occurrence of the entry after the last schedule rounded to the nearest whole interval + // + // i.e. if it's 4:02 on five minute intervals, this will be 4:05 + nextTime, err := gronx.NextTickAfter(schedule.GetEntry(), scheduled, true) + if err != nil { + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) - // check if the time since the last triggered build is greater than the entry duration for the schedule - if time.Since(t) > nextTime.Sub(prevTime) { - // trigger a build for the schedule since it has not previously ran - trigger = true - } + continue } - if trigger && schedule.GetActive() { - err = processSchedule(schedule, compiler, database, metadata, queue, scm) - if err != nil { - logrus.WithError(err).Warnf("%s for %s", baseErr, schedule.GetName()) + // check if we should wait to trigger a build for the schedule + // + // The current time must be after the next occurrence of the schedule. + if !time.Now().After(nextTime) { + logrus.Tracef("%s %s: current time not past next occurrence", scheduleWait, schedule.GetName()) - continue - } + continue + } + + // check if we should wait to trigger a build for the schedule + // + // The previous occurrence of the schedule must be after the starting time of processing schedules. + if !prevTime.After(start) { + logrus.Tracef("%s %s: previous occurence not after starting point", scheduleWait, schedule.GetName()) + + continue + } + + // update the scheduled_at field with the current timestamp + // + // This should help prevent multiple servers from processing a schedule at the same time + // by updating the schedule with a new timestamp to reflect the current state. + schedule.SetScheduledAt(time.Now().UTC().Unix()) + + // send API call to update schedule for ensuring scheduled_at field is set + err = database.UpdateSchedule(schedule, false) + if err != nil { + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) + + continue + } + + // process the schedule and trigger a new build + err = processSchedule(schedule, compiler, database, metadata, queue, scm) + if err != nil { + logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) + + continue } } @@ -98,13 +136,6 @@ func processSchedules(compiler compiler.Engine, database database.Interface, met //nolint:funlen // ignore function length and number of statements func processSchedule(s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { - // sleep for 1s - 3s before processing the schedule - // - // This should prevent multiple servers from processing a schedule at the same time by - // leveraging a base duration along with a standard deviation of randomness a.k.a. - // "jitter". To create the jitter, we use a base duration of 1s with a scale factor of 3.0. - time.Sleep(wait.Jitter(time.Second, 3.0)) - // send API call to capture the repo for the schedule r, err := database.GetRepo(s.GetRepoID()) if err != nil { @@ -337,8 +368,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat return err } - s.SetScheduledAt(time.Now().UTC().Unix()) - // break the loop because everything was successful break } // end of retry loop @@ -349,12 +378,6 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat return fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) } - // send API call to update schedule for ensuring scheduled_at field is set - err = database.UpdateSchedule(s, false) - if err != nil { - return fmt.Errorf("unable to update schedule %s/%s: %w", r.GetFullName(), s.GetName(), err) - } - // send API call to capture the triggered build b, err = database.GetBuildForRepo(r, b.GetNumber()) if err != nil { diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 0d95e88e5..689ba03c2 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -176,23 +176,30 @@ func server(c *cli.Context) error { g.Go(func() error { logrus.Info("starting scheduler") for { - // cut the configured minimum frequency duration for schedules in half + // track the starting time for when the server begins processing schedules // - // We need to sleep for some amount of time before we attempt to process schedules - // setup in the database. Since the minimum frequency is configurable, we cut it in - // half and use that as the base duration to determine how long to sleep for. - base := c.Duration("schedule-minimum-frequency") / 2 - logrus.Infof("sleeping for %v before scheduling builds", base) + // This will be used to control which schedules will have a build triggered based + // off the configured entry and last time a build was triggered for the schedule. + start := time.Now().UTC() - // sleep for a duration of time before processing schedules + // capture the interval of time to wait before processing schedules // + // We need to sleep for some amount of time before we attempt to process schedules + // setup in the database. Since the schedule interval is configurable, we use that + // as the base duration to determine how long to sleep for. + interval := c.Duration("schedule-interval") + // This should prevent multiple servers from processing schedules at the same time by // leveraging a base duration along with a standard deviation of randomness a.k.a. - // "jitter". To create the jitter, we use the configured minimum frequency duration - // along with a scale factor of 0.1. - time.Sleep(wait.Jitter(base, 0.1)) + // "jitter". To create the jitter, we use the configured schedule interval duration + // along with a scale factor of 0.5. + jitter := wait.Jitter(interval, 0.5) + + logrus.Infof("sleeping for %v before scheduling builds", jitter) + // sleep for a duration of time before processing schedules + time.Sleep(jitter) - err = processSchedules(compiler, database, metadata, queue, scm) + err = processSchedules(start, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warn("unable to process schedules") } else { From 3f0c184e0ce446e84c9b55ca5518659f76032b42 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 10 Jul 2023 10:27:35 -0600 Subject: [PATCH 275/298] fix(db tests): use lenient timestamp check for time.Now query matching (#902) Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --- database/build/build_test.go | 15 +++++++++++++++ database/build/clean_test.go | 3 +-- database/schedule/schedule_test.go | 20 ++++++++++++++++++++ database/schedule/update_test.go | 3 +-- database/secret/secret_test.go | 15 +++++++++++++++ database/secret/update_test.go | 7 +++---- database/service/clean_test.go | 3 +-- database/service/service_test.go | 22 ++++++++++++++++++++++ database/step/clean_test.go | 3 +-- database/step/step_test.go | 22 ++++++++++++++++++++++ 10 files changed, 101 insertions(+), 12 deletions(-) diff --git a/database/build/build_test.go b/database/build/build_test.go index 6304cd167..070744260 100644 --- a/database/build/build_test.go +++ b/database/build/build_test.go @@ -8,6 +8,7 @@ import ( "database/sql/driver" "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -266,3 +267,17 @@ type AnyArgument struct{} func (a AnyArgument) Match(v 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_test.go b/database/build/clean_test.go index 05b606b3f..ff6e36556 100644 --- a/database/build/clean_test.go +++ b/database/build/clean_test.go @@ -7,7 +7,6 @@ package build import ( "reflect" "testing" - "time" "github.com/DATA-DOG/go-sqlmock" ) @@ -48,7 +47,7 @@ func TestBuild_Engine_CleanBuilds(t *testing.T) { // ensure the mock expects the name query _mock.ExpectExec(`UPDATE "builds" SET "status"=$1,"error"=$2,"finished"=$3,"deploy_payload"=$4 WHERE created < $5 AND (status = 'running' OR status = 'pending')`). - WithArgs("error", "msg", time.Now().UTC().Unix(), AnyArgument{}, 3). + WithArgs("error", "msg", NowTimestamp{}, AnyArgument{}, 3). WillReturnResult(sqlmock.NewResult(1, 2)) _sqlite := testSqlite(t) diff --git a/database/schedule/schedule_test.go b/database/schedule/schedule_test.go index c86f1f353..fc4b4c6e1 100644 --- a/database/schedule/schedule_test.go +++ b/database/schedule/schedule_test.go @@ -5,8 +5,10 @@ package schedule import ( + "database/sql/driver" "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -210,3 +212,21 @@ func testRepo() *library.Repo { AllowComment: 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 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/schedule/update_test.go b/database/schedule/update_test.go index 2554cefdc..07cbfbc58 100644 --- a/database/schedule/update_test.go +++ b/database/schedule/update_test.go @@ -6,7 +6,6 @@ package schedule import ( "testing" - "time" "github.com/DATA-DOG/go-sqlmock" ) @@ -35,7 +34,7 @@ func TestSchedule_Engine_UpdateSchedule_Config(t *testing.T) { _mock.ExpectExec(`UPDATE "schedules" SET "repo_id"=$1,"active"=$2,"name"=$3,"entry"=$4,"created_at"=$5,"created_by"=$6,"updated_at"=$7,"updated_by"=$8,"scheduled_at"=$9 WHERE "id" = $10`). - WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", time.Now().UTC().Unix(), "user2", nil, 1). + WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", NowTimestamp{}, "user2", nil, 1). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) diff --git a/database/secret/secret_test.go b/database/secret/secret_test.go index 228567344..0d6a61c25 100644 --- a/database/secret/secret_test.go +++ b/database/secret/secret_test.go @@ -8,6 +8,7 @@ import ( "database/sql/driver" "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -238,3 +239,17 @@ type AnyArgument struct{} 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/secret/update_test.go b/database/secret/update_test.go index e719e220e..fd9a24ff6 100644 --- a/database/secret/update_test.go +++ b/database/secret/update_test.go @@ -6,7 +6,6 @@ package secret import ( "testing" - "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -57,21 +56,21 @@ func TestSecret_Engine_UpdateSecret(t *testing.T) { _mock.ExpectExec(`UPDATE "secrets" SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 WHERE "id" = $14`). - WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 1). + WithArgs("foo", "bar", nil, "baz", AnyArgument{}, "repo", nil, nil, false, 1, "user", AnyArgument{}, "user2", 1). WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the org query _mock.ExpectExec(`UPDATE "secrets" SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 WHERE "id" = $14`). - WithArgs("foo", "*", nil, "bar", AnyArgument{}, "org", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 2). + WithArgs("foo", "*", nil, "bar", AnyArgument{}, "org", nil, nil, false, 1, "user", AnyArgument{}, "user2", 2). WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the shared query _mock.ExpectExec(`UPDATE "secrets" SET "org"=$1,"repo"=$2,"team"=$3,"name"=$4,"value"=$5,"type"=$6,"images"=$7,"events"=$8,"allow_command"=$9,"created_at"=$10,"created_by"=$11,"updated_at"=$12,"updated_by"=$13 WHERE "id" = $14`). - WithArgs("foo", nil, "bar", "baz", AnyArgument{}, "shared", nil, nil, false, 1, "user", time.Now().UTC().Unix(), "user2", 3). + WithArgs("foo", nil, "bar", "baz", AnyArgument{}, "shared", nil, nil, false, 1, "user", NowTimestamp{}, "user2", 3). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) diff --git a/database/service/clean_test.go b/database/service/clean_test.go index f30939880..3bd9baf15 100644 --- a/database/service/clean_test.go +++ b/database/service/clean_test.go @@ -7,7 +7,6 @@ package service import ( "reflect" "testing" - "time" "github.com/DATA-DOG/go-sqlmock" ) @@ -59,7 +58,7 @@ func TestService_Engine_CleanService(t *testing.T) { // ensure the mock expects the name query _mock.ExpectExec(`UPDATE "services" SET "status"=$1,"error"=$2,"finished"=$3 WHERE created < $4 AND (status = 'running' OR status = 'pending')`). - WithArgs("error", "msg", time.Now().UTC().Unix(), 3). + WithArgs("error", "msg", NowTimestamp{}, 3). WillReturnResult(sqlmock.NewResult(1, 2)) _sqlite := testSqlite(t) diff --git a/database/service/service_test.go b/database/service/service_test.go index 7749f43d3..c9d658769 100644 --- a/database/service/service_test.go +++ b/database/service/service_test.go @@ -5,8 +5,10 @@ package service import ( + "database/sql/driver" "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -222,3 +224,23 @@ func testService() *library.Service { 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. +// +// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime + +// 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/step/clean_test.go b/database/step/clean_test.go index 22709749a..4d0c68e07 100644 --- a/database/step/clean_test.go +++ b/database/step/clean_test.go @@ -7,7 +7,6 @@ package step import ( "reflect" "testing" - "time" "github.com/DATA-DOG/go-sqlmock" ) @@ -59,7 +58,7 @@ func TestStep_Engine_CleanStep(t *testing.T) { // ensure the mock expects the name query _mock.ExpectExec(`UPDATE "steps" SET "status"=$1,"error"=$2,"finished"=$3 WHERE created < $4 AND (status = 'running' OR status = 'pending')`). - WithArgs("error", "msg", time.Now().UTC().Unix(), 3). + WithArgs("error", "msg", NowTimestamp{}, 3). WillReturnResult(sqlmock.NewResult(1, 2)) _sqlite := testSqlite(t) diff --git a/database/step/step_test.go b/database/step/step_test.go index 26edfa5e1..136d5ca40 100644 --- a/database/step/step_test.go +++ b/database/step/step_test.go @@ -5,8 +5,10 @@ package step import ( + "database/sql/driver" "reflect" "testing" + "time" "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/types/library" @@ -223,3 +225,23 @@ func testStep() *library.Step { 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. +// +// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime + +// 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 +} From 8a25e311b691aeba64fdb09608cd54c3872a0da8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:37:03 -0500 Subject: [PATCH 276/298] fix(deps): update deps (patch) (#895) * fix(deps): update deps (patch) * fix(deps): update deps (patch) --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: ecrupper --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index dea6f6204..48eba88e8 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 github.com/adhocore/gronx v1.6.3 - github.com/alicebob/miniredis/v2 v2.30.3 - github.com/aws/aws-sdk-go v1.44.281 + github.com/alicebob/miniredis/v2 v2.30.4 + github.com/aws/aws-sdk-go v1.44.298 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 @@ -30,7 +30,7 @@ require ( github.com/redis/go-redis/v9 v9.0.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 - github.com/urfave/cli/v2 v2.25.6 + github.com/urfave/cli/v2 v2.25.7 go.starlark.net v0.0.0-20230612165344-9532f5667272 golang.org/x/oauth2 v0.9.0 golang.org/x/sync v0.3.0 @@ -38,7 +38,7 @@ require ( gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 - k8s.io/apimachinery v0.27.2 + k8s.io/apimachinery v0.27.3 ) require ( diff --git a/go.sum b/go.sum index 2465b7cca..f1d227814 100644 --- a/go.sum +++ b/go.sum @@ -63,11 +63,11 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521IC9VjTTRz2nIaJE= -github.com/alicebob/miniredis/v2 v2.30.3 h1:hrqDB4cHFSHQf4gO3xu6YKQg8PqJpNjLYsQAFYHstqw= -github.com/alicebob/miniredis/v2 v2.30.3/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.281 h1:z/ptheJvINaIAsKXthxONM+toTKw2pxyk700Hfm6yUw= -github.com/aws/aws-sdk-go v1.44.281/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.298 h1:5qTxdubgV7PptZJmp/2qDwD2JL187ePL7VOxsSh1i3g= +github.com/aws/aws-sdk-go v1.44.298/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -381,8 +381,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.25.6 h1:yuSkgDSZfH3L1CjF2/5fNNg2KbM47pY2EvjBq4ESQnU= -github.com/urfave/cli/v2 v2.25.6/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -755,8 +755,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= -k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= +k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= From 73674fc4de2263bfd4a801389bc9419c0b1ea7d3 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:23:28 -0600 Subject: [PATCH 277/298] chore(release): upgrade types to v0.20.0 and upgrade other deps (#907) * chore(release): upgrade types to v0.20.0 + gorm and starlark upgrade * update Dockerfile to pin to alpine version for certs * go get correct docker version syntax * every day I surprise myself with my foolishness * pin gorm to an actual tag --- Dockerfile | 2 +- go.mod | 6 +++--- go.sum | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 98ecc5101..79beef6fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # # Use of this source code is governed by the LICENSE file in this repository. -FROM alpine as certs +FROM alpine:3.18.2@sha256:25fad2a32ad1f6f510e528448ae1ec69a28ef81916a004d3629874104f8a7f70 as certs RUN apk add --update --no-cache ca-certificates diff --git a/go.mod b/go.mod index 48eba88e8..9286615af 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.20.0-rc1 + github.com/go-vela/types v0.20.0 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v53 v53.2.0 @@ -31,13 +31,13 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.25.7 - go.starlark.net v0.0.0-20230612165344-9532f5667272 + go.starlark.net v0.0.0-20230712173630-2226322290fc golang.org/x/oauth2 v0.9.0 golang.org/x/sync v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 - gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 + gorm.io/gorm v1.25.2 k8s.io/apimachinery v0.27.3 ) diff --git a/go.sum b/go.sum index f1d227814..978abf40d 100644 --- a/go.sum +++ b/go.sum @@ -142,8 +142,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.20.0-rc1 h1:t4tz9YjExtrFMFTq6w+0xWens8b0UPC1kcI642Ta3yc= -github.com/go-vela/types v0.20.0-rc1/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= +github.com/go-vela/types v0.20.0 h1:u/wHwc6ElVbIEI+q9TaVl9Iai1EoEr4Lwis6mikOte8= +github.com/go-vela/types v0.20.0/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -400,8 +400,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.starlark.net v0.0.0-20230612165344-9532f5667272 h1:2/wtqS591wZyD2OsClsVBKRPEvBsQt/Js+fsCiYhwu8= -go.starlark.net v0.0.0-20230612165344-9532f5667272/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20230712173630-2226322290fc h1:x7dWtxLF8z8E5/+KkK3MJJTK/kBZhTCLmYCk75rhKxk= +go.starlark.net v0.0.0-20230712173630-2226322290fc/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -746,8 +746,8 @@ gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ= -gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From af551916026501435a453d0654e226e6daf3cfdc Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:31:17 -0600 Subject: [PATCH 278/298] chore(docker-alpine): pin to alpine tag and sha (#909) --- Dockerfile-alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile-alpine b/Dockerfile-alpine index f11d181f3..38ce8fded 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -2,7 +2,7 @@ # # Use of this source code is governed by the LICENSE file in this repository. -FROM alpine +FROM alpine:3.18.2@sha256:25fad2a32ad1f6f510e528448ae1ec69a28ef81916a004d3629874104f8a7f70 RUN apk add --update --no-cache ca-certificates From 41fdfd13c96ef25fa91bef680cea044f04d0762b Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 25 Jul 2023 04:25:53 -0600 Subject: [PATCH 279/298] refactor(database): return repo object on created and updated (#913) * init commit * fix tests --- api/admin/repo.go | 4 +-- api/build/create.go | 2 +- api/build/restart.go | 2 +- api/repo/chown.go | 2 +- api/repo/create.go | 10 ++---- api/repo/delete.go | 2 +- api/repo/repair.go | 2 +- api/repo/update.go | 5 +-- api/scm/sync.go | 2 +- api/scm/sync_org.go | 2 +- api/webhook/post.go | 6 ++-- cmd/vela-server/schedule.go | 2 +- database/repo/count_org_test.go | 4 +-- database/repo/count_test.go | 4 +-- database/repo/count_user_test.go | 4 +-- database/repo/create.go | 25 +++++++++---- database/repo/create_test.go | 8 ++++- database/repo/delete_test.go | 2 +- database/repo/get_org_test.go | 2 +- database/repo/get_test.go | 2 +- database/repo/interface.go | 4 +-- database/repo/list_org_test.go | 4 +-- database/repo/list_test.go | 4 +-- database/repo/list_user_test.go | 4 +-- database/repo/update.go | 25 +++++++++---- database/repo/update_test.go | 10 ++++-- router/middleware/build/build_test.go | 8 ++--- router/middleware/org/org_test.go | 2 +- router/middleware/perm/perm_test.go | 40 ++++++++++----------- router/middleware/pipeline/pipeline_test.go | 6 ++-- router/middleware/repo/repo_test.go | 2 +- router/middleware/service/service_test.go | 10 +++--- router/middleware/step/step_test.go | 10 +++--- 33 files changed, 123 insertions(+), 98 deletions(-) diff --git a/api/admin/repo.go b/api/admin/repo.go index 0f7327193..53ad236b9 100644 --- a/api/admin/repo.go +++ b/api/admin/repo.go @@ -66,7 +66,7 @@ func UpdateRepo(c *gin.Context) { } // send API call to update the repo - err = database.FromContext(c).UpdateRepo(input) + r, err := database.FromContext(c).UpdateRepo(input) if err != nil { retErr := fmt.Errorf("unable to update repo %d: %w", input.GetID(), err) @@ -75,5 +75,5 @@ func UpdateRepo(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, r) } diff --git a/api/build/create.go b/api/build/create.go index 38a8867c2..cac912867 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -329,7 +329,7 @@ func CreateBuild(c *gin.Context) { } // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to create new build: failed to update repo %s: %w", r.GetFullName(), err) diff --git a/api/build/restart.go b/api/build/restart.go index 8bb85e798..7b7dcca69 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -320,7 +320,7 @@ func RestartBuild(c *gin.Context) { } // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/api/repo/chown.go b/api/repo/chown.go index 00e728128..671e5a438 100644 --- a/api/repo/chown.go +++ b/api/repo/chown.go @@ -68,7 +68,7 @@ func ChownRepo(c *gin.Context) { r.SetUserID(u.GetID()) // send API call to update the repo - err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to change owner of repo %s to %s: %w", r.GetFullName(), u.GetName(), err) diff --git a/api/repo/create.go b/api/repo/create.go index e52cd23f4..33de7d3ae 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -285,7 +285,7 @@ func CreateRepo(c *gin.Context) { dbRepo.SetActive(true) // send API call to update the repo - err = database.FromContext(c).UpdateRepo(dbRepo) + r, err = database.FromContext(c).UpdateRepo(dbRepo) if err != nil { retErr := fmt.Errorf("unable to set repo %s to active: %w", dbRepo.GetFullName(), err) @@ -293,12 +293,9 @@ func CreateRepo(c *gin.Context) { return } - - // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepoForOrg(dbRepo.GetOrg(), dbRepo.GetName()) } else { // send API call to create the repo - err = database.FromContext(c).CreateRepo(r) + r, err = database.FromContext(c).CreateRepo(r) if err != nil { retErr := fmt.Errorf("unable to create new repo %s: %w", r.GetFullName(), err) @@ -306,9 +303,6 @@ func CreateRepo(c *gin.Context) { return } - - // send API call to capture the created repo - r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) } // create init hook in the DB after repo has been added in order to capture its ID diff --git a/api/repo/delete.go b/api/repo/delete.go index 63649f2eb..cc3ca66b9 100644 --- a/api/repo/delete.go +++ b/api/repo/delete.go @@ -88,7 +88,7 @@ func DeleteRepo(c *gin.Context) { // Mark the repo as inactive r.SetActive(false) - err = database.FromContext(c).UpdateRepo(r) + _, err = database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to set repo %s to inactive: %w", r.GetFullName(), err) diff --git a/api/repo/repair.go b/api/repo/repair.go index 192983d1c..7b7f0e98d 100644 --- a/api/repo/repair.go +++ b/api/repo/repair.go @@ -122,7 +122,7 @@ func RepairRepo(c *gin.Context) { r.SetActive(true) // send API call to update the repo - err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to set repo %s to active: %w", r.GetFullName(), err) diff --git a/api/repo/update.go b/api/repo/update.go index 374772d42..2f299bdc1 100644 --- a/api/repo/update.go +++ b/api/repo/update.go @@ -295,7 +295,7 @@ func UpdateRepo(c *gin.Context) { } // send API call to update the repo - err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) @@ -304,8 +304,5 @@ func UpdateRepo(c *gin.Context) { return } - // send API call to capture the updated repo - r, _ = database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) - c.JSON(http.StatusOK, r) } diff --git a/api/scm/sync.go b/api/scm/sync.go index b160f5fa0..c98ea82e4 100644 --- a/api/scm/sync.go +++ b/api/scm/sync.go @@ -80,7 +80,7 @@ func SyncRepo(c *gin.Context) { r.SetActive(false) // update repo in database - err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(r) if err != nil { retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) diff --git a/api/scm/sync_org.go b/api/scm/sync_org.go index ac18ec551..9cda091ef 100644 --- a/api/scm/sync_org.go +++ b/api/scm/sync_org.go @@ -113,7 +113,7 @@ func SyncReposForOrg(c *gin.Context) { if err != nil { repo.SetActive(false) - err := database.FromContext(c).UpdateRepo(repo) + _, err := database.FromContext(c).UpdateRepo(repo) if err != nil { retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) diff --git a/api/webhook/post.go b/api/webhook/post.go index 7eab225f5..bae23a863 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -621,7 +621,7 @@ func PostWebhook(c *gin.Context) { } // end of retry loop // send API call to update repo for ensuring counter is incremented - err = database.FromContext(c).UpdateRepo(repo) + repo, err = database.FromContext(c).UpdateRepo(repo) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -759,7 +759,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r } // update repo object in the database after applying edits - err = database.FromContext(c).UpdateRepo(dbRepo) + dbRepo, err = database.FromContext(c).UpdateRepo(dbRepo) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) @@ -891,7 +891,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types dbR.SetPreviousName(r.GetPreviousName()) // update the repo in the database - err = database.FromContext(c).UpdateRepo(dbR) + dbR, err = database.FromContext(c).UpdateRepo(dbR) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s/%s in database", baseErr, prevOrg, prevRepo) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 08e7867cc..e5b1a78c1 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -373,7 +373,7 @@ func processSchedule(s *library.Schedule, compiler compiler.Engine, database dat } // end of retry loop // send API call to update repo for ensuring counter is incremented - err = database.UpdateRepo(r) + r, err = database.UpdateRepo(r) if err != nil { return fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) } diff --git a/database/repo/count_org_test.go b/database/repo/count_org_test.go index 2ff3278f3..fd4797dad 100644 --- a/database/repo/count_org_test.go +++ b/database/repo/count_org_test.go @@ -43,12 +43,12 @@ func TestRepo_Engine_CountReposForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/count_test.go b/database/repo/count_test.go index f63a935e8..104cccc65 100644 --- a/database/repo/count_test.go +++ b/database/repo/count_test.go @@ -43,12 +43,12 @@ func TestRepo_Engine_CountRepos(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/count_user_test.go b/database/repo/count_user_test.go index 654788a69..45ea309ab 100644 --- a/database/repo/count_user_test.go +++ b/database/repo/count_user_test.go @@ -49,12 +49,12 @@ func TestRepo_Engine_CountReposForUser(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/create.go b/database/repo/create.go index fbfda486a..850d854aa 100644 --- a/database/repo/create.go +++ b/database/repo/create.go @@ -15,7 +15,7 @@ import ( ) // CreateRepo creates a new repo in the database. -func (e *engine) CreateRepo(r *library.Repo) error { +func (e *engine) CreateRepo(r *library.Repo) (*library.Repo, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -31,7 +31,7 @@ func (e *engine) CreateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Validate err := repo.Validate() if err != nil { - return err + return nil, err } // encrypt the fields for the repo @@ -39,12 +39,23 @@ func (e *engine) CreateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(e.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) + return nil, fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database - return e.client. - Table(constants.TableRepo). - Create(repo). - Error + err = e.client.Table(constants.TableRepo).Create(repo).Error + if err != nil { + return nil, err + } + + // decrypt the fields for the repo + err = repo.Decrypt(e.config.EncryptionKey) + if err != nil { + // only log to preserve backwards compatibility + e.logger.Errorf("unable to decrypt repo %d: %v", r.GetID(), err) + + return repo.ToLibrary(), nil + } + + return repo.ToLibrary(), nil } diff --git a/database/repo/create_test.go b/database/repo/create_test.go index ac0a86ffa..4241ce4ab 100644 --- a/database/repo/create_test.go +++ b/database/repo/create_test.go @@ -5,6 +5,7 @@ package repo import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -22,6 +23,7 @@ func TestRepo_Engine_CreateRepo(t *testing.T) { _repo.SetVisibility("public") _repo.SetPipelineType("yaml") _repo.SetPreviousName("oldName") + _repo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -60,7 +62,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateRepo(_repo) + got, err := test.database.CreateRepo(_repo) if test.failure { if err == nil { @@ -73,6 +75,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ if err != nil { t.Errorf("CreateRepo for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _repo) { + t.Errorf("CreateRepo for %s returned %s, want %s", test.name, got, _repo) + } }) } } diff --git a/database/repo/delete_test.go b/database/repo/delete_test.go index ccc50eb4a..a4504d6bc 100644 --- a/database/repo/delete_test.go +++ b/database/repo/delete_test.go @@ -32,7 +32,7 @@ func TestRepo_Engine_DeleteRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(_repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go index 2f1dee125..b60faefde 100644 --- a/database/repo/get_org_test.go +++ b/database/repo/get_org_test.go @@ -39,7 +39,7 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(_repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/get_test.go b/database/repo/get_test.go index a1b7a8485..e098626de 100644 --- a/database/repo/get_test.go +++ b/database/repo/get_test.go @@ -39,7 +39,7 @@ func TestRepo_Engine_GetRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(_repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/interface.go b/database/repo/interface.go index a53ad3a0a..1b641da35 100644 --- a/database/repo/interface.go +++ b/database/repo/interface.go @@ -33,7 +33,7 @@ type RepoInterface interface { // CountReposForUser defines a function that gets the count of repos by user ID. CountReposForUser(*library.User, map[string]interface{}) (int64, error) // CreateRepo defines a function that creates a new repo. - CreateRepo(*library.Repo) error + CreateRepo(*library.Repo) (*library.Repo, error) // DeleteRepo defines a function that deletes an existing repo. DeleteRepo(*library.Repo) error // GetRepo defines a function that gets a repo by ID. @@ -47,5 +47,5 @@ type RepoInterface interface { // ListReposForUser defines a function that gets a list of repos by user ID. ListReposForUser(*library.User, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) // UpdateRepo defines a function that updates an existing repo. - UpdateRepo(*library.Repo) error + UpdateRepo(*library.Repo) (*library.Repo, error) } diff --git a/database/repo/list_org_test.go b/database/repo/list_org_test.go index b668aff97..e54a11bf4 100644 --- a/database/repo/list_org_test.go +++ b/database/repo/list_org_test.go @@ -87,12 +87,12 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/list_test.go b/database/repo/list_test.go index 9e359c40f..6936406e6 100644 --- a/database/repo/list_test.go +++ b/database/repo/list_test.go @@ -57,12 +57,12 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/list_user_test.go b/database/repo/list_user_test.go index a65958c39..7bff6fe2c 100644 --- a/database/repo/list_user_test.go +++ b/database/repo/list_user_test.go @@ -92,12 +92,12 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(_repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(_repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/repo/update.go b/database/repo/update.go index 4c31791db..cf7111499 100644 --- a/database/repo/update.go +++ b/database/repo/update.go @@ -15,7 +15,7 @@ import ( ) // UpdateRepo updates an existing repo in the database. -func (e *engine) UpdateRepo(r *library.Repo) error { +func (e *engine) UpdateRepo(r *library.Repo) (*library.Repo, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -31,7 +31,7 @@ func (e *engine) UpdateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Validate err := repo.Validate() if err != nil { - return err + return nil, err } // encrypt the fields for the repo @@ -39,12 +39,23 @@ func (e *engine) UpdateRepo(r *library.Repo) error { // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Encrypt err = repo.Encrypt(e.config.EncryptionKey) if err != nil { - return fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) + return nil, fmt.Errorf("unable to encrypt repo %s: %w", r.GetFullName(), err) } // send query to the database - return e.client. - Table(constants.TableRepo). - Save(repo). - Error + err = e.client.Table(constants.TableRepo).Save(repo).Error + if err != nil { + return nil, err + } + + // decrypt the fields for the repo + err = repo.Decrypt(e.config.EncryptionKey) + if err != nil { + // only log to preserve backwards compatibility + e.logger.Errorf("unable to decrypt repo %d: %v", r.GetID(), err) + + return repo.ToLibrary(), nil + } + + return repo.ToLibrary(), nil } diff --git a/database/repo/update_test.go b/database/repo/update_test.go index 35d4b74bb..66f4fa6a9 100644 --- a/database/repo/update_test.go +++ b/database/repo/update_test.go @@ -5,6 +5,7 @@ package repo import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -22,6 +23,7 @@ func TestRepo_Engine_UpdateRepo(t *testing.T) { _repo.SetVisibility("public") _repo.SetPipelineType("yaml") _repo.SetPreviousName("oldName") + _repo.SetTopics([]string{}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -36,7 +38,7 @@ WHERE "id" = $24`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(_repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -62,7 +64,7 @@ WHERE "id" = $24`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateRepo(_repo) + got, err := test.database.UpdateRepo(_repo) if test.failure { if err == nil { @@ -75,6 +77,10 @@ WHERE "id" = $24`). if err != nil { t.Errorf("UpdateRepo for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _repo) { + t.Errorf("UpdateRepo for %s returned %s, want %s", test.name, got, _repo) + } }) } } diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index d8a540b9c..d0e0733a5 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -94,7 +94,7 @@ func TestBuild_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(want) // setup context @@ -176,7 +176,7 @@ func TestBuild_Establish_NoBuildParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) @@ -224,7 +224,7 @@ func TestBuild_Establish_InvalidBuildParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) @@ -272,7 +272,7 @@ func TestBuild_Establish_NoBuild(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/org/org_test.go b/router/middleware/org/org_test.go index aa64710cc..4c98de87e 100644 --- a/router/middleware/org/org_test.go +++ b/router/middleware/org/org_test.go @@ -69,7 +69,7 @@ func TestOrg_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index 70a88fbf8..a5af1cbbe 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -447,7 +447,7 @@ func TestPerm_MustBuildAccess(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -537,7 +537,7 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) _ = db.CreateUser(u) @@ -622,7 +622,7 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -706,7 +706,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/repo/foo/bar/baz", nil) @@ -787,7 +787,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/org/foo/*/baz", nil) @@ -868,7 +868,7 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/shared/foo/*/*", nil) @@ -949,7 +949,7 @@ func TestPerm_MustAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1047,7 +1047,7 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1145,7 +1145,7 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1243,7 +1243,7 @@ func TestPerm_MustWrite(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1341,7 +1341,7 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1439,7 +1439,7 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1537,7 +1537,7 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1635,7 +1635,7 @@ func TestPerm_MustRead(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1733,7 +1733,7 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1832,7 +1832,7 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { }() _, _ = db.CreateBuild(b) - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -1915,7 +1915,7 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2013,7 +2013,7 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2111,7 +2111,7 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2209,7 +2209,7 @@ func TestPerm_MustRead_NotRead(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index a7c76c892..4e7912372 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -107,7 +107,7 @@ func TestPipeline_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreatePipeline(want) // setup context @@ -189,7 +189,7 @@ func TestPipeline_Establish_NoPipelineParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) @@ -293,7 +293,7 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _ = db.CreateUser(u) // setup context diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index 83051c09c..50b6c8cc7 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -76,7 +76,7 @@ func TestRepo_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(want) + _, _ = db.CreateRepo(want) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index cd057b471..20c84c868 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -84,7 +84,7 @@ func TestService_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) _ = db.CreateService(want) @@ -171,7 +171,7 @@ func TestService_Establish_NoBuild(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) @@ -225,7 +225,7 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context @@ -281,7 +281,7 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context @@ -337,7 +337,7 @@ func TestService_Establish_NoService(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index d0ad740c4..85aa8c246 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -86,7 +86,7 @@ func TestStep_Establish(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) _ = db.CreateStep(want) @@ -173,7 +173,7 @@ func TestStep_Establish_NoBuild(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) // setup context gin.SetMode(gin.TestMode) @@ -227,7 +227,7 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context @@ -283,7 +283,7 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context @@ -339,7 +339,7 @@ func TestStep_Establish_NoStep(t *testing.T) { db.Close() }() - _ = db.CreateRepo(r) + _, _ = db.CreateRepo(r) _, _ = db.CreateBuild(b) // setup context From acbb8f116c4eae082ee6a172cb17cc0cca502eb8 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:50:29 -0600 Subject: [PATCH 280/298] fix(compiler): convert local templates to an engine field for nested templates (#916) * fix(compiler): convert local templates to an engine field for nested templates * add WithLocalTemplates test --- api/pipeline/compile.go | 2 +- api/pipeline/expand.go | 2 +- api/pipeline/validate.go | 2 +- compiler/engine.go | 5 +++- compiler/native/compile.go | 43 ++++----------------------------- compiler/native/compile_test.go | 2 +- compiler/native/expand.go | 27 ++++++++++++++++----- compiler/native/native.go | 24 ++++++++++++------ compiler/native/native_test.go | 20 +++++++++++++++ 9 files changed, 70 insertions(+), 57 deletions(-) diff --git a/api/pipeline/compile.go b/api/pipeline/compile.go index 723bf2522..8ac5fed93 100644 --- a/api/pipeline/compile.go +++ b/api/pipeline/compile.go @@ -97,7 +97,7 @@ func CompilePipeline(c *gin.Context) { compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // compile the pipeline - pipeline, _, err := compiler.CompileLite(p.GetData(), true, true, nil) + pipeline, _, err := compiler.CompileLite(p.GetData(), true, true) if err != nil { retErr := fmt.Errorf("unable to compile pipeline %s: %w", entry, err) diff --git a/api/pipeline/expand.go b/api/pipeline/expand.go index 05e5c7dd8..17f782fee 100644 --- a/api/pipeline/expand.go +++ b/api/pipeline/expand.go @@ -98,7 +98,7 @@ func ExpandPipeline(c *gin.Context) { compiler := compiler.FromContext(c).Duplicate().WithCommit(p.GetCommit()).WithMetadata(m).WithRepo(r).WithUser(u) // expand the templates in the pipeline - pipeline, _, err := compiler.CompileLite(p.GetData(), true, false, nil) + pipeline, _, err := compiler.CompileLite(p.GetData(), true, false) if err != nil { retErr := fmt.Errorf("unable to expand pipeline %s: %w", entry, err) diff --git a/api/pipeline/validate.go b/api/pipeline/validate.go index 42e49e2ae..45aae1ff8 100644 --- a/api/pipeline/validate.go +++ b/api/pipeline/validate.go @@ -105,7 +105,7 @@ func ValidatePipeline(c *gin.Context) { } // validate the pipeline - pipeline, _, err := compiler.CompileLite(p.GetData(), template, false, nil) + pipeline, _, err := compiler.CompileLite(p.GetData(), template, false) if err != nil { retErr := fmt.Errorf("unable to validate pipeline %s: %w", entry, err) diff --git a/compiler/engine.go b/compiler/engine.go index 5d1d32993..0296c99d4 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -25,7 +25,7 @@ type Engine interface { // CompileLite defines a function that produces an light executable // representation of a pipeline from an object. This calls // Parse internally to convert the object to a yaml configuration. - CompileLite(interface{}, bool, bool, []string) (*yaml.Build, *library.Pipeline, error) + CompileLite(interface{}, bool, bool) (*yaml.Build, *library.Pipeline, error) // Duplicate defines a function that // creates a clone of the Engine. @@ -130,6 +130,9 @@ type Engine interface { // WithLocal defines a function that sets // the compiler local field in the Engine. WithLocal(bool) Engine + // WithLocalTemplates defines a function that sets + // the compiler local templates field in the Engine. + WithLocalTemplates([]string) Engine // WithMetadata defines a function that sets // the compiler Metadata type in the Engine. WithMetadata(*types.Metadata) Engine diff --git a/compiler/native/compile.go b/compiler/native/compile.go index f74e19bab..d106fa480 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -82,7 +82,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err switch { case p.Metadata.RenderInline: - newPipeline, err := c.compileInline(p, nil, c.TemplateDepth) + newPipeline, err := c.compileInline(p, c.TemplateDepth) if err != nil { return nil, _pipeline, err } @@ -105,7 +105,7 @@ func (c *client) Compile(v interface{}) (*pipeline.Build, *library.Pipeline, err } // CompileLite produces a partial of an executable pipeline from a yaml configuration. -func (c *client) CompileLite(v interface{}, template, substitute bool, localTemplates []string) (*yaml.Build, *library.Pipeline, error) { +func (c *client) CompileLite(v interface{}, template, substitute bool) (*yaml.Build, *library.Pipeline, error) { p, data, err := c.Parse(v, c.repo.GetPipelineType(), new(yaml.Template)) if err != nil { return nil, nil, err @@ -117,7 +117,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp _pipeline.SetType(c.repo.GetPipelineType()) if p.Metadata.RenderInline { - newPipeline, err := c.compileInline(p, localTemplates, c.TemplateDepth) + newPipeline, err := c.compileInline(p, c.TemplateDepth) if err != nil { return nil, _pipeline, err } @@ -134,24 +134,6 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp // create map of templates for easy lookup templates := mapFromTemplates(p.Templates) - if c.local { - for _, file := range localTemplates { - // local templates override format is : - // - // example: example:/path/to/template.yml - parts := strings.Split(file, ":") - - // make sure the template was configured - _, ok := templates[parts[0]] - if !ok { - return nil, _pipeline, fmt.Errorf("template with name %s is not configured", parts[0]) - } - - // override the source for the given template - templates[parts[0]].Source = parts[1] - } - } - switch { case len(p.Stages) > 0: // inject the templates into the steps @@ -194,7 +176,7 @@ func (c *client) CompileLite(v interface{}, template, substitute bool, localTemp } // compileInline parses and expands out inline pipelines. -func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int) (*yaml.Build, error) { +func (c *client) compileInline(p *yaml.Build, depth int) (*yaml.Build, error) { newPipeline := *p newPipeline.Templates = yaml.TemplateSlice{} @@ -206,21 +188,6 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int } for _, template := range p.Templates { - if c.local { - for _, file := range localTemplates { - // local templates override format is : - // - // example: example:/path/to/template.yml - parts := strings.Split(file, ":") - - // make sure we're referencing the proper template - if parts[0] == template.Name { - // override the source for the given template - template.Source = parts[1] - } - } - } - bytes, err := c.getTemplate(template, template.Name) if err != nil { return nil, err @@ -240,7 +207,7 @@ func (c *client) compileInline(p *yaml.Build, localTemplates []string, depth int // if template parsed contains a template reference, recurse with decremented depth if len(parsed.Templates) > 0 && parsed.Metadata.RenderInline { - parsed, err = c.compileInline(parsed, localTemplates, depth-1) + parsed, err = c.compileInline(parsed, depth-1) if err != nil { return nil, err } diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 5281dccd1..3a37703d6 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -3422,7 +3422,7 @@ func Test_CompileLite(t *testing.T) { t.Errorf("Reading yaml file return err: %v", err) } - got, _, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute, nil) + got, _, err := compiler.CompileLite(yaml, tt.args.template, tt.args.substitute) if (err != nil) != tt.wantErr { t.Errorf("CompileLite() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/compiler/native/expand.go b/compiler/native/expand.go index 5314cf25e..d593bc26e 100644 --- a/compiler/native/expand.go +++ b/compiler/native/expand.go @@ -206,15 +206,30 @@ func (c *client) getTemplate(tmpl *yaml.Template, name string) ([]byte, error) { switch { case c.local: - a := &afero.Afero{ - Fs: afero.NewOsFs(), - } + // iterate over locally provided templates + for _, t := range c.localTemplates { + parts := strings.Split(t, ":") + if len(parts) != 2 { + return nil, fmt.Errorf("local templates must be provided in the form :, got %s", t) + } - bytes, err = a.ReadFile(tmpl.Source) - if err != nil { - return bytes, err + if strings.EqualFold(tmpl.Name, parts[0]) { + a := &afero.Afero{ + Fs: afero.NewOsFs(), + } + + bytes, err = a.ReadFile(parts[1]) + if err != nil { + return bytes, err + } + + return bytes, nil + } } + // no template found in provided templates, exit with error + return nil, fmt.Errorf("unable to find template %s: not supplied in list %s", tmpl.Name, c.localTemplates) + case strings.EqualFold(tmpl.Type, "github"): // parse source from template src, err := c.Github.Parse(tmpl.Source) diff --git a/compiler/native/native.go b/compiler/native/native.go index 733a32407..c394af933 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -34,14 +34,15 @@ type client struct { CloneImage string TemplateDepth int - build *library.Build - comment string - commit string - files []string - local bool - metadata *types.Metadata - repo *library.Repo - user *library.User + build *library.Build + comment string + commit string + files []string + local bool + localTemplates []string + metadata *types.Metadata + repo *library.Repo + user *library.User } // New returns a Pipeline implementation that integrates with the supported registries. @@ -161,6 +162,13 @@ func (c *client) WithLocal(local bool) compiler.Engine { return c } +// WithLocalTemplates sets the compiler local templates in the Engine. +func (c *client) WithLocalTemplates(templates []string) compiler.Engine { + c.localTemplates = templates + + return c +} + // WithMetadata sets the compiler metadata type in the Engine. func (c *client) WithMetadata(m *types.Metadata) compiler.Engine { if m != nil { diff --git a/compiler/native/native_test.go b/compiler/native/native_test.go index 62c6fb7ed..de1f60631 100644 --- a/compiler/native/native_test.go +++ b/compiler/native/native_test.go @@ -202,6 +202,26 @@ func TestNative_WithLocal(t *testing.T) { } } +func TestNative_WithLocalTemplates(t *testing.T) { + // setup types + set := flag.NewFlagSet("test", 0) + c := cli.NewContext(nil, set, nil) + + localTemplates := []string{"example:tmpl.yml", "exmpl:template.yml"} + want, _ := New(c) + want.localTemplates = []string{"example:tmpl.yml", "exmpl:template.yml"} + + // run test + got, err := New(c) + if err != nil { + t.Errorf("Unable to create new compiler: %v", err) + } + + if !reflect.DeepEqual(got.WithLocalTemplates(localTemplates), want) { + t.Errorf("WithLocalTemplates is %v, want %v", got, want) + } +} + func TestNative_WithMetadata(t *testing.T) { // setup types set := flag.NewFlagSet("test", 0) From 02fcd745ee7142d656a7b75936501e6641055382 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Thu, 27 Jul 2023 08:54:55 -0600 Subject: [PATCH 281/298] chore(release): upgrade types to v0.20.1 (#918) * chore(release): upgrade types to v0.20.1 * other deps --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 9286615af..b9ac96ee1 100644 --- a/go.mod +++ b/go.mod @@ -7,14 +7,14 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/adhocore/gronx v1.6.3 + github.com/adhocore/gronx v1.6.4 github.com/alicebob/miniredis/v2 v2.30.4 - github.com/aws/aws-sdk-go v1.44.298 + github.com/aws/aws-sdk-go v1.44.309 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.20.0 + github.com/go-vela/types v0.20.1 github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v53 v53.2.0 @@ -31,14 +31,14 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.25.7 - go.starlark.net v0.0.0-20230712173630-2226322290fc + go.starlark.net v0.0.0-20230725161458-0d7263928a74 golang.org/x/oauth2 v0.9.0 golang.org/x/sync v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 gorm.io/gorm v1.25.2 - k8s.io/apimachinery v0.27.3 + k8s.io/apimachinery v0.27.4 ) require ( @@ -94,7 +94,7 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microcosm-cc/bluemonday v1.0.24 // indirect + github.com/microcosm-cc/bluemonday v1.0.25 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -115,10 +115,10 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.10.0 // indirect - golang.org/x/net v0.11.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index 978abf40d..32499db9b 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/adhocore/gronx v1.6.3 h1:bnm5vieTrY3QQPpsfB0hrAaeaHDpuZTUC2LLCVMLe9c= -github.com/adhocore/gronx v1.6.3/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= +github.com/adhocore/gronx v1.6.4 h1:Bx5cNRVQsGquOOUJL3+2M5vlz1KCCMHrCECwb5UghNU= +github.com/adhocore/gronx v1.6.4/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= @@ -66,8 +66,8 @@ github.com/alicebob/miniredis/v2 v2.11.1/go.mod h1:UA48pmi7aSazcGAvcdKcBB49z521I github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.44.298 h1:5qTxdubgV7PptZJmp/2qDwD2JL187ePL7VOxsSh1i3g= -github.com/aws/aws-sdk-go v1.44.298/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.309 h1:IPJOFBzXekakxmEpDwd4RTKmmBR6LIAiXgNsM51bWbU= +github.com/aws/aws-sdk-go v1.44.309/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -142,8 +142,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.20.0 h1:u/wHwc6ElVbIEI+q9TaVl9Iai1EoEr4Lwis6mikOte8= -github.com/go-vela/types v0.20.0/go.mod h1:1ZSmKWX9MamKogwaIb53mzzRpZMV34mJFKiGfVFadFk= +github.com/go-vela/types v0.20.1 h1:hHAX0Iij2J7UZ9f3SlXbwNy481CjKzU9CBfkiLuysVE= +github.com/go-vela/types v0.20.1/go.mod h1:AXO4oQSygOBQ02fPapsKjQHkx2aQO3zTu7clpvVbXBY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -308,8 +308,8 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw= -github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8= +github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= +github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -400,8 +400,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.starlark.net v0.0.0-20230712173630-2226322290fc h1:x7dWtxLF8z8E5/+KkK3MJJTK/kBZhTCLmYCk75rhKxk= -go.starlark.net v0.0.0-20230712173630-2226322290fc/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.starlark.net v0.0.0-20230725161458-0d7263928a74 h1:EL8MuNFlzO8vvpHgZxDGPaehP0ozoJ1j1zA768zKXUQ= +go.starlark.net v0.0.0-20230725161458-0d7263928a74/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -415,8 +415,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -486,8 +486,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -558,8 +558,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -574,8 +574,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -755,8 +755,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= +k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= From adf4f65506e720803344d4874f62ba53900459d8 Mon Sep 17 00:00:00 2001 From: Jordan Brockopp Date: Mon, 31 Jul 2023 16:30:40 -0500 Subject: [PATCH 282/298] feat(database): add integration testing (#896) --- .github/workflows/integration-test.yml | 49 + .github/workflows/test.yml | 4 +- Makefile | 14 +- database/hook/table.go | 2 +- database/integration_test.go | 2255 ++++++++++++++++++++++++ database/log/list_build.go | 1 + database/log/list_build_test.go | 2 +- go.mod | 1 + go.sum | 4 +- 9 files changed, 2322 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/integration-test.yml create mode 100644 database/integration_test.go diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 000000000..655ec6c0e --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,49 @@ +# name of the action +name: integration-test + +# trigger on pull_request events that modify this file or any database files +on: + pull_request: + paths: + - '.github/workflows/integration-test.yml' + - 'database/**' + +# pipeline to execute +jobs: + database: + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:15-alpine + env: + POSTGRES_DB: vela + POSTGRES_PASSWORD: notARealPassword12345 + POSTGRES_USER: vela + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + env: + POSTGRES_ADDR: postgres://vela:notARealPassword12345@localhost:5432/vela + SQLITE_ADDR: vela.db + + steps: + - name: clone + uses: actions/checkout@v3 + + - name: install go + uses: actions/setup-go@v4 + with: + # use version from go.mod file + go-version-file: 'go.mod' + cache: true + check-latest: true + + - name: test + run: | + make integration-test \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3cf03420..cdc0c6aa3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,10 +25,10 @@ jobs: - name: test run: | - go test -race -covermode=atomic -coverprofile=coverage.out ./... + make test - name: coverage uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - file: coverage.out + file: coverage.out \ No newline at end of file diff --git a/Makefile b/Makefile index 61dce5988..f46e05a3f 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,13 @@ fix: @echo "### Fixing Go Code" @go fix ./... +# The `integration-test` target is intended to run all integration tests for the Go source code. +.PHONY: integration-test +integration-test: + @echo + @echo "### Integration Testing" + INTEGRATION=1 go test -run TestDatabase_Integration ./... + # The `test` target is intended to run # the tests for the Go source code. # @@ -99,7 +106,7 @@ fix: test: @echo @echo "### Testing Go Code" - @go test -race ./... + @go test -race -covermode=atomic -coverprofile=coverage.out ./... # The `test-cover` target is intended to run # the tests for the Go source code and then @@ -107,10 +114,7 @@ test: # # Usage: `make test-cover` .PHONY: test-cover -test-cover: - @echo - @echo "### Creating test coverage report" - @go test -race -covermode=atomic -coverprofile=coverage.out ./... +test-cover: test @echo @echo "### Opening test coverage report" @go tool cover -html=coverage.out diff --git a/database/hook/table.go b/database/hook/table.go index 9be4616c4..90419508f 100644 --- a/database/hook/table.go +++ b/database/hook/table.go @@ -51,7 +51,7 @@ hooks ( status TEXT, link TEXT, webhook_id INTEGER, - UNIQUE(repo_id, build_id) + UNIQUE(repo_id, number) ); ` ) diff --git a/database/integration_test.go b/database/integration_test.go new file mode 100644 index 000000000..2cebb815a --- /dev/null +++ b/database/integration_test.go @@ -0,0 +1,2255 @@ +// 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 ( + "os" + "reflect" + "strings" + "testing" + "time" + + "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/hook" + "github.com/go-vela/server/database/log" + "github.com/go-vela/server/database/pipeline" + "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/schedule" + "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/user" + "github.com/go-vela/server/database/worker" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/raw" +) + +// Resources represents the object containing test resources. +type Resources struct { + Builds []*library.Build + Deployments []*library.Deployment + Hooks []*library.Hook + Logs []*library.Log + Pipelines []*library.Pipeline + Repos []*library.Repo + Schedules []*library.Schedule + Secrets []*library.Secret + Services []*library.Service + Steps []*library.Step + Users []*library.User + Workers []*library.Worker +} + +func TestDatabase_Integration(t *testing.T) { + // check if we should skip the integration test + // + // https://konradreiche.com/blog/how-to-separate-integration-tests-in-go + if os.Getenv("INTEGRATION") == "" { + t.Skipf("skipping %s integration test due to environment variable constraint", t.Name()) + } + + // setup tests + tests := []struct { + name string + config *config + }{ + { + name: "postgres", + config: &config{ + Driver: "postgres", + Address: os.Getenv("POSTGRES_ADDR"), + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + { + name: "sqlite3", + config: &config{ + Driver: "sqlite3", + Address: os.Getenv("SQLITE_ADDR"), + CompressionLevel: 3, + ConnectionLife: 10 * time.Second, + ConnectionIdle: 5, + ConnectionOpen: 20, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // create resources for testing + resources := newResources() + + db, err := New( + WithAddress(test.config.Address), + WithCompressionLevel(test.config.CompressionLevel), + WithConnectionLife(test.config.ConnectionLife), + WithConnectionIdle(test.config.ConnectionIdle), + WithConnectionOpen(test.config.ConnectionOpen), + WithDriver(test.config.Driver), + WithEncryptionKey(test.config.EncryptionKey), + WithSkipCreation(test.config.SkipCreation), + ) + if err != nil { + t.Errorf("unable to create new database engine for %s: %v", test.name, err) + } + + driver := db.Driver() + if !strings.EqualFold(driver, test.config.Driver) { + t.Errorf("Driver() is %v, want %v", driver, test.config.Driver) + } + + err = db.Ping() + if err != nil { + t.Errorf("unable to ping database engine for %s: %v", test.name, err) + } + + t.Run("test_builds", func(t *testing.T) { testBuilds(t, db, resources) }) + + t.Run("test_hooks", func(t *testing.T) { testHooks(t, db, resources) }) + + t.Run("test_logs", func(t *testing.T) { testLogs(t, db, resources) }) + + t.Run("test_pipelines", func(t *testing.T) { testPipelines(t, db, resources) }) + + t.Run("test_repos", func(t *testing.T) { testRepos(t, db, resources) }) + + t.Run("test_schedules", func(t *testing.T) { testSchedules(t, db, resources) }) + + t.Run("test_secrets", func(t *testing.T) { testSecrets(t, db, resources) }) + + t.Run("test_services", func(t *testing.T) { testServices(t, db, resources) }) + + t.Run("test_steps", func(t *testing.T) { testSteps(t, db, resources) }) + + t.Run("test_users", func(t *testing.T) { testUsers(t, db, resources) }) + + t.Run("test_workers", func(t *testing.T) { testWorkers(t, db, resources) }) + + err = db.Close() + if err != nil { + t.Errorf("unable to close database engine for %s: %v", test.name, err) + } + }) + } +} + +func testBuilds(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for builds + methods := make(map[string]bool) + // capture the element type of the build interface + element := reflect.TypeOf(new(build.BuildInterface)).Elem() + // iterate through all methods found in the build interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for builds + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the repos for build related functions + for _, repo := range resources.Repos { + _, err := db.CreateRepo(repo) + if err != nil { + t.Errorf("unable to create repo %d: %v", repo.GetID(), err) + } + } + + buildOne := new(library.BuildQueue) + buildOne.SetCreated(1563474076) + buildOne.SetFullName("github/octocat") + buildOne.SetNumber(1) + buildOne.SetStatus("running") + + buildTwo := new(library.BuildQueue) + buildTwo.SetCreated(1563474076) + buildTwo.SetFullName("github/octocat") + buildTwo.SetNumber(2) + buildTwo.SetStatus("running") + + queueBuilds := []*library.BuildQueue{buildOne, buildTwo} + + // create the builds + for _, build := range resources.Builds { + _, err := db.CreateBuild(build) + if err != nil { + t.Errorf("unable to create build %d: %v", build.GetID(), err) + } + } + methods["CreateBuild"] = true + + // count the builds + count, err := db.CountBuilds() + if err != nil { + t.Errorf("unable to count builds: %v", err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountBuilds() is %v, want %v", count, len(resources.Builds)) + } + methods["CountBuilds"] = true + + // count the builds for a deployment + count, err = db.CountBuildsForDeployment(resources.Deployments[0], nil) + if err != nil { + t.Errorf("unable to count builds for deployment %d: %v", resources.Deployments[0].GetID(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountBuildsForDeployment() is %v, want %v", count, len(resources.Builds)) + } + methods["CountBuildsForDeployment"] = true + + // count the builds for an org + count, err = db.CountBuildsForOrg(resources.Repos[0].GetOrg(), nil) + if err != nil { + t.Errorf("unable to count builds for org %s: %v", resources.Repos[0].GetOrg(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountBuildsForOrg() is %v, want %v", count, len(resources.Builds)) + } + methods["CountBuildsForOrg"] = true + + // count the builds for a repo + count, err = db.CountBuildsForRepo(resources.Repos[0], nil) + if err != nil { + t.Errorf("unable to count builds for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountBuildsForRepo() is %v, want %v", count, len(resources.Builds)) + } + methods["CountBuildsForRepo"] = true + + // count the builds for a status + count, err = db.CountBuildsForStatus("running", nil) + if err != nil { + t.Errorf("unable to count builds for status %s: %v", "running", err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountBuildsForStatus() is %v, want %v", count, len(resources.Builds)) + } + methods["CountBuildsForStatus"] = true + + // list the builds + list, err := db.ListBuilds() + if err != nil { + t.Errorf("unable to list builds: %v", err) + } + if !reflect.DeepEqual(list, resources.Builds) { + t.Errorf("ListBuilds() is %v, want %v", list, resources.Builds) + } + methods["ListBuilds"] = true + + // list the builds for a deployment + list, count, err = db.ListBuildsForDeployment(resources.Deployments[0], nil, 1, 10) + if err != nil { + t.Errorf("unable to list builds for deployment %d: %v", resources.Deployments[0].GetID(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("ListBuildsForDeployment() is %v, want %v", count, len(resources.Builds)) + } + if !reflect.DeepEqual(list, []*library.Build{resources.Builds[1], resources.Builds[0]}) { + t.Errorf("ListBuildsForDeployment() is %v, want %v", list, []*library.Build{resources.Builds[1], resources.Builds[0]}) + } + methods["ListBuildsForDeployment"] = true + + // list the builds for an org + list, count, err = db.ListBuildsForOrg(resources.Repos[0].GetOrg(), nil, 1, 10) + if err != nil { + t.Errorf("unable to list builds for org %s: %v", resources.Repos[0].GetOrg(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("ListBuildsForOrg() is %v, want %v", count, len(resources.Builds)) + } + if !reflect.DeepEqual(list, resources.Builds) { + t.Errorf("ListBuildsForOrg() is %v, want %v", list, resources.Builds) + } + methods["ListBuildsForOrg"] = true + + // list the builds for a repo + list, count, err = db.ListBuildsForRepo(resources.Repos[0], nil, time.Now().UTC().Unix(), 0, 1, 10) + if err != nil { + t.Errorf("unable to list builds for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("ListBuildsForRepo() is %v, want %v", count, len(resources.Builds)) + } + if !reflect.DeepEqual(list, []*library.Build{resources.Builds[1], resources.Builds[0]}) { + t.Errorf("ListBuildsForRepo() is %v, want %v", list, []*library.Build{resources.Builds[1], resources.Builds[0]}) + } + methods["ListBuildsForRepo"] = true + + // list the pending and running builds + queueList, err := db.ListPendingAndRunningBuilds("0") + if err != nil { + t.Errorf("unable to list pending and running builds: %v", err) + } + if !reflect.DeepEqual(queueList, queueBuilds) { + t.Errorf("ListPendingAndRunningBuilds() is %v, want %v", queueList, queueBuilds) + } + methods["ListPendingAndRunningBuilds"] = true + + // lookup the last build by repo + got, err := db.LastBuildForRepo(resources.Repos[0], "main") + if err != nil { + t.Errorf("unable to get last build for repo %d: %v", resources.Repos[0].GetID(), err) + } + if !reflect.DeepEqual(got, resources.Builds[1]) { + t.Errorf("LastBuildForRepo() is %v, want %v", got, resources.Builds[1]) + } + methods["LastBuildForRepo"] = true + + // lookup the builds by repo and number + for _, build := range resources.Builds { + repo := resources.Repos[build.GetRepoID()-1] + got, err = db.GetBuildForRepo(repo, build.GetNumber()) + if err != nil { + t.Errorf("unable to get build %d for repo %d: %v", build.GetID(), repo.GetID(), err) + } + if !reflect.DeepEqual(got, build) { + t.Errorf("GetBuildForRepo() is %v, want %v", got, build) + } + } + methods["GetBuildForRepo"] = true + + // clean the builds + count, err = db.CleanBuilds("integration testing", 1563474090) + if err != nil { + t.Errorf("unable to clean builds: %v", err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CleanBuilds() is %v, want %v", count, len(resources.Builds)) + } + methods["CleanBuilds"] = true + + // update the builds + for _, build := range resources.Builds { + build.SetStatus("success") + _, err = db.UpdateBuild(build) + if err != nil { + t.Errorf("unable to update build %d: %v", build.GetID(), err) + } + + // lookup the build by ID + got, err = db.GetBuild(build.GetID()) + if err != nil { + t.Errorf("unable to get build %d by ID: %v", build.GetID(), err) + } + if !reflect.DeepEqual(got, build) { + t.Errorf("GetBuild() is %v, want %v", got, build) + } + } + methods["UpdateBuild"] = true + methods["GetBuild"] = true + + // delete the builds + for _, build := range resources.Builds { + err = db.DeleteBuild(build) + if err != nil { + t.Errorf("unable to delete build %d: %v", build.GetID(), err) + } + } + methods["DeleteBuild"] = true + + // delete the repos for build related functions + for _, repo := range resources.Repos { + err = db.DeleteRepo(repo) + if err != nil { + t.Errorf("unable to delete repo %d: %v", repo.GetID(), err) + } + } + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for builds", method) + } + } +} + +func testHooks(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for hooks + methods := make(map[string]bool) + // capture the element type of the hook interface + element := reflect.TypeOf(new(hook.HookInterface)).Elem() + // iterate through all methods found in the hook interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for hooks + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the hooks + for _, hook := range resources.Hooks { + _, err := db.CreateHook(hook) + if err != nil { + t.Errorf("unable to create hook %d: %v", hook.GetID(), err) + } + } + methods["CreateHook"] = true + + // count the hooks + count, err := db.CountHooks() + if err != nil { + t.Errorf("unable to count hooks: %v", err) + } + if int(count) != len(resources.Hooks) { + t.Errorf("CountHooks() is %v, want %v", count, len(resources.Hooks)) + } + methods["CountHooks"] = true + + // count the hooks for a repo + count, err = db.CountHooksForRepo(resources.Repos[0]) + if err != nil { + t.Errorf("unable to count hooks for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Builds) { + t.Errorf("CountHooksForRepo() is %v, want %v", count, len(resources.Builds)) + } + methods["CountHooksForRepo"] = true + + // list the hooks + list, err := db.ListHooks() + if err != nil { + t.Errorf("unable to list hooks: %v", err) + } + if !reflect.DeepEqual(list, resources.Hooks) { + t.Errorf("ListHooks() is %v, want %v", list, resources.Hooks) + } + methods["ListHooks"] = true + + // list the hooks for a repo + list, count, err = db.ListHooksForRepo(resources.Repos[0], 1, 10) + if err != nil { + t.Errorf("unable to list hooks for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Hooks) { + t.Errorf("ListHooksForRepo() is %v, want %v", count, len(resources.Hooks)) + } + if !reflect.DeepEqual(list, []*library.Hook{resources.Hooks[1], resources.Hooks[0]}) { + t.Errorf("ListHooksForRepo() is %v, want %v", list, []*library.Hook{resources.Hooks[1], resources.Hooks[0]}) + } + methods["ListHooksForRepo"] = true + + // lookup the last build by repo + got, err := db.LastHookForRepo(resources.Repos[0]) + if err != nil { + t.Errorf("unable to get last hook for repo %d: %v", resources.Repos[0].GetID(), err) + } + if !reflect.DeepEqual(got, resources.Hooks[1]) { + t.Errorf("LastHookForRepo() is %v, want %v", got, resources.Hooks[1]) + } + methods["LastHookForRepo"] = true + + // lookup the hooks by name + for _, hook := range resources.Hooks { + repo := resources.Repos[hook.GetRepoID()-1] + got, err = db.GetHookForRepo(repo, hook.GetNumber()) + if err != nil { + t.Errorf("unable to get hook %d for repo %d: %v", hook.GetID(), repo.GetID(), err) + } + if !reflect.DeepEqual(got, hook) { + t.Errorf("GetHookForRepo() is %v, want %v", got, hook) + } + } + methods["GetHookForRepo"] = true + + // update the hooks + for _, hook := range resources.Hooks { + hook.SetStatus("success") + _, err = db.UpdateHook(hook) + if err != nil { + t.Errorf("unable to update hook %d: %v", hook.GetID(), err) + } + + // lookup the hook by ID + got, err = db.GetHook(hook.GetID()) + if err != nil { + t.Errorf("unable to get hook %d by ID: %v", hook.GetID(), err) + } + if !reflect.DeepEqual(got, hook) { + t.Errorf("GetHook() is %v, want %v", got, hook) + } + } + methods["UpdateHook"] = true + methods["GetHook"] = true + + // delete the hooks + for _, hook := range resources.Hooks { + err = db.DeleteHook(hook) + if err != nil { + t.Errorf("unable to delete hook %d: %v", hook.GetID(), err) + } + } + methods["DeleteHook"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for hooks", method) + } + } +} + +func testLogs(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for logs + methods := make(map[string]bool) + // capture the element type of the log interface + element := reflect.TypeOf(new(log.LogInterface)).Elem() + // iterate through all methods found in the log interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for logs + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the logs + for _, log := range resources.Logs { + err := db.CreateLog(log) + if err != nil { + t.Errorf("unable to create log %d: %v", log.GetID(), err) + } + } + methods["CreateLog"] = true + + // count the logs + count, err := db.CountLogs() + if err != nil { + t.Errorf("unable to count logs: %v", err) + } + if int(count) != len(resources.Logs) { + t.Errorf("CountLogs() is %v, want %v", count, len(resources.Logs)) + } + methods["CountLogs"] = true + + // count the logs for a build + count, err = db.CountLogsForBuild(resources.Builds[0]) + if err != nil { + t.Errorf("unable to count logs for build %d: %v", resources.Builds[0].GetID(), err) + } + if int(count) != len(resources.Logs) { + t.Errorf("CountLogs() is %v, want %v", count, len(resources.Logs)) + } + methods["CountLogsForBuild"] = true + + // list the logs + list, err := db.ListLogs() + if err != nil { + t.Errorf("unable to list logs: %v", err) + } + if !reflect.DeepEqual(list, resources.Logs) { + t.Errorf("ListLogs() is %v, want %v", list, resources.Logs) + } + methods["ListLogs"] = true + + // list the logs for a build + list, count, err = db.ListLogsForBuild(resources.Builds[0], 1, 10) + if err != nil { + t.Errorf("unable to list logs for build %d: %v", resources.Builds[0].GetID(), err) + } + if int(count) != len(resources.Logs) { + t.Errorf("ListLogsForBuild() is %v, want %v", count, len(resources.Logs)) + } + if !reflect.DeepEqual(list, resources.Logs) { + t.Errorf("ListLogsForBuild() is %v, want %v", list, resources.Logs) + } + methods["ListLogsForBuild"] = true + + // lookup the logs by service + for _, log := range []*library.Log{resources.Logs[0], resources.Logs[1]} { + service := resources.Services[log.GetServiceID()-1] + got, err := db.GetLogForService(service) + if err != nil { + t.Errorf("unable to get log %d for service %d: %v", log.GetID(), service.GetID(), err) + } + if !reflect.DeepEqual(got, log) { + t.Errorf("GetLogForService() is %v, want %v", got, log) + } + } + methods["GetLogForService"] = true + + // lookup the logs by service + for _, log := range []*library.Log{resources.Logs[2], resources.Logs[3]} { + step := resources.Steps[log.GetStepID()-1] + got, err := db.GetLogForStep(step) + if err != nil { + t.Errorf("unable to get log %d for step %d: %v", log.GetID(), step.GetID(), err) + } + if !reflect.DeepEqual(got, log) { + t.Errorf("GetLogForStep() is %v, want %v", got, log) + } + } + methods["GetLogForStep"] = true + + // update the logs + for _, log := range resources.Logs { + log.SetData([]byte("bar")) + err = db.UpdateLog(log) + if err != nil { + t.Errorf("unable to update log %d: %v", log.GetID(), err) + } + + // lookup the log by ID + got, err := db.GetLog(log.GetID()) + if err != nil { + t.Errorf("unable to get log %d by ID: %v", log.GetID(), err) + } + if !reflect.DeepEqual(got, log) { + t.Errorf("GetLog() is %v, want %v", got, log) + } + } + methods["UpdateLog"] = true + methods["GetLog"] = true + + // delete the logs + for _, log := range resources.Logs { + err = db.DeleteLog(log) + if err != nil { + t.Errorf("unable to delete log %d: %v", log.GetID(), err) + } + } + methods["DeleteLog"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for logs", method) + } + } +} + +func testPipelines(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for pipelines + methods := make(map[string]bool) + // capture the element type of the pipeline interface + element := reflect.TypeOf(new(pipeline.PipelineInterface)).Elem() + // iterate through all methods found in the pipeline interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for pipelines + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the pipelines + for _, pipeline := range resources.Pipelines { + _, err := db.CreatePipeline(pipeline) + if err != nil { + t.Errorf("unable to create pipeline %d: %v", pipeline.GetID(), err) + } + } + methods["CreatePipeline"] = true + + // count the pipelines + count, err := db.CountPipelines() + if err != nil { + t.Errorf("unable to count pipelines: %v", err) + } + if int(count) != len(resources.Pipelines) { + t.Errorf("CountPipelines() is %v, want %v", count, len(resources.Pipelines)) + } + methods["CountPipelines"] = true + + // count the pipelines for a repo + count, err = db.CountPipelinesForRepo(resources.Repos[0]) + if err != nil { + t.Errorf("unable to count pipelines for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Pipelines) { + t.Errorf("CountPipelinesForRepo() is %v, want %v", count, len(resources.Pipelines)) + } + methods["CountPipelinesForRepo"] = true + + // list the pipelines + list, err := db.ListPipelines() + if err != nil { + t.Errorf("unable to list pipelines: %v", err) + } + if !reflect.DeepEqual(list, resources.Pipelines) { + t.Errorf("ListPipelines() is %v, want %v", list, resources.Pipelines) + } + methods["ListPipelines"] = true + + // list the pipelines for a repo + list, count, err = db.ListPipelinesForRepo(resources.Repos[0], 1, 10) + if err != nil { + t.Errorf("unable to list pipelines for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Pipelines) { + t.Errorf("ListPipelinesForRepo() is %v, want %v", count, len(resources.Pipelines)) + } + if !reflect.DeepEqual(list, resources.Pipelines) { + t.Errorf("ListPipelines() is %v, want %v", list, resources.Pipelines) + } + methods["ListPipelinesForRepo"] = true + + // lookup the pipelines by name + for _, pipeline := range resources.Pipelines { + repo := resources.Repos[pipeline.GetRepoID()-1] + got, err := db.GetPipelineForRepo(pipeline.GetCommit(), repo) + if err != nil { + t.Errorf("unable to get pipeline %d for repo %d: %v", pipeline.GetID(), repo.GetID(), err) + } + if !reflect.DeepEqual(got, pipeline) { + t.Errorf("GetPipelineForRepo() is %v, want %v", got, pipeline) + } + } + methods["GetPipelineForRepo"] = true + + // update the pipelines + for _, pipeline := range resources.Pipelines { + pipeline.SetVersion("2") + _, err = db.UpdatePipeline(pipeline) + if err != nil { + t.Errorf("unable to update pipeline %d: %v", pipeline.GetID(), err) + } + + // lookup the pipeline by ID + got, err := db.GetPipeline(pipeline.GetID()) + if err != nil { + t.Errorf("unable to get pipeline %d by ID: %v", pipeline.GetID(), err) + } + if !reflect.DeepEqual(got, pipeline) { + t.Errorf("GetPipeline() is %v, want %v", got, pipeline) + } + } + methods["UpdatePipeline"] = true + methods["GetPipeline"] = true + + // delete the pipelines + for _, pipeline := range resources.Pipelines { + err = db.DeletePipeline(pipeline) + if err != nil { + t.Errorf("unable to delete pipeline %d: %v", pipeline.GetID(), err) + } + } + methods["DeletePipeline"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for pipelines", method) + } + } +} + +func testRepos(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for repos + methods := make(map[string]bool) + // capture the element type of the repo interface + element := reflect.TypeOf(new(repo.RepoInterface)).Elem() + // iterate through all methods found in the repo interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for repos + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the repos + for _, repo := range resources.Repos { + _, err := db.CreateRepo(repo) + if err != nil { + t.Errorf("unable to create repo %d: %v", repo.GetID(), err) + } + } + methods["CreateRepo"] = true + + // count the repos + count, err := db.CountRepos() + if err != nil { + t.Errorf("unable to count repos: %v", err) + } + if int(count) != len(resources.Repos) { + t.Errorf("CountRepos() is %v, want %v", count, len(resources.Repos)) + } + methods["CountRepos"] = true + + // count the repos for an org + count, err = db.CountReposForOrg(resources.Repos[0].GetOrg(), nil) + if err != nil { + t.Errorf("unable to count repos for org %s: %v", resources.Repos[0].GetOrg(), err) + } + if int(count) != len(resources.Repos) { + t.Errorf("CountReposForOrg() is %v, want %v", count, len(resources.Repos)) + } + methods["CountReposForOrg"] = true + + // count the repos for a user + count, err = db.CountReposForUser(resources.Users[0], nil) + if err != nil { + t.Errorf("unable to count repos for user %d: %v", resources.Users[0].GetID(), err) + } + if int(count) != len(resources.Repos) { + t.Errorf("CountReposForUser() is %v, want %v", count, len(resources.Repos)) + } + methods["CountReposForUser"] = true + + // list the repos + list, err := db.ListRepos() + if err != nil { + t.Errorf("unable to list repos: %v", err) + } + if !reflect.DeepEqual(list, resources.Repos) { + t.Errorf("ListRepos() is %v, want %v", list, resources.Repos) + } + methods["ListRepos"] = true + + // list the repos for an org + list, count, err = db.ListReposForOrg(resources.Repos[0].GetOrg(), "name", nil, 1, 10) + if err != nil { + t.Errorf("unable to list repos for org %s: %v", resources.Repos[0].GetOrg(), err) + } + if int(count) != len(resources.Repos) { + t.Errorf("ListReposForOrg() is %v, want %v", count, len(resources.Repos)) + } + if !reflect.DeepEqual(list, resources.Repos) { + t.Errorf("ListReposForOrg() is %v, want %v", list, resources.Repos) + } + methods["ListReposForOrg"] = true + + // list the repos for a user + list, count, err = db.ListReposForUser(resources.Users[0], "name", nil, 1, 10) + if err != nil { + t.Errorf("unable to list repos for user %d: %v", resources.Users[0].GetID(), err) + } + if int(count) != len(resources.Repos) { + t.Errorf("ListReposForUser() is %v, want %v", count, len(resources.Repos)) + } + if !reflect.DeepEqual(list, resources.Repos) { + t.Errorf("ListReposForUser() is %v, want %v", list, resources.Repos) + } + methods["ListReposForUser"] = true + + // lookup the repos by name + for _, repo := range resources.Repos { + got, err := db.GetRepoForOrg(repo.GetOrg(), repo.GetName()) + if err != nil { + t.Errorf("unable to get repo %d by org: %v", repo.GetID(), err) + } + if !reflect.DeepEqual(got, repo) { + t.Errorf("GetRepoForOrg() is %v, want %v", got, repo) + } + } + methods["GetRepoForOrg"] = true + + // update the repos + for _, repo := range resources.Repos { + repo.SetActive(false) + _, err = db.UpdateRepo(repo) + if err != nil { + t.Errorf("unable to update repo %d: %v", repo.GetID(), err) + } + + // lookup the repo by ID + got, err := db.GetRepo(repo.GetID()) + if err != nil { + t.Errorf("unable to get repo %d by ID: %v", repo.GetID(), err) + } + if !reflect.DeepEqual(got, repo) { + t.Errorf("GetRepo() is %v, want %v", got, repo) + } + } + methods["UpdateRepo"] = true + methods["GetRepo"] = true + + // delete the repos + for _, repo := range resources.Repos { + err = db.DeleteRepo(repo) + if err != nil { + t.Errorf("unable to delete repo %d: %v", repo.GetID(), err) + } + } + methods["DeleteRepo"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for repos", method) + } + } +} + +func testSchedules(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for schedules + methods := make(map[string]bool) + // capture the element type of the schedule interface + element := reflect.TypeOf(new(schedule.ScheduleInterface)).Elem() + // iterate through all methods found in the schedule interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for schedules + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the schedules + for _, schedule := range resources.Schedules { + err := db.CreateSchedule(schedule) + if err != nil { + t.Errorf("unable to create schedule %d: %v", schedule.GetID(), err) + } + } + methods["CreateSchedule"] = true + + // count the schedules + count, err := db.CountSchedules() + if err != nil { + t.Errorf("unable to count schedules: %v", err) + } + if int(count) != len(resources.Schedules) { + t.Errorf("CountSchedules() is %v, want %v", count, len(resources.Schedules)) + } + methods["CountSchedules"] = true + + // count the schedules for a repo + count, err = db.CountSchedulesForRepo(resources.Repos[0]) + if err != nil { + t.Errorf("unable to count schedules for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Schedules) { + t.Errorf("CountSchedulesForRepo() is %v, want %v", count, len(resources.Schedules)) + } + methods["CountSchedulesForRepo"] = true + + // list the schedules + list, err := db.ListSchedules() + if err != nil { + t.Errorf("unable to list schedules: %v", err) + } + if !reflect.DeepEqual(list, resources.Schedules) { + t.Errorf("ListSchedules() is %v, want %v", list, resources.Schedules) + } + methods["ListSchedules"] = true + + // list the active schedules + list, err = db.ListActiveSchedules() + if err != nil { + t.Errorf("unable to list schedules: %v", err) + } + if !reflect.DeepEqual(list, resources.Schedules) { + t.Errorf("ListActiveSchedules() is %v, want %v", list, resources.Schedules) + } + methods["ListActiveSchedules"] = true + + // list the schedules for a repo + list, count, err = db.ListSchedulesForRepo(resources.Repos[0], 1, 10) + if err != nil { + t.Errorf("unable to count schedules for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != len(resources.Schedules) { + t.Errorf("ListSchedulesForRepo() is %v, want %v", count, len(resources.Schedules)) + } + if !reflect.DeepEqual(list, []*library.Schedule{resources.Schedules[1], resources.Schedules[0]}) { + t.Errorf("ListSchedulesForRepo() is %v, want %v", list, []*library.Schedule{resources.Schedules[1], resources.Schedules[0]}) + } + methods["ListSchedulesForRepo"] = true + + // lookup the schedules by name + for _, schedule := range resources.Schedules { + repo := resources.Repos[schedule.GetRepoID()-1] + got, err := db.GetScheduleForRepo(repo, schedule.GetName()) + if err != nil { + t.Errorf("unable to get schedule %d for repo %d: %v", schedule.GetID(), repo.GetID(), err) + } + if !reflect.DeepEqual(got, schedule) { + t.Errorf("GetScheduleForRepo() is %v, want %v", got, schedule) + } + } + methods["GetScheduleForRepo"] = true + + // update the schedules + for _, schedule := range resources.Schedules { + schedule.SetUpdatedAt(time.Now().UTC().Unix()) + err = db.UpdateSchedule(schedule, true) + if err != nil { + t.Errorf("unable to update schedule %d: %v", schedule.GetID(), err) + } + + // lookup the schedule by ID + got, err := db.GetSchedule(schedule.GetID()) + if err != nil { + t.Errorf("unable to get schedule %d by ID: %v", schedule.GetID(), err) + } + if !reflect.DeepEqual(got, schedule) { + t.Errorf("GetSchedule() is %v, want %v", got, schedule) + } + } + methods["UpdateSchedule"] = true + methods["GetSchedule"] = true + + // delete the schedules + for _, schedule := range resources.Schedules { + err = db.DeleteSchedule(schedule) + if err != nil { + t.Errorf("unable to delete schedule %d: %v", schedule.GetID(), err) + } + } + methods["DeleteSchedule"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for schedules", method) + } + } +} + +func testSecrets(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for secrets + methods := make(map[string]bool) + // capture the element type of the secret interface + element := reflect.TypeOf(new(secret.SecretInterface)).Elem() + // iterate through all methods found in the secret interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for secrets + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the secrets + for _, secret := range resources.Secrets { + err := db.CreateSecret(secret) + if err != nil { + t.Errorf("unable to create secret %d: %v", secret.GetID(), err) + } + } + methods["CreateSecret"] = true + + // count the secrets + count, err := db.CountSecrets() + if err != nil { + t.Errorf("unable to count secrets: %v", err) + } + if int(count) != len(resources.Secrets) { + t.Errorf("CountSecrets() is %v, want %v", count, len(resources.Secrets)) + } + methods["CountSecrets"] = true + + for _, secret := range resources.Secrets { + switch secret.GetType() { + case constants.SecretOrg: + // count the secrets for an org + count, err = db.CountSecretsForOrg(secret.GetOrg(), nil) + if err != nil { + t.Errorf("unable to count secrets for org %s: %v", secret.GetOrg(), err) + } + if int(count) != 1 { + t.Errorf("CountSecretsForOrg() is %v, want %v", count, 1) + } + methods["CountSecretsForOrg"] = true + case constants.SecretRepo: + // count the secrets for a repo + count, err = db.CountSecretsForRepo(resources.Repos[0], nil) + if err != nil { + t.Errorf("unable to count secrets for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != 1 { + t.Errorf("CountSecretsForRepo() is %v, want %v", count, 1) + } + methods["CountSecretsForRepo"] = true + case constants.SecretShared: + // count the secrets for a team + count, err = db.CountSecretsForTeam(secret.GetOrg(), secret.GetTeam(), nil) + if err != nil { + t.Errorf("unable to count secrets for team %s: %v", secret.GetTeam(), err) + } + if int(count) != 1 { + t.Errorf("CountSecretsForTeam() is %v, want %v", count, 1) + } + methods["CountSecretsForTeam"] = true + + // count the secrets for a list of teams + count, err = db.CountSecretsForTeams(secret.GetOrg(), []string{secret.GetTeam()}, nil) + if err != nil { + t.Errorf("unable to count secrets for teams %s: %v", []string{secret.GetTeam()}, err) + } + if int(count) != 1 { + t.Errorf("CountSecretsForTeams() is %v, want %v", count, 1) + } + methods["CountSecretsForTeams"] = true + default: + t.Errorf("unsupported type %s for secret %d", secret.GetType(), secret.GetID()) + } + } + + // list the secrets + list, err := db.ListSecrets() + if err != nil { + t.Errorf("unable to list secrets: %v", err) + } + if !reflect.DeepEqual(list, resources.Secrets) { + t.Errorf("ListSecrets() is %v, want %v", list, resources.Secrets) + } + methods["ListSecrets"] = true + + for _, secret := range resources.Secrets { + switch secret.GetType() { + case constants.SecretOrg: + // list the secrets for an org + list, count, err = db.ListSecretsForOrg(secret.GetOrg(), nil, 1, 10) + if err != nil { + t.Errorf("unable to list secrets for org %s: %v", secret.GetOrg(), err) + } + if int(count) != 1 { + t.Errorf("ListSecretsForOrg() is %v, want %v", count, 1) + } + if !reflect.DeepEqual(list, []*library.Secret{secret}) { + t.Errorf("ListSecretsForOrg() is %v, want %v", list, []*library.Secret{secret}) + } + methods["ListSecretsForOrg"] = true + case constants.SecretRepo: + // list the secrets for a repo + list, count, err = db.ListSecretsForRepo(resources.Repos[0], nil, 1, 10) + if err != nil { + t.Errorf("unable to list secrets for repo %d: %v", resources.Repos[0].GetID(), err) + } + if int(count) != 1 { + t.Errorf("ListSecretsForRepo() is %v, want %v", count, 1) + } + if !reflect.DeepEqual(list, []*library.Secret{secret}) { + t.Errorf("ListSecretsForRepo() is %v, want %v", list, []*library.Secret{secret}) + } + methods["ListSecretsForRepo"] = true + case constants.SecretShared: + // list the secrets for a team + list, count, err = db.ListSecretsForTeam(secret.GetOrg(), secret.GetTeam(), nil, 1, 10) + if err != nil { + t.Errorf("unable to list secrets for team %s: %v", secret.GetTeam(), err) + } + if int(count) != 1 { + t.Errorf("ListSecretsForTeam() is %v, want %v", count, 1) + } + if !reflect.DeepEqual(list, []*library.Secret{secret}) { + t.Errorf("ListSecretsForTeam() is %v, want %v", list, []*library.Secret{secret}) + } + methods["ListSecretsForTeam"] = true + + // list the secrets for a list of teams + list, count, err = db.ListSecretsForTeams(secret.GetOrg(), []string{secret.GetTeam()}, nil, 1, 10) + if err != nil { + t.Errorf("unable to list secrets for teams %s: %v", []string{secret.GetTeam()}, err) + } + if int(count) != 1 { + t.Errorf("ListSecretsForTeams() is %v, want %v", count, 1) + } + if !reflect.DeepEqual(list, []*library.Secret{secret}) { + t.Errorf("ListSecretsForTeams() is %v, want %v", list, []*library.Secret{secret}) + } + methods["ListSecretsForTeams"] = true + default: + t.Errorf("unsupported type %s for secret %d", secret.GetType(), secret.GetID()) + } + } + + for _, secret := range resources.Secrets { + switch secret.GetType() { + case constants.SecretOrg: + // lookup the secret by org + got, err := db.GetSecretForOrg(secret.GetOrg(), secret.GetName()) + if err != nil { + t.Errorf("unable to get secret %d for org %s: %v", secret.GetID(), secret.GetOrg(), err) + } + if !reflect.DeepEqual(got, secret) { + t.Errorf("GetSecretForOrg() is %v, want %v", got, secret) + } + methods["GetSecretForOrg"] = true + case constants.SecretRepo: + // lookup the secret by repo + got, err := db.GetSecretForRepo(secret.GetName(), resources.Repos[0]) + if err != nil { + t.Errorf("unable to get secret %d for repo %d: %v", secret.GetID(), resources.Repos[0].GetID(), err) + } + if !reflect.DeepEqual(got, secret) { + t.Errorf("GetSecretForRepo() is %v, want %v", got, secret) + } + methods["GetSecretForRepo"] = true + case constants.SecretShared: + // lookup the secret by team + got, err := db.GetSecretForTeam(secret.GetOrg(), secret.GetTeam(), secret.GetName()) + if err != nil { + t.Errorf("unable to get secret %d for team %s: %v", secret.GetID(), secret.GetTeam(), err) + } + if !reflect.DeepEqual(got, secret) { + t.Errorf("GetSecretForTeam() is %v, want %v", got, secret) + } + methods["GetSecretForTeam"] = true + default: + t.Errorf("unsupported type %s for secret %d", secret.GetType(), secret.GetID()) + } + } + + // update the secrets + for _, secret := range resources.Secrets { + secret.SetUpdatedAt(time.Now().UTC().Unix()) + err = db.UpdateSecret(secret) + if err != nil { + t.Errorf("unable to update secret %d: %v", secret.GetID(), err) + } + + // lookup the secret by ID + got, err := db.GetSecret(secret.GetID()) + if err != nil { + t.Errorf("unable to get secret %d by ID: %v", secret.GetID(), err) + } + if !reflect.DeepEqual(got, secret) { + t.Errorf("GetSecret() is %v, want %v", got, secret) + } + } + methods["UpdateSecret"] = true + methods["GetSecret"] = true + + // delete the secrets + for _, secret := range resources.Secrets { + err = db.DeleteSecret(secret) + if err != nil { + t.Errorf("unable to delete secret %d: %v", secret.GetID(), err) + } + } + methods["DeleteSecret"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for secrets", method) + } + } +} + +func testServices(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for services + methods := make(map[string]bool) + // capture the element type of the service interface + element := reflect.TypeOf(new(service.ServiceInterface)).Elem() + // iterate through all methods found in the service interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for services + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the services + for _, service := range resources.Services { + err := db.CreateService(service) + if err != nil { + t.Errorf("unable to create service %d: %v", service.GetID(), err) + } + } + methods["CreateService"] = true + + // count the services + count, err := db.CountServices() + if err != nil { + t.Errorf("unable to count services: %v", err) + } + if int(count) != len(resources.Services) { + t.Errorf("CountServices() is %v, want %v", count, len(resources.Services)) + } + methods["CountServices"] = true + + // count the services for a build + count, err = db.CountServicesForBuild(resources.Builds[0], nil) + if err != nil { + t.Errorf("unable to count services for build %d: %v", resources.Builds[0].GetID(), err) + } + if int(count) != len(resources.Services) { + t.Errorf("CountServicesForBuild() is %v, want %v", count, len(resources.Services)) + } + methods["CountServicesForBuild"] = true + + // list the services + list, err := db.ListServices() + if err != nil { + t.Errorf("unable to list services: %v", err) + } + if !reflect.DeepEqual(list, resources.Services) { + t.Errorf("ListServices() is %v, want %v", list, resources.Services) + } + methods["ListServices"] = true + + // list the services for a build + list, count, err = db.ListServicesForBuild(resources.Builds[0], nil, 1, 10) + if err != nil { + t.Errorf("unable to list services for build %d: %v", resources.Builds[0].GetID(), err) + } + if !reflect.DeepEqual(list, []*library.Service{resources.Services[1], resources.Services[0]}) { + t.Errorf("ListServicesForBuild() is %v, want %v", list, []*library.Service{resources.Services[1], resources.Services[0]}) + } + if int(count) != len(resources.Services) { + t.Errorf("ListServicesForBuild() is %v, want %v", count, len(resources.Services)) + } + methods["ListServicesForBuild"] = true + + expected := map[string]float64{ + "#init": 1, + "target/vela-git:v0.3.0": 1, + } + images, err := db.ListServiceImageCount() + if err != nil { + t.Errorf("unable to list service image count: %v", err) + } + if !reflect.DeepEqual(images, expected) { + t.Errorf("ListServiceImageCount() is %v, want %v", images, expected) + } + methods["ListServiceImageCount"] = true + + expected = map[string]float64{ + "pending": 1, + "failure": 0, + "killed": 0, + "running": 1, + "success": 0, + } + statuses, err := db.ListServiceStatusCount() + if err != nil { + t.Errorf("unable to list service status count: %v", err) + } + if !reflect.DeepEqual(statuses, expected) { + t.Errorf("ListServiceStatusCount() is %v, want %v", statuses, expected) + } + methods["ListServiceStatusCount"] = true + + // lookup the services by name + for _, service := range resources.Services { + build := resources.Builds[service.GetBuildID()-1] + got, err := db.GetServiceForBuild(build, service.GetNumber()) + if err != nil { + t.Errorf("unable to get service %d for build %d: %v", service.GetID(), build.GetID(), err) + } + if !reflect.DeepEqual(got, service) { + t.Errorf("GetServiceForBuild() is %v, want %v", got, service) + } + } + methods["GetServiceForBuild"] = true + + // clean the services + count, err = db.CleanServices("integration testing", 1563474090) + if err != nil { + t.Errorf("unable to clean services: %v", err) + } + if int(count) != len(resources.Services) { + t.Errorf("CleanServices() is %v, want %v", count, len(resources.Services)) + } + methods["CleanServices"] = true + + // update the services + for _, service := range resources.Services { + service.SetStatus("success") + err = db.UpdateService(service) + if err != nil { + t.Errorf("unable to update service %d: %v", service.GetID(), err) + } + + // lookup the service by ID + got, err := db.GetService(service.GetID()) + if err != nil { + t.Errorf("unable to get service %d by ID: %v", service.GetID(), err) + } + if !reflect.DeepEqual(got, service) { + t.Errorf("GetService() is %v, want %v", got, service) + } + } + methods["UpdateService"] = true + methods["GetService"] = true + + // delete the services + for _, service := range resources.Services { + err = db.DeleteService(service) + if err != nil { + t.Errorf("unable to delete service %d: %v", service.GetID(), err) + } + } + methods["DeleteService"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for services", method) + } + } +} + +func testSteps(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for steps + methods := make(map[string]bool) + // capture the element type of the step interface + element := reflect.TypeOf(new(step.StepInterface)).Elem() + // iterate through all methods found in the step interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for steps + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the steps + for _, step := range resources.Steps { + err := db.CreateStep(step) + if err != nil { + t.Errorf("unable to create step %d: %v", step.GetID(), err) + } + } + methods["CreateStep"] = true + + // count the steps + count, err := db.CountSteps() + if err != nil { + t.Errorf("unable to count steps: %v", err) + } + if int(count) != len(resources.Steps) { + t.Errorf("CountSteps() is %v, want %v", count, len(resources.Steps)) + } + methods["CountSteps"] = true + + // count the steps for a build + count, err = db.CountStepsForBuild(resources.Builds[0], nil) + if err != nil { + t.Errorf("unable to count steps for build %d: %v", resources.Builds[0].GetID(), err) + } + if int(count) != len(resources.Steps) { + t.Errorf("CountStepsForBuild() is %v, want %v", count, len(resources.Steps)) + } + methods["CountStepsForBuild"] = true + + // list the steps + list, err := db.ListSteps() + if err != nil { + t.Errorf("unable to list steps: %v", err) + } + if !reflect.DeepEqual(list, resources.Steps) { + t.Errorf("ListSteps() is %v, want %v", list, resources.Steps) + } + methods["ListSteps"] = true + + // list the steps for a build + list, count, err = db.ListStepsForBuild(resources.Builds[0], nil, 1, 10) + if err != nil { + t.Errorf("unable to list steps for build %d: %v", resources.Builds[0].GetID(), err) + } + if !reflect.DeepEqual(list, []*library.Step{resources.Steps[1], resources.Steps[0]}) { + t.Errorf("ListStepsForBuild() is %v, want %v", list, []*library.Step{resources.Steps[1], resources.Steps[0]}) + } + if int(count) != len(resources.Steps) { + t.Errorf("ListStepsForBuild() is %v, want %v", count, len(resources.Steps)) + } + methods["ListStepsForBuild"] = true + + expected := map[string]float64{ + "#init": 1, + "target/vela-git:v0.3.0": 1, + } + images, err := db.ListStepImageCount() + if err != nil { + t.Errorf("unable to list step image count: %v", err) + } + if !reflect.DeepEqual(images, expected) { + t.Errorf("ListStepImageCount() is %v, want %v", images, expected) + } + methods["ListStepImageCount"] = true + + expected = map[string]float64{ + "pending": 1, + "failure": 0, + "killed": 0, + "running": 1, + "success": 0, + } + statuses, err := db.ListStepStatusCount() + if err != nil { + t.Errorf("unable to list step status count: %v", err) + } + if !reflect.DeepEqual(statuses, expected) { + t.Errorf("ListStepStatusCount() is %v, want %v", statuses, expected) + } + methods["ListStepStatusCount"] = true + + // lookup the steps by name + for _, step := range resources.Steps { + build := resources.Builds[step.GetBuildID()-1] + got, err := db.GetStepForBuild(build, step.GetNumber()) + if err != nil { + t.Errorf("unable to get step %d for build %d: %v", step.GetID(), build.GetID(), err) + } + if !reflect.DeepEqual(got, step) { + t.Errorf("GetStepForBuild() is %v, want %v", got, step) + } + } + methods["GetStepForBuild"] = true + + // clean the steps + count, err = db.CleanSteps("integration testing", 1563474090) + if err != nil { + t.Errorf("unable to clean steps: %v", err) + } + if int(count) != len(resources.Steps) { + t.Errorf("CleanSteps() is %v, want %v", count, len(resources.Steps)) + } + methods["CleanSteps"] = true + + // update the steps + for _, step := range resources.Steps { + step.SetStatus("success") + err = db.UpdateStep(step) + if err != nil { + t.Errorf("unable to update step %d: %v", step.GetID(), err) + } + + // lookup the step by ID + got, err := db.GetStep(step.GetID()) + if err != nil { + t.Errorf("unable to get step %d by ID: %v", step.GetID(), err) + } + if !reflect.DeepEqual(got, step) { + t.Errorf("GetStep() is %v, want %v", got, step) + } + } + methods["UpdateStep"] = true + methods["GetStep"] = true + + // delete the steps + for _, step := range resources.Steps { + err = db.DeleteStep(step) + if err != nil { + t.Errorf("unable to delete step %d: %v", step.GetID(), err) + } + } + methods["DeleteStep"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for steps", method) + } + } +} + +func testUsers(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for users + methods := make(map[string]bool) + // capture the element type of the user interface + element := reflect.TypeOf(new(user.UserInterface)).Elem() + // iterate through all methods found in the user interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for users + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + userOne := new(library.User) + userOne.SetID(1) + userOne.SetName("octocat") + userOne.SetToken("") + userOne.SetRefreshToken("") + userOne.SetHash("") + userOne.SetFavorites(nil) + userOne.SetActive(false) + userOne.SetAdmin(false) + + userTwo := new(library.User) + userTwo.SetID(2) + userTwo.SetName("octokitty") + userTwo.SetToken("") + userTwo.SetRefreshToken("") + userTwo.SetHash("") + userTwo.SetFavorites(nil) + userTwo.SetActive(false) + userTwo.SetAdmin(false) + + liteUsers := []*library.User{userOne, userTwo} + + // create the users + for _, user := range resources.Users { + err := db.CreateUser(user) + if err != nil { + t.Errorf("unable to create user %d: %v", user.GetID(), err) + } + } + methods["CreateUser"] = true + + // count the users + count, err := db.CountUsers() + if err != nil { + t.Errorf("unable to count users: %v", err) + } + if int(count) != len(resources.Users) { + t.Errorf("CountUsers() is %v, want %v", count, len(resources.Users)) + } + methods["CountUsers"] = true + + // list the users + list, err := db.ListUsers() + if err != nil { + t.Errorf("unable to list users: %v", err) + } + if !reflect.DeepEqual(list, resources.Users) { + t.Errorf("ListUsers() is %v, want %v", list, resources.Users) + } + methods["ListUsers"] = true + + // lite list the users + list, count, err = db.ListLiteUsers(1, 10) + if err != nil { + t.Errorf("unable to list lite users: %v", err) + } + if !reflect.DeepEqual(list, liteUsers) { + t.Errorf("ListLiteUsers() is %v, want %v", list, liteUsers) + } + if int(count) != len(liteUsers) { + t.Errorf("ListLiteUsers() is %v, want %v", count, len(liteUsers)) + } + methods["ListLiteUsers"] = true + + // lookup the users by name + for _, user := range resources.Users { + got, err := db.GetUserForName(user.GetName()) + if err != nil { + t.Errorf("unable to get user %d by name: %v", user.GetID(), err) + } + if !reflect.DeepEqual(got, user) { + t.Errorf("GetUserForName() is %v, want %v", got, user) + } + } + methods["GetUserForName"] = true + + // update the users + for _, user := range resources.Users { + user.SetActive(false) + err = db.UpdateUser(user) + if err != nil { + t.Errorf("unable to update user %d: %v", user.GetID(), err) + } + + // lookup the user by ID + got, err := db.GetUser(user.GetID()) + if err != nil { + t.Errorf("unable to get user %d by ID: %v", user.GetID(), err) + } + if !reflect.DeepEqual(got, user) { + t.Errorf("GetUser() is %v, want %v", got, user) + } + } + methods["UpdateUser"] = true + methods["GetUser"] = true + + // delete the users + for _, user := range resources.Users { + err = db.DeleteUser(user) + if err != nil { + t.Errorf("unable to delete user %d: %v", user.GetID(), err) + } + } + methods["DeleteUser"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for users", method) + } + } +} + +func testWorkers(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for workers + methods := make(map[string]bool) + // capture the element type of the worker interface + element := reflect.TypeOf(new(worker.WorkerInterface)).Elem() + // iterate through all methods found in the worker interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for workers + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the workers + for _, worker := range resources.Workers { + err := db.CreateWorker(worker) + if err != nil { + t.Errorf("unable to create worker %d: %v", worker.GetID(), err) + } + } + methods["CreateWorker"] = true + + // count the workers + count, err := db.CountWorkers() + if err != nil { + t.Errorf("unable to count workers: %v", err) + } + if int(count) != len(resources.Workers) { + t.Errorf("CountWorkers() is %v, want %v", count, len(resources.Workers)) + } + methods["CountWorkers"] = true + + // list the workers + list, err := db.ListWorkers() + if err != nil { + t.Errorf("unable to list workers: %v", err) + } + if !reflect.DeepEqual(list, resources.Workers) { + t.Errorf("ListWorkers() is %v, want %v", list, resources.Workers) + } + methods["ListWorkers"] = true + + // lookup the workers by hostname + for _, worker := range resources.Workers { + got, err := db.GetWorkerForHostname(worker.GetHostname()) + if err != nil { + t.Errorf("unable to get worker %d by hostname: %v", worker.GetID(), err) + } + if !reflect.DeepEqual(got, worker) { + t.Errorf("GetWorkerForHostname() is %v, want %v", got, worker) + } + } + methods["GetWorkerForHostname"] = true + + // update the workers + for _, worker := range resources.Workers { + worker.SetActive(false) + err = db.UpdateWorker(worker) + if err != nil { + t.Errorf("unable to update worker %d: %v", worker.GetID(), err) + } + + // lookup the worker by ID + got, err := db.GetWorker(worker.GetID()) + if err != nil { + t.Errorf("unable to get worker %d by ID: %v", worker.GetID(), err) + } + if !reflect.DeepEqual(got, worker) { + t.Errorf("GetWorker() is %v, want %v", got, worker) + } + } + methods["UpdateWorker"] = true + methods["GetWorker"] = true + + // delete the workers + for _, worker := range resources.Workers { + err = db.DeleteWorker(worker) + if err != nil { + t.Errorf("unable to delete worker %d: %v", worker.GetID(), err) + } + } + methods["DeleteWorker"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for workers", method) + } + } +} + +func newResources() *Resources { + 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.SetDeployPayload(raw.StringSliceMap{"foo": "test1"}) + buildOne.SetClone("https://github.com/github/octocat.git") + buildOne.SetSource("https://github.com/github/octocat/deployments/1") + 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("changes") + buildOne.SetHost("example.company.com") + buildOne.SetRuntime("docker") + buildOne.SetDistribution("linux") + + buildTwo := new(library.Build) + buildTwo.SetID(2) + buildTwo.SetRepoID(1) + buildTwo.SetPipelineID(1) + buildTwo.SetNumber(2) + buildTwo.SetParent(1) + buildTwo.SetEvent("pull_request") + buildTwo.SetEventAction("") + buildTwo.SetStatus("running") + buildTwo.SetError("") + buildTwo.SetEnqueued(1563474077) + buildTwo.SetCreated(1563474076) + buildTwo.SetStarted(1563474078) + buildTwo.SetFinished(1563474079) + buildTwo.SetDeploy("") + buildTwo.SetDeployPayload(raw.StringSliceMap{"foo": "test1"}) + buildTwo.SetClone("https://github.com/github/octocat.git") + buildTwo.SetSource("https://github.com/github/octocat/deployments/1") + buildTwo.SetTitle("pull_request received from https://github.com/github/octocat") + buildTwo.SetMessage("Second commit...") + buildTwo.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135164") + buildTwo.SetSender("OctoKitty") + buildTwo.SetAuthor("OctoKitty") + buildTwo.SetEmail("OctoKitty@github.com") + buildTwo.SetLink("https://example.company.com/github/octocat/2") + buildTwo.SetBranch("main") + buildTwo.SetRef("refs/heads/main") + buildTwo.SetBaseRef("") + buildTwo.SetHeadRef("changes") + buildTwo.SetHost("example.company.com") + buildTwo.SetRuntime("docker") + buildTwo.SetDistribution("linux") + + deploymentOne := new(library.Deployment) + deploymentOne.SetID(1) + deploymentOne.SetRepoID(1) + deploymentOne.SetURL("https://github.com/github/octocat/deployments/1") + deploymentOne.SetUser("octocat") + deploymentOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + deploymentOne.SetRef("refs/heads/master") + deploymentOne.SetTask("vela-deploy") + deploymentOne.SetTarget("production") + deploymentOne.SetDescription("Deployment request from Vela") + deploymentOne.SetPayload(map[string]string{"foo": "test1"}) + + deploymentTwo := new(library.Deployment) + deploymentTwo.SetID(1) + deploymentTwo.SetRepoID(1) + deploymentTwo.SetURL("https://github.com/github/octocat/deployments/2") + deploymentTwo.SetUser("octocat") + deploymentTwo.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135164") + deploymentTwo.SetRef("refs/heads/master") + deploymentTwo.SetTask("vela-deploy") + deploymentTwo.SetTarget("production") + deploymentTwo.SetDescription("Deployment request from Vela") + deploymentTwo.SetPayload(map[string]string{"foo": "test1"}) + + hookOne := new(library.Hook) + hookOne.SetID(1) + hookOne.SetRepoID(1) + hookOne.SetBuildID(1) + hookOne.SetNumber(1) + hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + hookOne.SetCreated(time.Now().UTC().Unix()) + hookOne.SetHost("github.com") + hookOne.SetEvent("push") + hookOne.SetEventAction("") + hookOne.SetBranch("main") + hookOne.SetError("") + hookOne.SetStatus("success") + hookOne.SetLink("https://github.com/github/octocat/settings/hooks/1") + hookOne.SetWebhookID(123456) + + hookTwo := new(library.Hook) + hookTwo.SetID(2) + hookTwo.SetRepoID(1) + hookTwo.SetBuildID(1) + hookTwo.SetNumber(2) + hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") + hookTwo.SetCreated(time.Now().UTC().Unix()) + hookTwo.SetHost("github.com") + hookTwo.SetEvent("push") + hookTwo.SetEventAction("") + hookTwo.SetBranch("main") + hookTwo.SetError("") + hookTwo.SetStatus("success") + hookTwo.SetLink("https://github.com/github/octocat/settings/hooks/1") + hookTwo.SetWebhookID(123456) + + logServiceOne := new(library.Log) + logServiceOne.SetID(1) + logServiceOne.SetBuildID(1) + logServiceOne.SetRepoID(1) + logServiceOne.SetServiceID(1) + logServiceOne.SetStepID(0) + logServiceOne.SetData([]byte("foo")) + + logServiceTwo := new(library.Log) + logServiceTwo.SetID(2) + logServiceTwo.SetBuildID(1) + logServiceTwo.SetRepoID(1) + logServiceTwo.SetServiceID(2) + logServiceTwo.SetStepID(0) + logServiceTwo.SetData([]byte("foo")) + + logStepOne := new(library.Log) + logStepOne.SetID(3) + logStepOne.SetBuildID(1) + logStepOne.SetRepoID(1) + logStepOne.SetServiceID(0) + logStepOne.SetStepID(1) + logStepOne.SetData([]byte("foo")) + + logStepTwo := new(library.Log) + logStepTwo.SetID(4) + logStepTwo.SetBuildID(1) + logStepTwo.SetRepoID(1) + logStepTwo.SetServiceID(0) + logStepTwo.SetStepID(2) + logStepTwo.SetData([]byte("foo")) + + pipelineOne := new(library.Pipeline) + pipelineOne.SetID(1) + pipelineOne.SetRepoID(1) + pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + pipelineOne.SetFlavor("large") + pipelineOne.SetPlatform("docker") + pipelineOne.SetRef("refs/heads/main") + pipelineOne.SetType("yaml") + pipelineOne.SetVersion("1") + pipelineOne.SetExternalSecrets(false) + pipelineOne.SetInternalSecrets(false) + pipelineOne.SetServices(true) + pipelineOne.SetStages(false) + pipelineOne.SetSteps(true) + pipelineOne.SetTemplates(false) + pipelineOne.SetData([]byte("version: 1")) + + pipelineTwo := new(library.Pipeline) + pipelineTwo.SetID(2) + pipelineTwo.SetRepoID(1) + pipelineTwo.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135164") + pipelineTwo.SetFlavor("large") + pipelineTwo.SetPlatform("docker") + pipelineTwo.SetRef("refs/heads/main") + pipelineTwo.SetType("yaml") + pipelineTwo.SetVersion("1") + pipelineTwo.SetExternalSecrets(false) + pipelineTwo.SetInternalSecrets(false) + pipelineTwo.SetServices(true) + pipelineTwo.SetStages(false) + pipelineTwo.SetSteps(true) + pipelineTwo.SetTemplates(false) + pipelineTwo.SetData([]byte("version: 1")) + + repoOne := new(library.Repo) + repoOne.SetID(1) + repoOne.SetUserID(1) + 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.SetAllowPull(false) + repoOne.SetAllowPush(true) + repoOne.SetAllowDeploy(false) + repoOne.SetAllowTag(false) + repoOne.SetAllowComment(false) + repoOne.SetPipelineType("") + repoOne.SetPreviousName("") + + repoTwo := new(library.Repo) + repoTwo.SetID(2) + repoTwo.SetUserID(1) + 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.SetAllowPull(false) + repoTwo.SetAllowPush(true) + repoTwo.SetAllowDeploy(false) + repoTwo.SetAllowTag(false) + repoTwo.SetAllowComment(false) + repoTwo.SetPipelineType("") + repoTwo.SetPreviousName("") + + scheduleOne := new(library.Schedule) + scheduleOne.SetID(1) + scheduleOne.SetRepoID(1) + scheduleOne.SetActive(true) + scheduleOne.SetName("nightly") + scheduleOne.SetEntry("0 0 * * *") + scheduleOne.SetCreatedAt(time.Now().UTC().Unix()) + scheduleOne.SetCreatedBy("octocat") + scheduleOne.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + scheduleOne.SetUpdatedBy("octokitty") + scheduleOne.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + + scheduleTwo := new(library.Schedule) + scheduleTwo.SetID(2) + scheduleTwo.SetRepoID(1) + scheduleTwo.SetActive(true) + scheduleTwo.SetName("hourly") + scheduleTwo.SetEntry("0 * * * *") + scheduleTwo.SetCreatedAt(time.Now().UTC().Unix()) + scheduleTwo.SetCreatedBy("octocat") + scheduleTwo.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + scheduleTwo.SetUpdatedBy("octokitty") + scheduleTwo.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + + secretOrg := new(library.Secret) + secretOrg.SetID(1) + secretOrg.SetOrg("github") + secretOrg.SetRepo("*") + secretOrg.SetTeam("") + secretOrg.SetName("foo") + secretOrg.SetValue("bar") + secretOrg.SetType("org") + secretOrg.SetImages([]string{"alpine"}) + secretOrg.SetEvents([]string{"push", "tag", "deployment"}) + secretOrg.SetAllowCommand(true) + secretOrg.SetCreatedAt(time.Now().UTC().Unix()) + secretOrg.SetCreatedBy("octocat") + secretOrg.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + secretOrg.SetUpdatedBy("octokitty") + + secretRepo := new(library.Secret) + secretRepo.SetID(2) + secretRepo.SetOrg("github") + secretRepo.SetRepo("octocat") + secretRepo.SetTeam("") + secretRepo.SetName("foo") + secretRepo.SetValue("bar") + secretRepo.SetType("repo") + secretRepo.SetImages([]string{"alpine"}) + secretRepo.SetEvents([]string{"push", "tag", "deployment"}) + secretRepo.SetAllowCommand(true) + secretRepo.SetCreatedAt(time.Now().UTC().Unix()) + secretRepo.SetCreatedBy("octocat") + secretRepo.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + secretRepo.SetUpdatedBy("octokitty") + + secretShared := new(library.Secret) + secretShared.SetID(3) + secretShared.SetOrg("github") + secretShared.SetRepo("") + secretShared.SetTeam("octocat") + secretShared.SetName("foo") + secretShared.SetValue("bar") + secretShared.SetType("shared") + secretShared.SetImages([]string{"alpine"}) + secretShared.SetEvents([]string{"push", "tag", "deployment"}) + secretShared.SetAllowCommand(true) + secretShared.SetCreatedAt(time.Now().UTC().Unix()) + secretShared.SetCreatedBy("octocat") + secretShared.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + secretShared.SetUpdatedBy("octokitty") + + serviceOne := new(library.Service) + serviceOne.SetID(1) + serviceOne.SetBuildID(1) + serviceOne.SetRepoID(1) + serviceOne.SetNumber(1) + serviceOne.SetName("init") + serviceOne.SetImage("#init") + serviceOne.SetStatus("running") + serviceOne.SetError("") + serviceOne.SetExitCode(0) + serviceOne.SetCreated(1563474076) + serviceOne.SetStarted(1563474078) + serviceOne.SetFinished(1563474079) + serviceOne.SetHost("example.company.com") + serviceOne.SetRuntime("docker") + serviceOne.SetDistribution("linux") + + serviceTwo := new(library.Service) + serviceTwo.SetID(2) + serviceTwo.SetBuildID(1) + serviceTwo.SetRepoID(1) + serviceTwo.SetNumber(2) + serviceTwo.SetName("clone") + serviceTwo.SetImage("target/vela-git:v0.3.0") + serviceTwo.SetStatus("pending") + serviceTwo.SetError("") + serviceTwo.SetExitCode(0) + serviceTwo.SetCreated(1563474086) + serviceTwo.SetStarted(1563474088) + serviceTwo.SetFinished(1563474089) + serviceTwo.SetHost("example.company.com") + serviceTwo.SetRuntime("docker") + serviceTwo.SetDistribution("linux") + + stepOne := new(library.Step) + stepOne.SetID(1) + stepOne.SetBuildID(1) + stepOne.SetRepoID(1) + stepOne.SetNumber(1) + stepOne.SetName("init") + stepOne.SetImage("#init") + stepOne.SetStage("init") + stepOne.SetStatus("running") + stepOne.SetError("") + stepOne.SetExitCode(0) + stepOne.SetCreated(1563474076) + stepOne.SetStarted(1563474078) + stepOne.SetFinished(1563474079) + stepOne.SetHost("example.company.com") + stepOne.SetRuntime("docker") + stepOne.SetDistribution("linux") + + stepTwo := new(library.Step) + stepTwo.SetID(2) + stepTwo.SetBuildID(1) + stepTwo.SetRepoID(1) + stepTwo.SetNumber(2) + stepTwo.SetName("clone") + stepTwo.SetImage("target/vela-git:v0.3.0") + stepTwo.SetStage("init") + stepTwo.SetStatus("pending") + stepTwo.SetError("") + stepTwo.SetExitCode(0) + stepTwo.SetCreated(1563474086) + stepTwo.SetStarted(1563474088) + stepTwo.SetFinished(1563474089) + stepTwo.SetHost("example.company.com") + stepTwo.SetRuntime("docker") + stepTwo.SetDistribution("linux") + + userOne := new(library.User) + userOne.SetID(1) + userOne.SetName("octocat") + userOne.SetToken("superSecretToken") + userOne.SetRefreshToken("superSecretRefreshToken") + userOne.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") + userOne.SetFavorites([]string{"github/octocat"}) + userOne.SetActive(true) + userOne.SetAdmin(false) + + userTwo := new(library.User) + userTwo.SetID(2) + userTwo.SetName("octokitty") + userTwo.SetToken("superSecretToken") + userTwo.SetRefreshToken("superSecretRefreshToken") + userTwo.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") + userTwo.SetFavorites([]string{"github/octocat"}) + userTwo.SetActive(true) + userTwo.SetAdmin(false) + + workerOne := new(library.Worker) + workerOne.SetID(1) + workerOne.SetHostname("worker-1.example.com") + workerOne.SetAddress("https://worker-1.example.com") + workerOne.SetRoutes([]string{"vela"}) + workerOne.SetActive(true) + workerOne.SetStatus("available") + workerOne.SetLastStatusUpdateAt(time.Now().UTC().Unix()) + workerOne.SetRunningBuildIDs([]string{"12345"}) + workerOne.SetLastBuildStartedAt(time.Now().UTC().Unix()) + workerOne.SetLastBuildFinishedAt(time.Now().UTC().Unix()) + workerOne.SetLastCheckedIn(time.Now().UTC().Unix()) + workerOne.SetBuildLimit(1) + + workerTwo := new(library.Worker) + workerTwo.SetID(2) + workerTwo.SetHostname("worker-2.example.com") + workerTwo.SetAddress("https://worker-2.example.com") + workerTwo.SetRoutes([]string{"vela"}) + workerTwo.SetActive(true) + workerTwo.SetStatus("available") + workerTwo.SetLastStatusUpdateAt(time.Now().UTC().Unix()) + workerTwo.SetRunningBuildIDs([]string{"12345"}) + workerTwo.SetLastBuildStartedAt(time.Now().UTC().Unix()) + workerTwo.SetLastBuildFinishedAt(time.Now().UTC().Unix()) + workerTwo.SetLastCheckedIn(time.Now().UTC().Unix()) + workerTwo.SetBuildLimit(1) + + return &Resources{ + Builds: []*library.Build{buildOne, buildTwo}, + Deployments: []*library.Deployment{deploymentOne, deploymentTwo}, + Hooks: []*library.Hook{hookOne, hookTwo}, + Logs: []*library.Log{logServiceOne, logServiceTwo, logStepOne, logStepTwo}, + Pipelines: []*library.Pipeline{pipelineOne, pipelineTwo}, + Repos: []*library.Repo{repoOne, repoTwo}, + Schedules: []*library.Schedule{scheduleOne, scheduleTwo}, + Secrets: []*library.Secret{secretOrg, secretRepo, secretShared}, + Services: []*library.Service{serviceOne, serviceTwo}, + Steps: []*library.Step{stepOne, stepTwo}, + Users: []*library.User{userOne, userTwo}, + Workers: []*library.Worker{workerOne, workerTwo}, + } +} diff --git a/database/log/list_build.go b/database/log/list_build.go index 58ca12111..ab083a706 100644 --- a/database/log/list_build.go +++ b/database/log/list_build.go @@ -37,6 +37,7 @@ func (e *engine) ListLogsForBuild(b *library.Build, page, perPage int) ([]*libra err = e.client. Table(constants.TableLog). Where("build_id = ?", b.GetID()). + Order("service_id ASC NULLS LAST"). Order("step_id ASC"). Limit(perPage). Offset(offset). diff --git a/database/log/list_build_test.go b/database/log/list_build_test.go index fb08236e9..cf20fb50e 100644 --- a/database/log/list_build_test.go +++ b/database/log/list_build_test.go @@ -49,7 +49,7 @@ func TestLog_Engine_ListLogsForBuild(t *testing.T) { AddRow(1, 1, 1, 1, 0, []byte{}).AddRow(2, 1, 1, 0, 1, []byte{}) // ensure the mock expects the query - _mock.ExpectQuery(`SELECT * FROM "logs" WHERE build_id = $1 ORDER BY step_id ASC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "logs" WHERE build_id = $1 ORDER BY service_id ASC NULLS LAST,step_id ASC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() diff --git a/go.mod b/go.mod index b9ac96ee1..f36b309d4 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.8 // indirect diff --git a/go.sum b/go.sum index 32499db9b..a8eaa2a36 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -289,8 +290,9 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= From b3084f9e111c3ece519b961c42f85d06d25387e6 Mon Sep 17 00:00:00 2001 From: claire1618 <55173466+claire1618@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:08:11 -0500 Subject: [PATCH 283/298] fix: getting visbility to match on vela and SCM (#924) * enhance: getting visbility to match on vela and SCM * fix: modifying test cases to consider new visibility changes --------- Co-authored-by: Claire.Nicholas --- api/repo/create.go | 6 ++---- scm/github/repo.go | 25 +++++++++++++++++-------- scm/github/repo_test.go | 2 ++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/api/repo/create.go b/api/repo/create.go index 33de7d3ae..ca0dc2d6e 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -140,10 +140,8 @@ func CreateRepo(c *gin.Context) { } // set the visibility field based off the input provided - if len(input.GetVisibility()) == 0 { - // default visibility field to public - r.SetVisibility(constants.VisibilityPublic) - } else { + if len(input.GetVisibility()) > 0 { + // default visibility field to the input visibility r.SetVisibility(input.GetVisibility()) } diff --git a/scm/github/repo.go b/scm/github/repo.go index 682a2db94..5cd3b0999 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -465,15 +465,24 @@ func (c *client) ListUserRepos(u *library.User) ([]*library.Repo, error) { // toLibraryRepo does a partial conversion of a github repo to a library repo. func toLibraryRepo(gr github.Repository) *library.Repo { + // setting the visbility to match the SCM visbility + var visibility string + if *gr.Private { + visibility = constants.VisibilityPrivate + } else { + visibility = constants.VisibilityPublic + } + return &library.Repo{ - Org: gr.GetOwner().Login, - Name: gr.Name, - FullName: gr.FullName, - Link: gr.HTMLURL, - Clone: gr.CloneURL, - Branch: gr.DefaultBranch, - Topics: &gr.Topics, - Private: gr.Private, + Org: gr.GetOwner().Login, + Name: gr.Name, + FullName: gr.FullName, + Link: gr.HTMLURL, + Clone: gr.CloneURL, + Branch: gr.DefaultBranch, + Topics: &gr.Topics, + Private: gr.Private, + Visibility: &visibility, } } diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 7482c71ce..1fcd3bf0c 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1028,6 +1028,7 @@ func TestGithub_GetRepo(t *testing.T) { want.SetBranch("master") want.SetPrivate(false) want.SetTopics([]string{"octocat", "atom", "electron", "api"}) + want.SetVisibility("public") client, _ := NewTest(s.URL) @@ -1191,6 +1192,7 @@ func TestGithub_ListUserRepos(t *testing.T) { r.SetBranch("master") r.SetPrivate(false) r.SetTopics([]string{"octocat", "atom", "electron", "api"}) + r.SetVisibility("public") want := []*library.Repo{r} From 516d4fe51672ab6ca9bd015392c4ebee782e7c2c Mon Sep 17 00:00:00 2001 From: Jordan Sussman Date: Wed, 9 Aug 2023 09:18:16 -0500 Subject: [PATCH 284/298] chore: add context to schedule functions (#898) --- api/schedule/create.go | 11 ++++++----- api/schedule/delete.go | 3 ++- api/schedule/list.go | 3 ++- api/schedule/update.go | 5 +++-- cmd/vela-server/schedule.go | 13 +++++++------ cmd/vela-server/server.go | 2 +- database/database.go | 6 +++++- database/integration_test.go | 23 +++++++++++++---------- database/opts.go | 14 +++++++++++++- database/resource.go | 4 +++- database/resource_test.go | 3 ++- database/schedule/count.go | 3 ++- database/schedule/count_active.go | 3 ++- database/schedule/count_active_test.go | 7 ++++--- database/schedule/count_repo.go | 3 ++- database/schedule/count_repo_test.go | 7 ++++--- database/schedule/count_test.go | 7 ++++--- database/schedule/create.go | 3 ++- database/schedule/create_test.go | 3 ++- database/schedule/delete.go | 3 ++- database/schedule/delete_test.go | 5 +++-- database/schedule/get.go | 3 ++- database/schedule/get_repo.go | 3 ++- database/schedule/get_repo_test.go | 5 +++-- database/schedule/get_test.go | 5 +++-- database/schedule/index.go | 4 +++- database/schedule/index_test.go | 3 ++- database/schedule/interface.go | 25 +++++++++++++------------ database/schedule/list.go | 5 +++-- database/schedule/list_active.go | 5 +++-- database/schedule/list_active_test.go | 7 ++++--- database/schedule/list_repo.go | 5 +++-- database/schedule/list_repo_test.go | 7 ++++--- database/schedule/list_test.go | 7 ++++--- database/schedule/opts.go | 10 ++++++++++ database/schedule/schedule.go | 7 +++++-- database/schedule/schedule_test.go | 6 ++++++ database/schedule/table.go | 3 ++- database/schedule/table_test.go | 3 ++- database/schedule/update.go | 3 ++- database/schedule/update_test.go | 9 +++++---- router/middleware/schedule/schedule.go | 3 ++- 42 files changed, 167 insertions(+), 92 deletions(-) diff --git a/api/schedule/create.go b/api/schedule/create.go index f03fa0cea..3c5c4790a 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.go @@ -77,6 +77,7 @@ func CreateSchedule(c *gin.Context) { // capture middleware values u := user.Retrieve(c) r := repo.Retrieve(c) + ctx := c.Request.Context() allowlist := c.Value("allowlistschedule").([]string) minimumFrequency := c.Value("scheduleminimumfrequency").(time.Duration) @@ -145,7 +146,7 @@ func CreateSchedule(c *gin.Context) { } // send API call to capture the schedule from the database - dbSchedule, err := database.FromContext(c).GetScheduleForRepo(r, input.GetName()) + dbSchedule, err := database.FromContext(c).GetScheduleForRepo(ctx, r, input.GetName()) if err == nil && dbSchedule.GetActive() { retErr := fmt.Errorf("unable to create schedule: %s is already active", input.GetName()) @@ -170,7 +171,7 @@ func CreateSchedule(c *gin.Context) { dbSchedule.SetActive(true) // send API call to update the schedule - err = database.FromContext(c).UpdateSchedule(dbSchedule, true) + err = database.FromContext(c).UpdateSchedule(ctx, dbSchedule, true) if err != nil { retErr := fmt.Errorf("unable to set schedule %s to active: %w", dbSchedule.GetName(), err) @@ -180,10 +181,10 @@ func CreateSchedule(c *gin.Context) { } // send API call to capture the updated schedule - s, _ = database.FromContext(c).GetScheduleForRepo(r, dbSchedule.GetName()) + s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, dbSchedule.GetName()) } else { // send API call to create the schedule - err = database.FromContext(c).CreateSchedule(s) + err = database.FromContext(c).CreateSchedule(ctx, s) if err != nil { retErr := fmt.Errorf("unable to create new schedule %s: %w", r.GetName(), err) @@ -193,7 +194,7 @@ func CreateSchedule(c *gin.Context) { } // send API call to capture the created schedule - s, _ = database.FromContext(c).GetScheduleForRepo(r, input.GetName()) + s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, input.GetName()) } c.JSON(http.StatusCreated, s) diff --git a/api/schedule/delete.go b/api/schedule/delete.go index a697954d8..9c6f1dda8 100644 --- a/api/schedule/delete.go +++ b/api/schedule/delete.go @@ -65,6 +65,7 @@ func DeleteSchedule(c *gin.Context) { r := repo.Retrieve(c) u := user.Retrieve(c) s := schedule.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -75,7 +76,7 @@ func DeleteSchedule(c *gin.Context) { "user": u.GetName(), }).Infof("deleting schedule %s", s.GetName()) - err := database.FromContext(c).DeleteSchedule(s) + err := database.FromContext(c).DeleteSchedule(ctx, s) if err != nil { retErr := fmt.Errorf("unable to delete schedule %s: %w", s.GetName(), err) diff --git a/api/schedule/list.go b/api/schedule/list.go index cb64ada74..a3d6d6e14 100644 --- a/api/schedule/list.go +++ b/api/schedule/list.go @@ -76,6 +76,7 @@ import ( func ListSchedules(c *gin.Context) { // capture middleware values r := repo.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -109,7 +110,7 @@ func ListSchedules(c *gin.Context) { perPage = util.MaxInt(1, util.MinInt(100, perPage)) // send API call to capture the list of schedules for the repo - s, t, err := database.FromContext(c).ListSchedulesForRepo(r, page, perPage) + s, t, err := database.FromContext(c).ListSchedulesForRepo(ctx, r, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get schedules for repo %s: %w", r.GetFullName(), err) diff --git a/api/schedule/update.go b/api/schedule/update.go index 5221d222c..a58990f33 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -74,6 +74,7 @@ func UpdateSchedule(c *gin.Context) { // capture middleware values r := repo.Retrieve(c) s := schedule.Retrieve(c) + ctx := c.Request.Context() u := user.Retrieve(c) scheduleName := util.PathParameter(c, "schedule") minimumFrequency := c.Value("scheduleminimumfrequency").(time.Duration) @@ -128,7 +129,7 @@ func UpdateSchedule(c *gin.Context) { s.SetUpdatedBy(u.GetName()) // update the schedule within the database - err = database.FromContext(c).UpdateSchedule(s, true) + err = database.FromContext(c).UpdateSchedule(ctx, s, true) if err != nil { retErr := fmt.Errorf("unable to update scheduled %s: %w", scheduleName, err) @@ -138,7 +139,7 @@ func UpdateSchedule(c *gin.Context) { } // capture the updated scheduled - s, _ = database.FromContext(c).GetScheduleForRepo(r, scheduleName) + s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, scheduleName) c.JSON(http.StatusOK, s) } diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index e5b1a78c1..aa7bed207 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -5,6 +5,7 @@ package main import ( + "context" "fmt" "strings" "time" @@ -30,11 +31,11 @@ const ( scheduleWait = "waiting to trigger build for schedule" ) -func processSchedules(start time.Time, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { +func processSchedules(ctx context.Context, start time.Time, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { logrus.Infof("processing active schedules to create builds") // send API call to capture the list of active schedules - schedules, err := database.ListActiveSchedules() + schedules, err := database.ListActiveSchedules(ctx) if err != nil { return err } @@ -53,7 +54,7 @@ func processSchedules(start time.Time, compiler compiler.Engine, database databa // This is needed to ensure we are not dealing with a stale schedule since we fetch // all schedules once and iterate through that list which can take a significant // amount of time to get to the end of the list. - schedule, err := database.GetSchedule(s.GetID()) + schedule, err := database.GetSchedule(ctx, s.GetID()) if err != nil { logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) @@ -115,7 +116,7 @@ func processSchedules(start time.Time, compiler compiler.Engine, database databa schedule.SetScheduledAt(time.Now().UTC().Unix()) // send API call to update schedule for ensuring scheduled_at field is set - err = database.UpdateSchedule(schedule, false) + err = database.UpdateSchedule(ctx, schedule, false) if err != nil { logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) @@ -123,7 +124,7 @@ func processSchedules(start time.Time, compiler compiler.Engine, database databa } // process the schedule and trigger a new build - err = processSchedule(schedule, compiler, database, metadata, queue, scm) + err = processSchedule(ctx, schedule, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) @@ -135,7 +136,7 @@ func processSchedules(start time.Time, compiler compiler.Engine, database databa } //nolint:funlen // ignore function length and number of statements -func processSchedule(s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { +func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { // send API call to capture the repo for the schedule r, err := database.GetRepo(s.GetRepoID()) if err != nil { diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 689ba03c2..d18a74278 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -199,7 +199,7 @@ func server(c *cli.Context) error { // sleep for a duration of time before processing schedules time.Sleep(jitter) - err = processSchedules(start, compiler, database, metadata, queue, scm) + err = processSchedules(ctx, start, compiler, database, metadata, queue, scm) if err != nil { logrus.WithError(err).Warn("unable to process schedules") } else { diff --git a/database/database.go b/database/database.go index c612ba3aa..d0317e3ff 100644 --- a/database/database.go +++ b/database/database.go @@ -5,6 +5,7 @@ package database import ( + "context" "fmt" "time" @@ -54,6 +55,8 @@ type ( client *gorm.DB // engine configuration settings used in database functions config *config + // engine context used in database functions + ctx context.Context // sirupsen/logrus logger used in database functions logger *logrus.Entry @@ -85,6 +88,7 @@ func New(opts ...EngineOpt) (Interface, error) { e.client = new(gorm.DB) e.config = new(config) e.logger = new(logrus.Entry) + e.ctx = context.TODO() // apply all provided configuration options for _, opt := range opts { @@ -143,7 +147,7 @@ func New(opts ...EngineOpt) (Interface, error) { } // create database agnostic engines for resources - err = e.NewResources() + err = e.NewResources(e.ctx) if err != nil { return nil, err } diff --git a/database/integration_test.go b/database/integration_test.go index 2cebb815a..9741c764f 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -5,6 +5,7 @@ package database import ( + "context" "os" "reflect" "strings" @@ -923,9 +924,11 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods[element.Method(i).Name] = false } + ctx := context.TODO() + // create the schedules for _, schedule := range resources.Schedules { - err := db.CreateSchedule(schedule) + err := db.CreateSchedule(ctx, schedule) if err != nil { t.Errorf("unable to create schedule %d: %v", schedule.GetID(), err) } @@ -933,7 +936,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods["CreateSchedule"] = true // count the schedules - count, err := db.CountSchedules() + count, err := db.CountSchedules(ctx) if err != nil { t.Errorf("unable to count schedules: %v", err) } @@ -943,7 +946,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods["CountSchedules"] = true // count the schedules for a repo - count, err = db.CountSchedulesForRepo(resources.Repos[0]) + count, err = db.CountSchedulesForRepo(ctx, resources.Repos[0]) if err != nil { t.Errorf("unable to count schedules for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -953,7 +956,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods["CountSchedulesForRepo"] = true // list the schedules - list, err := db.ListSchedules() + list, err := db.ListSchedules(ctx) if err != nil { t.Errorf("unable to list schedules: %v", err) } @@ -963,7 +966,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods["ListSchedules"] = true // list the active schedules - list, err = db.ListActiveSchedules() + list, err = db.ListActiveSchedules(ctx) if err != nil { t.Errorf("unable to list schedules: %v", err) } @@ -973,7 +976,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { methods["ListActiveSchedules"] = true // list the schedules for a repo - list, count, err = db.ListSchedulesForRepo(resources.Repos[0], 1, 10) + list, count, err = db.ListSchedulesForRepo(ctx, resources.Repos[0], 1, 10) if err != nil { t.Errorf("unable to count schedules for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -988,7 +991,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { // lookup the schedules by name for _, schedule := range resources.Schedules { repo := resources.Repos[schedule.GetRepoID()-1] - got, err := db.GetScheduleForRepo(repo, schedule.GetName()) + got, err := db.GetScheduleForRepo(ctx, repo, schedule.GetName()) if err != nil { t.Errorf("unable to get schedule %d for repo %d: %v", schedule.GetID(), repo.GetID(), err) } @@ -1001,13 +1004,13 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { // update the schedules for _, schedule := range resources.Schedules { schedule.SetUpdatedAt(time.Now().UTC().Unix()) - err = db.UpdateSchedule(schedule, true) + err = db.UpdateSchedule(ctx, schedule, true) if err != nil { t.Errorf("unable to update schedule %d: %v", schedule.GetID(), err) } // lookup the schedule by ID - got, err := db.GetSchedule(schedule.GetID()) + got, err := db.GetSchedule(ctx, schedule.GetID()) if err != nil { t.Errorf("unable to get schedule %d by ID: %v", schedule.GetID(), err) } @@ -1020,7 +1023,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { // delete the schedules for _, schedule := range resources.Schedules { - err = db.DeleteSchedule(schedule) + err = db.DeleteSchedule(ctx, schedule) if err != nil { t.Errorf("unable to delete schedule %d: %v", schedule.GetID(), err) } diff --git a/database/opts.go b/database/opts.go index 3714989c5..42ab3d033 100644 --- a/database/opts.go +++ b/database/opts.go @@ -4,7 +4,10 @@ package database -import "time" +import ( + "context" + "time" +) // EngineOpt represents a configuration option to initialize the database engine. type EngineOpt func(*engine) error @@ -88,3 +91,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/resource.go b/database/resource.go index 1ff9c929c..f9643b229 100644 --- a/database/resource.go +++ b/database/resource.go @@ -5,6 +5,7 @@ package database import ( + "context" "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" @@ -19,7 +20,7 @@ import ( ) // NewResources creates and returns the database agnostic engines for resources. -func (e *engine) NewResources() error { +func (e *engine) NewResources(ctx context.Context) error { var err error // create the database agnostic engine for builds @@ -77,6 +78,7 @@ func (e *engine) NewResources() error { // create the database agnostic engine for schedules e.ScheduleInterface, err = schedule.New( + schedule.WithContext(e.ctx), schedule.WithClient(e.client), schedule.WithLogger(e.logger), schedule.WithSkipCreation(e.config.SkipCreation), diff --git a/database/resource_test.go b/database/resource_test.go index 36a4694e6..233dbb800 100644 --- a/database/resource_test.go +++ b/database/resource_test.go @@ -5,6 +5,7 @@ package database import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -94,7 +95,7 @@ func TestDatabase_Engine_NewResources(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.NewResources() + err := test.database.NewResources(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/count.go b/database/schedule/count.go index c7ce5f3aa..7a0d8c1ee 100644 --- a/database/schedule/count.go +++ b/database/schedule/count.go @@ -5,11 +5,12 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" ) // CountSchedules gets the count of all schedules from the database. -func (e *engine) CountSchedules() (int64, error) { +func (e *engine) CountSchedules(ctx context.Context) (int64, error) { e.logger.Tracef("getting count of all schedules from the database") // variable to store query results diff --git a/database/schedule/count_active.go b/database/schedule/count_active.go index f3240f2f8..d65315186 100644 --- a/database/schedule/count_active.go +++ b/database/schedule/count_active.go @@ -5,11 +5,12 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" ) // CountActiveSchedules gets the count of all active schedules from the database. -func (e *engine) CountActiveSchedules() (int64, error) { +func (e *engine) CountActiveSchedules(ctx context.Context) (int64, error) { e.logger.Tracef("getting count of all active schedules from the database") // variable to store query results diff --git a/database/schedule/count_active_test.go b/database/schedule/count_active_test.go index aa417efaa..866e11425 100644 --- a/database/schedule/count_active_test.go +++ b/database/schedule/count_active_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -46,12 +47,12 @@ func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -80,7 +81,7 @@ func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountActiveSchedules() + got, err := test.database.CountActiveSchedules(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/count_repo.go b/database/schedule/count_repo.go index 1ec5177cb..da806151c 100644 --- a/database/schedule/count_repo.go +++ b/database/schedule/count_repo.go @@ -5,13 +5,14 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // CountSchedulesForRepo gets the count of schedules by repo ID from the database. -func (e *engine) CountSchedulesForRepo(r *library.Repo) (int64, error) { +func (e *engine) CountSchedulesForRepo(ctx context.Context, r *library.Repo) (int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/schedule/count_repo_test.go b/database/schedule/count_repo_test.go index 792c21b1d..7bfbbe9bd 100644 --- a/database/schedule/count_repo_test.go +++ b/database/schedule/count_repo_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -50,12 +51,12 @@ func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -84,7 +85,7 @@ func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountSchedulesForRepo(_repo) + got, err := test.database.CountSchedulesForRepo(context.TODO(), _repo) if test.failure { if err == nil { diff --git a/database/schedule/count_test.go b/database/schedule/count_test.go index 01cfbbae4..d8523b784 100644 --- a/database/schedule/count_test.go +++ b/database/schedule/count_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -44,12 +45,12 @@ func TestSchedule_Engine_CountSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -78,7 +79,7 @@ func TestSchedule_Engine_CountSchedules(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountSchedules() + got, err := test.database.CountSchedules(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/create.go b/database/schedule/create.go index a6e532e8c..f04b95508 100644 --- a/database/schedule/create.go +++ b/database/schedule/create.go @@ -6,6 +6,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -13,7 +14,7 @@ import ( ) // CreateSchedule creates a new schedule in the database. -func (e *engine) CreateSchedule(s *library.Schedule) error { +func (e *engine) CreateSchedule(ctx context.Context, s *library.Schedule) error { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("creating schedule %s in the database", s.GetName()) diff --git a/database/schedule/create_test.go b/database/schedule/create_test.go index 015654151..426115915 100644 --- a/database/schedule/create_test.go +++ b/database/schedule/create_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -58,7 +59,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateSchedule(_schedule) + err := test.database.CreateSchedule(context.TODO(), _schedule) if test.failure { if err == nil { diff --git a/database/schedule/delete.go b/database/schedule/delete.go index 42ee4988d..765b31120 100644 --- a/database/schedule/delete.go +++ b/database/schedule/delete.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +13,7 @@ import ( ) // DeleteSchedule deletes an existing schedule from the database. -func (e *engine) DeleteSchedule(s *library.Schedule) error { +func (e *engine) DeleteSchedule(ctx context.Context, s *library.Schedule) error { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("deleting schedule %s in the database", s.GetName()) diff --git a/database/schedule/delete_test.go b/database/schedule/delete_test.go index 3d1a3cd48..0e958de52 100644 --- a/database/schedule/delete_test.go +++ b/database/schedule/delete_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -32,7 +33,7 @@ func TestSchedule_Engine_DeleteSchedule(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_schedule) + err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -58,7 +59,7 @@ func TestSchedule_Engine_DeleteSchedule(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.DeleteSchedule(_schedule) + err = test.database.DeleteSchedule(context.TODO(), _schedule) if test.failure { if err == nil { diff --git a/database/schedule/get.go b/database/schedule/get.go index 73fcc162e..e4540f0f0 100644 --- a/database/schedule/get.go +++ b/database/schedule/get.go @@ -5,13 +5,14 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // GetSchedule gets a schedule by ID from the database. -func (e *engine) GetSchedule(id int64) (*library.Schedule, error) { +func (e *engine) GetSchedule(ctx context.Context, id int64) (*library.Schedule, error) { e.logger.Tracef("getting schedule %d from the database", id) // variable to store query results diff --git a/database/schedule/get_repo.go b/database/schedule/get_repo.go index ff5ab40e5..d0ddc4271 100644 --- a/database/schedule/get_repo.go +++ b/database/schedule/get_repo.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +13,7 @@ import ( ) // GetScheduleForRepo gets a schedule by repo ID and name from the database. -func (e *engine) GetScheduleForRepo(r *library.Repo, name string) (*library.Schedule, error) { +func (e *engine) GetScheduleForRepo(ctx context.Context, r *library.Repo, name string) (*library.Schedule, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/schedule/get_repo_test.go b/database/schedule/get_repo_test.go index fb29bea37..56b010e97 100644 --- a/database/schedule/get_repo_test.go +++ b/database/schedule/get_repo_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -43,7 +44,7 @@ func TestSchedule_Engine_GetScheduleForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_schedule) + err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -72,7 +73,7 @@ func TestSchedule_Engine_GetScheduleForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetScheduleForRepo(_repo, "nightly") + got, err := test.database.GetScheduleForRepo(context.TODO(), _repo, "nightly") if test.failure { if err == nil { diff --git a/database/schedule/get_test.go b/database/schedule/get_test.go index acea35b2a..6fc0ed11e 100644 --- a/database/schedule/get_test.go +++ b/database/schedule/get_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -37,7 +38,7 @@ func TestSchedule_Engine_GetSchedule(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_schedule) + err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -66,7 +67,7 @@ func TestSchedule_Engine_GetSchedule(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetSchedule(1) + got, err := test.database.GetSchedule(context.TODO(), 1) if test.failure { if err == nil { diff --git a/database/schedule/index.go b/database/schedule/index.go index f14082cee..6b88199fa 100644 --- a/database/schedule/index.go +++ b/database/schedule/index.go @@ -4,6 +4,8 @@ package schedule +import "context" + const ( // CreateRepoIDIndex represents a query to create an // index on the schedules table for the repo_id column. @@ -16,7 +18,7 @@ ON schedules (repo_id); ) // CreateScheduleIndexes creates the indexes for the schedules table in the database. -func (e *engine) CreateScheduleIndexes() error { +func (e *engine) CreateScheduleIndexes(ctx context.Context) error { e.logger.Tracef("creating indexes for schedules table in the database") // create the repo_id column index for the schedules table diff --git a/database/schedule/index_test.go b/database/schedule/index_test.go index b8d334366..145fd5ac7 100644 --- a/database/schedule/index_test.go +++ b/database/schedule/index_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestSchedule_Engine_CreateScheduleIndexes(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateScheduleIndexes() + err := test.database.CreateScheduleIndexes(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/interface.go b/database/schedule/interface.go index afa163063..6f7309d16 100644 --- a/database/schedule/interface.go +++ b/database/schedule/interface.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/library" ) @@ -18,32 +19,32 @@ type ScheduleInterface interface { // https://en.wikipedia.org/wiki/Data_definition_language // CreateScheduleIndexes defines a function that creates the indexes for the schedules table. - CreateScheduleIndexes() error + CreateScheduleIndexes(context.Context) error // CreateScheduleTable defines a function that creates the schedules table. - CreateScheduleTable(string) error + CreateScheduleTable(context.Context, string) error // Schedule Data Manipulation Language Functions // // https://en.wikipedia.org/wiki/Data_manipulation_language // CountSchedules defines a function that gets the count of all schedules. - CountSchedules() (int64, error) + CountSchedules(context.Context) (int64, error) // CountSchedulesForRepo defines a function that gets the count of schedules by repo ID. - CountSchedulesForRepo(*library.Repo) (int64, error) + CountSchedulesForRepo(context.Context, *library.Repo) (int64, error) // CreateSchedule defines a function that creates a new schedule. - CreateSchedule(*library.Schedule) error + CreateSchedule(context.Context, *library.Schedule) error // DeleteSchedule defines a function that deletes an existing schedule. - DeleteSchedule(*library.Schedule) error + DeleteSchedule(context.Context, *library.Schedule) error // GetSchedule defines a function that gets a schedule by ID. - GetSchedule(int64) (*library.Schedule, error) + GetSchedule(context.Context, int64) (*library.Schedule, error) // GetScheduleForRepo defines a function that gets a schedule by repo ID and name. - GetScheduleForRepo(*library.Repo, string) (*library.Schedule, error) + GetScheduleForRepo(context.Context, *library.Repo, string) (*library.Schedule, error) // ListActiveSchedules defines a function that gets a list of all active schedules. - ListActiveSchedules() ([]*library.Schedule, error) + ListActiveSchedules(context.Context) ([]*library.Schedule, error) // ListSchedules defines a function that gets a list of all schedules. - ListSchedules() ([]*library.Schedule, error) + ListSchedules(context.Context) ([]*library.Schedule, error) // ListSchedulesForRepo defines a function that gets a list of schedules by repo ID. - ListSchedulesForRepo(*library.Repo, int, int) ([]*library.Schedule, int64, error) + ListSchedulesForRepo(context.Context, *library.Repo, int, int) ([]*library.Schedule, int64, error) // UpdateSchedule defines a function that updates an existing schedule. - UpdateSchedule(*library.Schedule, bool) error + UpdateSchedule(context.Context, *library.Schedule, bool) error } diff --git a/database/schedule/list.go b/database/schedule/list.go index f4c5aa5e7..fbba87ca2 100644 --- a/database/schedule/list.go +++ b/database/schedule/list.go @@ -5,13 +5,14 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListSchedules gets a list of all schedules from the database. -func (e *engine) ListSchedules() ([]*library.Schedule, error) { +func (e *engine) ListSchedules(ctx context.Context) ([]*library.Schedule, error) { e.logger.Trace("listing all schedules from the database") // variables to store query results and return value @@ -20,7 +21,7 @@ func (e *engine) ListSchedules() ([]*library.Schedule, error) { schedules := []*library.Schedule{} // count the results - count, err := e.CountSchedules() + count, err := e.CountSchedules(ctx) if err != nil { return nil, err } diff --git a/database/schedule/list_active.go b/database/schedule/list_active.go index d0efa5dde..0afd4ddc5 100644 --- a/database/schedule/list_active.go +++ b/database/schedule/list_active.go @@ -5,13 +5,14 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListActiveSchedules gets a list of all active schedules from the database. -func (e *engine) ListActiveSchedules() ([]*library.Schedule, error) { +func (e *engine) ListActiveSchedules(ctx context.Context) ([]*library.Schedule, error) { e.logger.Trace("listing all active schedules from the database") // variables to store query results and return value @@ -20,7 +21,7 @@ func (e *engine) ListActiveSchedules() ([]*library.Schedule, error) { schedules := []*library.Schedule{} // count the results - count, err := e.CountActiveSchedules() + count, err := e.CountActiveSchedules(ctx) if err != nil { return nil, err } diff --git a/database/schedule/list_active_test.go b/database/schedule/list_active_test.go index 69c690def..35591a4ad 100644 --- a/database/schedule/list_active_test.go +++ b/database/schedule/list_active_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -55,12 +56,12 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -89,7 +90,7 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListActiveSchedules() + got, err := test.database.ListActiveSchedules(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/list_repo.go b/database/schedule/list_repo.go index 1137e0c4b..9d0cfed5e 100644 --- a/database/schedule/list_repo.go +++ b/database/schedule/list_repo.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +13,7 @@ import ( ) // ListSchedulesForRepo gets a list of schedules by repo ID from the database. -func (e *engine) ListSchedulesForRepo(r *library.Repo, page, perPage int) ([]*library.Schedule, int64, error) { +func (e *engine) ListSchedulesForRepo(ctx context.Context, r *library.Repo, page, perPage int) ([]*library.Schedule, int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -24,7 +25,7 @@ func (e *engine) ListSchedulesForRepo(r *library.Repo, page, perPage int) ([]*li schedules := []*library.Schedule{} // count the results - count, err := e.CountSchedulesForRepo(r) + count, err := e.CountSchedulesForRepo(ctx, r) if err != nil { return nil, 0, err } diff --git a/database/schedule/list_repo_test.go b/database/schedule/list_repo_test.go index df56c0ee4..425e5dddb 100644 --- a/database/schedule/list_repo_test.go +++ b/database/schedule/list_repo_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -59,12 +60,12 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -93,7 +94,7 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListSchedulesForRepo(_repo, 1, 10) + got, _, err := test.database.ListSchedulesForRepo(context.TODO(), _repo, 1, 10) if test.failure { if err == nil { diff --git a/database/schedule/list_test.go b/database/schedule/list_test.go index b0c3bb417..cdb13f756 100644 --- a/database/schedule/list_test.go +++ b/database/schedule/list_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "reflect" "testing" @@ -54,12 +55,12 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_scheduleOne) + err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(_scheduleTwo) + err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -88,7 +89,7 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListSchedules() + got, err := test.database.ListSchedules(context.TODO()) if test.failure { if err == nil { diff --git a/database/schedule/opts.go b/database/schedule/opts.go index 7ac87bea1..cb2c89cfe 100644 --- a/database/schedule/opts.go +++ b/database/schedule/opts.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -42,3 +43,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine for Schedules. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/schedule/schedule.go b/database/schedule/schedule.go index 0517dcae9..269278f52 100644 --- a/database/schedule/schedule.go +++ b/database/schedule/schedule.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -25,6 +26,8 @@ type ( // engine configuration settings used in schedule functions config *config + ctx context.Context + // gorm.io/gorm database client used in schedule functions // // https://pkg.go.dev/gorm.io/gorm#DB @@ -65,13 +68,13 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the schedules table - err := e.CreateScheduleTable(e.client.Config.Dialector.Name()) + err := e.CreateScheduleTable(e.ctx, e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TableSchedule, err) } // create the indexes for the schedules table - err = e.CreateScheduleIndexes() + err = e.CreateScheduleIndexes(e.ctx) if err != nil { return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableSchedule, err) } diff --git a/database/schedule/schedule_test.go b/database/schedule/schedule_test.go index fc4b4c6e1..aae0403a5 100644 --- a/database/schedule/schedule_test.go +++ b/database/schedule/schedule_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "database/sql/driver" "reflect" "testing" @@ -63,6 +64,7 @@ func TestSchedule_New(t *testing.T) { logger: logger, skipCreation: false, want: &engine{ + ctx: context.TODO(), client: _postgres, config: &config{SkipCreation: false}, logger: logger, @@ -75,6 +77,7 @@ func TestSchedule_New(t *testing.T) { logger: logger, skipCreation: false, want: &engine{ + ctx: context.TODO(), client: _sqlite, config: &config{SkipCreation: false}, logger: logger, @@ -86,6 +89,7 @@ func TestSchedule_New(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { got, err := New( + WithContext(context.TODO()), WithClient(test.client), WithLogger(test.logger), WithSkipCreation(test.skipCreation), @@ -135,6 +139,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { } _engine, err := New( + WithContext(context.TODO()), WithClient(_postgres), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), @@ -157,6 +162,7 @@ func testSqlite(t *testing.T) *engine { } _engine, err := New( + WithContext(context.TODO()), WithClient(_sqlite), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), diff --git a/database/schedule/table.go b/database/schedule/table.go index 05ffe8bad..7ea6eb873 100644 --- a/database/schedule/table.go +++ b/database/schedule/table.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" ) @@ -49,7 +50,7 @@ schedules ( ) // CreateScheduleTable creates the schedules table in the database. -func (e *engine) CreateScheduleTable(driver string) error { +func (e *engine) CreateScheduleTable(ctx context.Context, driver string) error { e.logger.Tracef("creating schedules table in the database") // handle the driver provided to create the table diff --git a/database/schedule/table_test.go b/database/schedule/table_test.go index c4dbf4e40..c0d785ed1 100644 --- a/database/schedule/table_test.go +++ b/database/schedule/table_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestSchedule_Engine_CreateScheduleTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateScheduleTable(test.name) + err := test.database.CreateScheduleTable(context.TODO(), test.name) if test.failure { if err == nil { diff --git a/database/schedule/update.go b/database/schedule/update.go index dd03f62c5..934b50c59 100644 --- a/database/schedule/update.go +++ b/database/schedule/update.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +13,7 @@ import ( ) // UpdateSchedule updates an existing schedule in the database. -func (e *engine) UpdateSchedule(s *library.Schedule, fields bool) error { +func (e *engine) UpdateSchedule(ctx context.Context, s *library.Schedule, fields bool) error { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("updating schedule %s in the database", s.GetName()) diff --git a/database/schedule/update_test.go b/database/schedule/update_test.go index 07cbfbc58..345c7b2db 100644 --- a/database/schedule/update_test.go +++ b/database/schedule/update_test.go @@ -5,6 +5,7 @@ package schedule import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -40,7 +41,7 @@ WHERE "id" = $10`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_schedule) + err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -66,7 +67,7 @@ WHERE "id" = $10`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSchedule(_schedule, true) + err = test.database.UpdateSchedule(context.TODO(), _schedule, true) if test.failure { if err == nil { @@ -112,7 +113,7 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(_schedule) + err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -138,7 +139,7 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSchedule(_schedule, false) + err = test.database.UpdateSchedule(context.TODO(), _schedule, false) if test.failure { if err == nil { diff --git a/router/middleware/schedule/schedule.go b/router/middleware/schedule/schedule.go index de06e0651..65f78c4e0 100644 --- a/router/middleware/schedule/schedule.go +++ b/router/middleware/schedule/schedule.go @@ -27,6 +27,7 @@ func Establish() gin.HandlerFunc { return func(c *gin.Context) { r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() sParam := util.PathParameter(c, "schedule") if len(sParam) == 0 { @@ -45,7 +46,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading schedule %s for repo %s", sParam, r.GetFullName()) - s, err := database.FromContext(c).GetScheduleForRepo(r, sParam) + s, err := database.FromContext(c).GetScheduleForRepo(ctx, r, sParam) if err != nil { retErr := fmt.Errorf("unable to read schedule %s for repo %s: %w", sParam, r.GetFullName(), err) util.HandleError(c, http.StatusNotFound, retErr) From 439455c96e847ca6313eccbc93656aeb91a03d46 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 11 Aug 2023 08:00:25 -0500 Subject: [PATCH 285/298] chore: add context to build functions (#922) --- api/admin/build.go | 10 ++++- api/admin/clean.go | 5 ++- api/badge.go | 4 +- api/build/cancel.go | 3 +- api/build/clean.go | 5 ++- api/build/create.go | 8 ++-- api/build/delete.go | 3 +- api/build/get_id.go | 3 +- api/build/list_org.go | 3 +- api/build/list_repo.go | 3 +- api/build/plan.go | 11 +++--- api/build/publish.go | 10 ++--- api/build/restart.go | 8 ++-- api/build/update.go | 3 +- api/deployment/list.go | 3 +- api/metrics.go | 17 ++++---- api/webhook/post.go | 21 ++++++---- cmd/vela-server/schedule.go | 7 ++-- database/build/build.go | 7 +++- database/build/build_test.go | 6 +++ database/build/clean.go | 3 +- database/build/clean_test.go | 11 +++--- database/build/count.go | 4 +- database/build/count_deployment.go | 4 +- database/build/count_deployment_test.go | 7 ++-- database/build/count_org.go | 4 +- database/build/count_org_test.go | 7 ++-- database/build/count_repo.go | 4 +- database/build/count_repo_test.go | 7 ++-- database/build/count_status.go | 4 +- database/build/count_status_test.go | 7 ++-- database/build/count_test.go | 7 ++-- database/build/create.go | 4 +- database/build/create_test.go | 3 +- database/build/delete.go | 4 +- database/build/delete_test.go | 5 ++- database/build/get.go | 4 +- database/build/get_repo.go | 4 +- database/build/get_repo_test.go | 5 ++- database/build/get_test.go | 5 ++- database/build/index.go | 4 +- database/build/index_test.go | 3 +- database/build/interface.go | 40 ++++++++++--------- database/build/last_repo.go | 3 +- database/build/last_repo_test.go | 5 ++- database/build/list.go | 6 ++- database/build/list_deployment.go | 6 ++- database/build/list_deployment_test.go | 7 ++-- database/build/list_org.go | 6 ++- database/build/list_org_test.go | 7 ++-- database/build/list_pending_running.go | 4 +- database/build/list_pending_running_test.go | 7 ++-- database/build/list_repo.go | 6 ++- database/build/list_repo_test.go | 7 ++-- database/build/list_test.go | 7 ++-- database/build/opts.go | 11 ++++++ database/build/table.go | 8 +++- database/build/table_test.go | 3 +- database/build/update.go | 4 +- database/build/update_test.go | 5 ++- database/integration_test.go | 34 ++++++++-------- database/resource.go | 1 + router/middleware/build/build.go | 3 +- router/middleware/build/build_test.go | 5 ++- router/middleware/perm/perm_test.go | 43 ++++++++++++++------- router/middleware/service/service_test.go | 17 ++++---- router/middleware/step/step_test.go | 17 ++++---- 67 files changed, 322 insertions(+), 190 deletions(-) diff --git a/api/admin/build.go b/api/admin/build.go index 0666c2fad..2be805ef2 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -50,13 +50,16 @@ import ( // AllBuildsQueue represents the API handler to // captures all running and pending builds stored in the database. func AllBuildsQueue(c *gin.Context) { + // capture middleware values + ctx := c.Request.Context() + logrus.Info("Admin: reading running and pending builds") // default timestamp to 24 hours ago if user did not provide it as query parameter after := c.DefaultQuery("after", strconv.FormatInt(time.Now().UTC().Add(-24*time.Hour).Unix(), 10)) // send API call to capture pending and running builds - b, err := database.FromContext(c).ListPendingAndRunningBuilds(after) + b, err := database.FromContext(c).ListPendingAndRunningBuilds(ctx, after) if err != nil { retErr := fmt.Errorf("unable to capture all running and pending builds: %w", err) @@ -103,6 +106,9 @@ func AllBuildsQueue(c *gin.Context) { func UpdateBuild(c *gin.Context) { logrus.Info("Admin: updating build in database") + // capture middleware values + ctx := c.Request.Context() + // capture body from API request input := new(library.Build) @@ -116,7 +122,7 @@ func UpdateBuild(c *gin.Context) { } // send API call to update the build - b, err := database.FromContext(c).UpdateBuild(input) + b, err := database.FromContext(c).UpdateBuild(ctx, input) if err != nil { retErr := fmt.Errorf("unable to update build %d: %w", input.GetID(), err) diff --git a/api/admin/clean.go b/api/admin/clean.go index 4895c3e55..89884c8d5 100644 --- a/api/admin/clean.go +++ b/api/admin/clean.go @@ -62,7 +62,10 @@ import ( // CleanResources represents the API handler to // update any user stored in the database. func CleanResources(c *gin.Context) { + // capture middleware values u := user.Retrieve(c) + ctx := c.Request.Context() + logrus.Infof("platform admin %s: updating pending resources in database", u.GetName()) // default error message @@ -96,7 +99,7 @@ func CleanResources(c *gin.Context) { } // send API call to clean builds - builds, err := database.FromContext(c).CleanBuilds(msg, before) + builds, err := database.FromContext(c).CleanBuilds(ctx, msg, before) if err != nil { retErr := fmt.Errorf("unable to update builds: %w", err) diff --git a/api/badge.go b/api/badge.go index cdc028e28..bb84d2c48 100644 --- a/api/badge.go +++ b/api/badge.go @@ -46,6 +46,8 @@ func GetBadge(c *gin.Context) { // capture middleware values o := org.Retrieve(c) r := repo.Retrieve(c) + ctx := c.Request.Context() + branch := util.QueryParameter(c, "branch", r.GetBranch()) // update engine logger with API metadata @@ -57,7 +59,7 @@ func GetBadge(c *gin.Context) { }).Infof("creating latest build badge for repo %s on branch %s", r.GetFullName(), branch) // send API call to capture the last build for the repo and branch - b, err := database.FromContext(c).LastBuildForRepo(r, branch) + b, err := database.FromContext(c).LastBuildForRepo(ctx, r, branch) if err != nil { c.String(http.StatusOK, constants.BadgeUnknown) return diff --git a/api/build/cancel.go b/api/build/cancel.go index 350573911..923d2eb77 100644 --- a/api/build/cancel.go +++ b/api/build/cancel.go @@ -80,6 +80,7 @@ func CancelBuild(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) @@ -190,7 +191,7 @@ func CancelBuild(c *gin.Context) { // update the status in the build table b.SetStatus(constants.StatusCanceled) - b, err := database.FromContext(c).UpdateBuild(b) + b, err := database.FromContext(c).UpdateBuild(ctx, b) if err != nil { retErr := fmt.Errorf("unable to update status for build %s: %w", entry, err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/api/build/clean.go b/api/build/clean.go index 6fc0ba10b..8344694b7 100644 --- a/api/build/clean.go +++ b/api/build/clean.go @@ -5,6 +5,7 @@ package build import ( + "context" "fmt" "time" @@ -18,14 +19,14 @@ import ( // without execution. This will kill all resources, // like steps and services, for the build in the // configured backend. -func CleanBuild(database database.Interface, b *library.Build, services []*library.Service, steps []*library.Step, e error) { +func CleanBuild(ctx context.Context, database database.Interface, b *library.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) b.SetFinished(time.Now().UTC().Unix()) // send API call to update the build - b, err := database.UpdateBuild(b) + b, err := database.UpdateBuild(ctx, b) if err != nil { logrus.Errorf("unable to kill build %d: %v", b.GetNumber(), err) } diff --git a/api/build/create.go b/api/build/create.go index cac912867..8b97062ae 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -85,6 +85,7 @@ func CreateBuild(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -137,7 +138,7 @@ func CreateBuild(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(ctx, r, filters) if err != nil { retErr := fmt.Errorf("unable to create new build: unable to get count of builds for repo %s", r.GetFullName()) @@ -321,7 +322,7 @@ func CreateBuild(c *gin.Context) { input.SetPipelineID(pipeline.GetID()) // create the objects from the pipeline in the database - err = PlanBuild(database.FromContext(c), p, input, r) + err = PlanBuild(ctx, database.FromContext(c), p, input, r) if err != nil { util.HandleError(c, http.StatusInternalServerError, err) @@ -339,7 +340,7 @@ func CreateBuild(c *gin.Context) { } // send API call to capture the created build - input, _ = database.FromContext(c).GetBuildForRepo(r, input.GetNumber()) + input, _ = database.FromContext(c).GetBuildForRepo(ctx, r, input.GetNumber()) c.JSON(http.StatusCreated, input) @@ -351,6 +352,7 @@ func CreateBuild(c *gin.Context) { // publish the build to the queue go PublishToQueue( + ctx, queue.FromGinContext(c), database.FromContext(c), p, diff --git a/api/build/delete.go b/api/build/delete.go index 19a1fd17c..ffc9a7ac4 100644 --- a/api/build/delete.go +++ b/api/build/delete.go @@ -65,6 +65,7 @@ func DeleteBuild(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) @@ -79,7 +80,7 @@ func DeleteBuild(c *gin.Context) { }).Infof("deleting build %s", entry) // send API call to remove the build - err := database.FromContext(c).DeleteBuild(b) + err := database.FromContext(c).DeleteBuild(ctx, b) if err != nil { retErr := fmt.Errorf("unable to delete build %s: %w", entry, err) diff --git a/api/build/get_id.go b/api/build/get_id.go index 47fb18874..1bbd47d69 100644 --- a/api/build/get_id.go +++ b/api/build/get_id.go @@ -58,6 +58,7 @@ func GetBuildByID(c *gin.Context) { // Capture user from middleware u := user.Retrieve(c) + ctx := c.Request.Context() // Parse build ID from path id, err := strconv.ParseInt(c.Param("id"), 10, 64) @@ -79,7 +80,7 @@ func GetBuildByID(c *gin.Context) { }).Infof("reading build %d", id) // Get build from database - b, err = database.FromContext(c).GetBuild(id) + b, err = database.FromContext(c).GetBuild(ctx, id) if err != nil { retErr := fmt.Errorf("unable to get build: %w", err) diff --git a/api/build/list_org.go b/api/build/list_org.go index 9758bbc6a..3ab3bf9d3 100644 --- a/api/build/list_org.go +++ b/api/build/list_org.go @@ -110,6 +110,7 @@ func ListBuildsForOrg(c *gin.Context) { // capture middleware values o := org.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -199,7 +200,7 @@ func ListBuildsForOrg(c *gin.Context) { } // send API call to capture the list of builds for the org (and event type if passed in) - b, t, err = database.FromContext(c).ListBuildsForOrg(o, filters, page, perPage) + b, t, err = database.FromContext(c).ListBuildsForOrg(ctx, o, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to list builds for org %s: %w", o, err) diff --git a/api/build/list_repo.go b/api/build/list_repo.go index f11d35b0b..1fb701dc5 100644 --- a/api/build/list_repo.go +++ b/api/build/list_repo.go @@ -131,6 +131,7 @@ func ListBuildsForRepo(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -238,7 +239,7 @@ func ListBuildsForRepo(c *gin.Context) { return } - b, t, err = database.FromContext(c).ListBuildsForRepo(r, filters, before, after, page, perPage) + b, t, err = database.FromContext(c).ListBuildsForRepo(ctx, r, filters, before, after, page, perPage) if err != nil { retErr := fmt.Errorf("unable to list builds for repo %s: %w", r.GetFullName(), err) diff --git a/api/build/plan.go b/api/build/plan.go index eff7aa630..13080b40c 100644 --- a/api/build/plan.go +++ b/api/build/plan.go @@ -5,6 +5,7 @@ package build import ( + "context" "fmt" "time" @@ -20,13 +21,13 @@ import ( // and services, for the build in the configured backend. // TODO: // - return build and error. -func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { +func PlanBuild(ctx context.Context, database database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) // send API call to create the build // TODO: return created build and error instead of just error - b, err := database.CreateBuild(b) + b, err := database.CreateBuild(ctx, b) if err != nil { // clean up the objects from the pipeline in the database // TODO: @@ -35,7 +36,7 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, // of UPDATE-ing the existing build - which results in // a constraint error (repo_id, number) // - do we want to update the build or just delete it? - CleanBuild(database, b, nil, nil, err) + CleanBuild(ctx, database, b, nil, nil, err) return fmt.Errorf("unable to create new build for %s: %w", r.GetFullName(), err) } @@ -44,7 +45,7 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, services, err := service.PlanServices(database, p, b) if err != nil { // clean up the objects from the pipeline in the database - CleanBuild(database, b, services, nil, err) + CleanBuild(ctx, database, b, services, nil, err) return err } @@ -53,7 +54,7 @@ func PlanBuild(database database.Interface, p *pipeline.Build, b *library.Build, steps, err := step.PlanSteps(database, p, b) if err != nil { // clean up the objects from the pipeline in the database - CleanBuild(database, b, services, steps, err) + CleanBuild(ctx, database, b, services, steps, err) return err } diff --git a/api/build/publish.go b/api/build/publish.go index a74bc265c..7e1b3d5a3 100644 --- a/api/build/publish.go +++ b/api/build/publish.go @@ -19,7 +19,7 @@ import ( // PublishToQueue is a helper function that creates // a build item and publishes it to the queue. -func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { +func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { item := types.ToItem(p, b, r, u) logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) @@ -29,7 +29,7 @@ func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Buil logrus.Errorf("Failed to convert item to json for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - CleanBuild(db, b, nil, nil, err) + CleanBuild(ctx, db, b, nil, nil, err) return } @@ -41,7 +41,7 @@ func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Buil logrus.Errorf("unable to set route for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - CleanBuild(db, b, nil, nil, err) + CleanBuild(ctx, db, b, nil, nil, err) return } @@ -57,7 +57,7 @@ func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Buil logrus.Errorf("Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) // error out the build - CleanBuild(db, b, nil, nil, err) + CleanBuild(ctx, db, b, nil, nil, err) return } @@ -67,7 +67,7 @@ func PublishToQueue(queue queue.Service, db database.Interface, p *pipeline.Buil b.SetEnqueued(time.Now().UTC().Unix()) // update the build in the db to reflect the time it was enqueued - _, err = db.UpdateBuild(b) + _, err = db.UpdateBuild(ctx, b) if err != nil { logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", b.GetNumber(), r.GetFullName(), err) } diff --git a/api/build/restart.go b/api/build/restart.go index 7b7dcca69..e2280cce2 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -86,6 +86,7 @@ func RestartBuild(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) @@ -117,7 +118,7 @@ func RestartBuild(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).CountBuildsForRepo(r, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(ctx, r, filters) if err != nil { retErr := fmt.Errorf("unable to restart build: unable to get count of builds for repo %s", r.GetFullName()) @@ -312,7 +313,7 @@ func RestartBuild(c *gin.Context) { b.SetPipelineID(pipeline.GetID()) // create the objects from the pipeline in the database - err = PlanBuild(database.FromContext(c), p, b, r) + err = PlanBuild(ctx, database.FromContext(c), p, b, r) if err != nil { util.HandleError(c, http.StatusInternalServerError, err) @@ -329,7 +330,7 @@ func RestartBuild(c *gin.Context) { } // send API call to capture the restarted build - b, _ = database.FromContext(c).GetBuildForRepo(r, b.GetNumber()) + b, _ = database.FromContext(c).GetBuildForRepo(ctx, r, b.GetNumber()) c.JSON(http.StatusCreated, b) @@ -341,6 +342,7 @@ func RestartBuild(c *gin.Context) { // publish the build to the queue go PublishToQueue( + ctx, queue.FromGinContext(c), database.FromContext(c), p, diff --git a/api/build/update.go b/api/build/update.go index 8dde2cd77..d042fdd82 100644 --- a/api/build/update.go +++ b/api/build/update.go @@ -74,6 +74,7 @@ func UpdateBuild(c *gin.Context) { b := build.Retrieve(c) o := org.Retrieve(c) r := repo.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%d", r.GetFullName(), b.GetNumber()) @@ -151,7 +152,7 @@ func UpdateBuild(c *gin.Context) { } // send API call to update the build - b, err = database.FromContext(c).UpdateBuild(b) + b, err = database.FromContext(c).UpdateBuild(ctx, b) if err != nil { retErr := fmt.Errorf("unable to update build %s: %w", entry, err) diff --git a/api/deployment/list.go b/api/deployment/list.go index b3745aeca..cb2ec2010 100644 --- a/api/deployment/list.go +++ b/api/deployment/list.go @@ -82,6 +82,7 @@ func ListDeployments(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -138,7 +139,7 @@ func ListDeployments(c *gin.Context) { dWithBs := []*library.Deployment{} for _, deployment := range d { - b, _, err := database.FromContext(c).ListBuildsForDeployment(deployment, nil, 1, 3) + b, _, err := database.FromContext(c).ListBuildsForDeployment(ctx, deployment, nil, 1, 3) if err != nil { retErr := fmt.Errorf("unable to get builds for deployment %d: %w", deployment.GetID(), err) diff --git a/api/metrics.go b/api/metrics.go index fc1a7f04f..c8c120868 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -234,6 +234,9 @@ func CustomMetrics(c *gin.Context) { // //nolint:funlen,gocyclo // ignore function length and cyclomatic complexity func recordGauges(c *gin.Context) { + // capture middleware values + ctx := c.Request.Context() + // variable to store query parameters q := MetricsQueryParameters{} @@ -269,7 +272,7 @@ func recordGauges(c *gin.Context) { // build_count if q.BuildCount { // send API call to capture the total number of builds - b, err := database.FromContext(c).CountBuilds() + b, err := database.FromContext(c).CountBuilds(ctx) if err != nil { logrus.Errorf("unable to get count of all builds: %v", err) } @@ -280,7 +283,7 @@ func recordGauges(c *gin.Context) { // running_build_count if q.RunningBuildCount { // send API call to capture the total number of running builds - bRun, err := database.FromContext(c).CountBuildsForStatus("running", nil) + bRun, err := database.FromContext(c).CountBuildsForStatus(ctx, "running", nil) if err != nil { logrus.Errorf("unable to get count of all running builds: %v", err) } @@ -291,7 +294,7 @@ func recordGauges(c *gin.Context) { // pending_build_count if q.PendingBuildCount { // send API call to capture the total number of pending builds - bPen, err := database.FromContext(c).CountBuildsForStatus("pending", nil) + bPen, err := database.FromContext(c).CountBuildsForStatus(ctx, "pending", nil) if err != nil { logrus.Errorf("unable to get count of all pending builds: %v", err) } @@ -313,7 +316,7 @@ func recordGauges(c *gin.Context) { // failure_build_count if q.FailureBuildCount { // send API call to capture the total number of failure builds - bFail, err := database.FromContext(c).CountBuildsForStatus("failure", nil) + bFail, err := database.FromContext(c).CountBuildsForStatus(ctx, "failure", nil) if err != nil { logrus.Errorf("unable to get count of all failure builds: %v", err) } @@ -324,7 +327,7 @@ func recordGauges(c *gin.Context) { // killed_build_count if q.KilledBuildCount { // send API call to capture the total number of killed builds - bKill, err := database.FromContext(c).CountBuildsForStatus("killed", nil) + bKill, err := database.FromContext(c).CountBuildsForStatus(ctx, "killed", nil) if err != nil { logrus.Errorf("unable to get count of all killed builds: %v", err) } @@ -335,7 +338,7 @@ func recordGauges(c *gin.Context) { // success_build_count if q.SuccessBuildCount { // send API call to capture the total number of success builds - bSucc, err := database.FromContext(c).CountBuildsForStatus("success", nil) + bSucc, err := database.FromContext(c).CountBuildsForStatus(ctx, "success", nil) if err != nil { logrus.Errorf("unable to get count of all success builds: %v", err) } @@ -346,7 +349,7 @@ func recordGauges(c *gin.Context) { // error_build_count if q.ErrorBuildCount { // send API call to capture the total number of error builds - bErr, err := database.FromContext(c).CountBuildsForStatus("error", nil) + bErr, err := database.FromContext(c).CountBuildsForStatus(ctx, "error", nil) if err != nil { logrus.Errorf("unable to get count of all error builds: %v", err) } diff --git a/api/webhook/post.go b/api/webhook/post.go index bae23a863..1d6f4edd8 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -6,7 +6,6 @@ package webhook import ( "bytes" - "context" "fmt" "io" "net/http" @@ -76,11 +75,12 @@ func PostWebhook(c *gin.Context) { // capture middleware values m := c.MustGet("metadata").(*types.Metadata) + ctx := c.Request.Context() // duplicate request so we can perform operations on the request body // // https://golang.org/pkg/net/http/#Request.Clone - dupRequest := c.Request.Clone(context.TODO()) + dupRequest := c.Request.Clone(ctx) // -------------------- Start of TODO: -------------------- // @@ -313,7 +313,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the number of pending or running builds for the repo - builds, err := database.FromContext(c).CountBuildsForRepo(repo, filters) + builds, err := database.FromContext(c).CountBuildsForRepo(ctx, repo, filters) if err != nil { retErr := fmt.Errorf("%s: unable to get count of builds for repo %s", baseErr, repo.GetFullName()) util.HandleError(c, http.StatusBadRequest, retErr) @@ -591,7 +591,7 @@ func PostWebhook(c *gin.Context) { // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = build.PlanBuild(database.FromContext(c), p, b, repo) + err = build.PlanBuild(ctx, database.FromContext(c), p, b, repo) if err != nil { retErr := fmt.Errorf("%s: %w", baseErr, err) @@ -655,7 +655,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture the triggered build - b, err = database.FromContext(c).GetBuildForRepo(repo, b.GetNumber()) + b, err = database.FromContext(c).GetBuildForRepo(ctx, repo, b.GetNumber()) if err != nil { retErr := fmt.Errorf("%s: failed to get new build %s/%d: %w", baseErr, repo.GetFullName(), b.GetNumber(), err) util.HandleError(c, http.StatusInternalServerError, retErr) @@ -679,6 +679,7 @@ func PostWebhook(c *gin.Context) { // publish the build to the queue go build.PublishToQueue( + ctx, queue.FromGinContext(c), database.FromContext(c), p, @@ -782,6 +783,10 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r // associated with that repo as well as build links for the UI. func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) (*library.Repo, error) { logrus.Infof("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) + + // capture context from gin + ctx := c.Request.Context() + // get the old name of the repo prevOrg, prevRepo := util.SplitFullName(r.GetPreviousName()) @@ -851,7 +856,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types } // get total number of builds associated with repository - t, err = database.FromContext(c).CountBuildsForRepo(dbR, nil) + t, err = database.FromContext(c).CountBuildsForRepo(ctx, dbR, nil) if err != nil { return nil, fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) } @@ -860,7 +865,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types page = 1 // capture all builds belonging to repo in database for build := int64(0); build < t; build += 100 { - b, _, err := database.FromContext(c).ListBuildsForRepo(dbR, nil, time.Now().Unix(), 0, page, 100) + b, _, err := database.FromContext(c).ListBuildsForRepo(ctx, dbR, nil, time.Now().Unix(), 0, page, 100) if err != nil { return nil, fmt.Errorf("unable to get build list for repo %s: %w", dbR.GetFullName(), err) } @@ -876,7 +881,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types fmt.Sprintf("%s/%s/%d", m.Vela.WebAddress, r.GetFullName(), build.GetNumber()), ) - _, err = database.FromContext(c).UpdateBuild(build) + _, err = database.FromContext(c).UpdateBuild(ctx, build) if err != nil { return nil, fmt.Errorf("unable to update build for repo %s: %w", dbR.GetFullName(), err) } diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index aa7bed207..cd1a19664 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -173,7 +173,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // send API call to capture the number of pending or running builds for the repo - builds, err := database.CountBuildsForRepo(r, filters) + builds, err := database.CountBuildsForRepo(context.TODO(), r, filters) if err != nil { return fmt.Errorf("unable to get count of builds for repo %s: %w", r.GetFullName(), err) } @@ -351,7 +351,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler // using the same Number and thus create a constraint // conflict; consider deleting the partially created // build object in the database - err = build.PlanBuild(database, p, b, r) + err = build.PlanBuild(context.TODO(), database, p, b, r) if err != nil { // check if the retry limit has been exceeded if i < retryLimit-1 { @@ -380,13 +380,14 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // send API call to capture the triggered build - b, err = database.GetBuildForRepo(r, b.GetNumber()) + b, err = database.GetBuildForRepo(context.TODO(), r, b.GetNumber()) if err != nil { return fmt.Errorf("unable to get new build %s/%d: %w", r.GetFullName(), b.GetNumber(), err) } // publish the build to the queue go build.PublishToQueue( + context.TODO(), queue, database, p, diff --git a/database/build/build.go b/database/build/build.go index 6deb13892..ce750e5ee 100644 --- a/database/build/build.go +++ b/database/build/build.go @@ -5,6 +5,7 @@ package build import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -25,6 +26,8 @@ type ( // engine configuration settings used in build functions config *config + ctx context.Context + // gorm.io/gorm database client used in build functions // // https://pkg.go.dev/gorm.io/gorm#DB @@ -65,13 +68,13 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the builds table - err := e.CreateBuildTable(e.client.Config.Dialector.Name()) + err := e.CreateBuildTable(e.ctx, e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TableBuild, err) } // create the indexes for the builds table - err = e.CreateBuildIndexes() + err = e.CreateBuildIndexes(e.ctx) if err != nil { return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableBuild, err) } diff --git a/database/build/build_test.go b/database/build/build_test.go index 070744260..0e6eb9fd9 100644 --- a/database/build/build_test.go +++ b/database/build/build_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "database/sql/driver" "reflect" "testing" @@ -67,6 +68,7 @@ func TestBuild_New(t *testing.T) { want: &engine{ client: _postgres, config: &config{SkipCreation: false}, + ctx: context.TODO(), logger: logger, }, }, @@ -79,6 +81,7 @@ func TestBuild_New(t *testing.T) { want: &engine{ client: _sqlite, config: &config{SkipCreation: false}, + ctx: context.TODO(), logger: logger, }, }, @@ -88,6 +91,7 @@ func TestBuild_New(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { got, err := New( + WithContext(context.TODO()), WithClient(test.client), WithLogger(test.logger), WithSkipCreation(test.skipCreation), @@ -140,6 +144,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { } _engine, err := New( + WithContext(context.TODO()), WithClient(_postgres), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), @@ -162,6 +167,7 @@ func testSqlite(t *testing.T) *engine { } _engine, err := New( + WithContext(context.TODO()), WithClient(_sqlite), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), diff --git a/database/build/clean.go b/database/build/clean.go index 5e0541b35..700998687 100644 --- a/database/build/clean.go +++ b/database/build/clean.go @@ -5,6 +5,7 @@ package build import ( + "context" "time" "github.com/go-vela/types/constants" @@ -14,7 +15,7 @@ import ( ) // CleanBuilds updates builds to an error with a provided message with a created timestamp prior to a defined moment. -func (e *engine) CleanBuilds(msg string, before int64) (int64, error) { +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) diff --git a/database/build/clean_test.go b/database/build/clean_test.go index ff6e36556..279268ff4 100644 --- a/database/build/clean_test.go +++ b/database/build/clean_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -53,22 +54,22 @@ func TestBuild_Engine_CleanBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildThree) + _, err = _sqlite.CreateBuild(context.TODO(), _buildThree) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildFour) + _, err = _sqlite.CreateBuild(context.TODO(), _buildFour) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -97,7 +98,7 @@ func TestBuild_Engine_CleanBuilds(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CleanBuilds("msg", 3) + got, err := test.database.CleanBuilds(context.TODO(), "msg", 3) if test.failure { if err == nil { diff --git a/database/build/count.go b/database/build/count.go index 7700c5786..57c84030c 100644 --- a/database/build/count.go +++ b/database/build/count.go @@ -5,11 +5,13 @@ package build import ( + "context" + "github.com/go-vela/types/constants" ) // CountBuilds gets the count of all builds from the database. -func (e *engine) CountBuilds() (int64, error) { +func (e *engine) CountBuilds(ctx context.Context) (int64, error) { e.logger.Tracef("getting count of all builds from the database") // variable to store query results diff --git a/database/build/count_deployment.go b/database/build/count_deployment.go index 6203f196b..21e58c6c8 100644 --- a/database/build/count_deployment.go +++ b/database/build/count_deployment.go @@ -5,13 +5,15 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // CountBuildsForDeployment gets the count of builds by deployment URL from the database. -func (e *engine) CountBuildsForDeployment(d *library.Deployment, filters map[string]interface{}) (int64, error) { +func (e *engine) CountBuildsForDeployment(ctx context.Context, d *library.Deployment, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "deployment": d.GetURL(), }).Tracef("getting count of builds for deployment %s from the database", d.GetURL()) diff --git a/database/build/count_deployment_test.go b/database/build/count_deployment_test.go index 611ca6247..4b067896d 100644 --- a/database/build/count_deployment_test.go +++ b/database/build/count_deployment_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -44,12 +45,12 @@ func TestBuild_Engine_CountBuildsForDeployment(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -80,7 +81,7 @@ func TestBuild_Engine_CountBuildsForDeployment(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountBuildsForDeployment(_deployment, filters) + got, err := test.database.CountBuildsForDeployment(context.TODO(), _deployment, filters) if test.failure { if err == nil { diff --git a/database/build/count_org.go b/database/build/count_org.go index 37825bad6..90e01c5e8 100644 --- a/database/build/count_org.go +++ b/database/build/count_org.go @@ -5,12 +5,14 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" ) // CountBuildsForOrg gets the count of builds by org name from the database. -func (e *engine) CountBuildsForOrg(org string, filters map[string]interface{}) (int64, error) { +func (e *engine) CountBuildsForOrg(ctx context.Context, org string, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "org": org, }).Tracef("getting count of builds for org %s from the database", org) diff --git a/database/build/count_org_test.go b/database/build/count_org_test.go index d2c2b2c4d..77b60652b 100644 --- a/database/build/count_org_test.go +++ b/database/build/count_org_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -67,12 +68,12 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -137,7 +138,7 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountBuildsForOrg("foo", test.filters) + got, err := test.database.CountBuildsForOrg(context.TODO(), "foo", test.filters) if test.failure { if err == nil { diff --git a/database/build/count_repo.go b/database/build/count_repo.go index b49a415e0..e7fcee5b8 100644 --- a/database/build/count_repo.go +++ b/database/build/count_repo.go @@ -5,13 +5,15 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // CountBuildsForRepo gets the count of builds by repo ID from the database. -func (e *engine) CountBuildsForRepo(r *library.Repo, filters map[string]interface{}) (int64, error) { +func (e *engine) CountBuildsForRepo(ctx context.Context, r *library.Repo, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/build/count_repo_test.go b/database/build/count_repo_test.go index 313dcba70..c7f406b32 100644 --- a/database/build/count_repo_test.go +++ b/database/build/count_repo_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -46,12 +47,12 @@ func TestBuild_Engine_CountBuildsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -82,7 +83,7 @@ func TestBuild_Engine_CountBuildsForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountBuildsForRepo(_repo, filters) + got, err := test.database.CountBuildsForRepo(context.TODO(), _repo, filters) if test.failure { if err == nil { diff --git a/database/build/count_status.go b/database/build/count_status.go index af6a9f957..98d4acf5b 100644 --- a/database/build/count_status.go +++ b/database/build/count_status.go @@ -5,11 +5,13 @@ package build import ( + "context" + "github.com/go-vela/types/constants" ) // CountBuildsForStatus gets the count of builds by status from the database. -func (e *engine) CountBuildsForStatus(status string, filters map[string]interface{}) (int64, error) { +func (e *engine) CountBuildsForStatus(ctx context.Context, status string, filters map[string]interface{}) (int64, error) { e.logger.Tracef("getting count of builds for status %s from the database", status) // variable to store query results diff --git a/database/build/count_status_test.go b/database/build/count_status_test.go index 34c7ce525..c35d694e0 100644 --- a/database/build/count_status_test.go +++ b/database/build/count_status_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -39,12 +40,12 @@ func TestBuild_Engine_CountBuildsForStatus(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -75,7 +76,7 @@ func TestBuild_Engine_CountBuildsForStatus(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountBuildsForStatus("running", filters) + got, err := test.database.CountBuildsForStatus(context.TODO(), "running", filters) if test.failure { if err == nil { diff --git a/database/build/count_test.go b/database/build/count_test.go index f63e1430b..c29d3f04f 100644 --- a/database/build/count_test.go +++ b/database/build/count_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -37,12 +38,12 @@ func TestBuild_Engine_CountBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -71,7 +72,7 @@ func TestBuild_Engine_CountBuilds(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountBuilds() + got, err := test.database.CountBuilds(context.TODO()) if test.failure { if err == nil { diff --git a/database/build/create.go b/database/build/create.go index 52c425e9f..ff5d7a91d 100644 --- a/database/build/create.go +++ b/database/build/create.go @@ -6,6 +6,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -13,7 +15,7 @@ import ( ) // CreateBuild creates a new build in the database. -func (e *engine) CreateBuild(b *library.Build) (*library.Build, error) { +func (e *engine) CreateBuild(ctx context.Context, b *library.Build) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("creating build %d in the database", b.GetNumber()) diff --git a/database/build/create_test.go b/database/build/create_test.go index d6051c2dd..c425c5db7 100644 --- a/database/build/create_test.go +++ b/database/build/create_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -56,7 +57,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CreateBuild(_build) + got, err := test.database.CreateBuild(context.TODO(), _build) if test.failure { if err == nil { diff --git a/database/build/delete.go b/database/build/delete.go index 76643eed1..a7048c7e7 100644 --- a/database/build/delete.go +++ b/database/build/delete.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // DeleteBuild deletes an existing build from the database. -func (e *engine) DeleteBuild(b *library.Build) error { +func (e *engine) DeleteBuild(ctx context.Context, b *library.Build) error { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("deleting build %d from the database", b.GetNumber()) diff --git a/database/build/delete_test.go b/database/build/delete_test.go index 252912b23..93d1b5459 100644 --- a/database/build/delete_test.go +++ b/database/build/delete_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -29,7 +30,7 @@ func TestBuild_Engine_DeleteBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(context.TODO(), _build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -55,7 +56,7 @@ func TestBuild_Engine_DeleteBuild(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.DeleteBuild(_build) + err = test.database.DeleteBuild(context.TODO(), _build) if test.failure { if err == nil { diff --git a/database/build/get.go b/database/build/get.go index 236d62cca..8c57d7fe6 100644 --- a/database/build/get.go +++ b/database/build/get.go @@ -5,13 +5,15 @@ package build import ( + "context" + "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(id int64) (*library.Build, error) { +func (e *engine) GetBuild(ctx context.Context, id int64) (*library.Build, error) { e.logger.Tracef("getting build %d from the database", id) // variable to store query results diff --git a/database/build/get_repo.go b/database/build/get_repo.go index 8d93dcb3c..7b37bc2a7 100644 --- a/database/build/get_repo.go +++ b/database/build/get_repo.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // GetBuildForRepo gets a build by repo ID and number from the database. -func (e *engine) GetBuildForRepo(r *library.Repo, number int) (*library.Build, error) { +func (e *engine) GetBuildForRepo(ctx context.Context, r *library.Repo, number int) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "build": number, "org": r.GetOrg(), diff --git a/database/build/get_repo_test.go b/database/build/get_repo_test.go index 92f86bd0c..8a36b55e9 100644 --- a/database/build/get_repo_test.go +++ b/database/build/get_repo_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -43,7 +44,7 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(context.TODO(), _build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -72,7 +73,7 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetBuildForRepo(_repo, 1) + got, err := test.database.GetBuildForRepo(context.TODO(), _repo, 1) if test.failure { if err == nil { diff --git a/database/build/get_test.go b/database/build/get_test.go index 21ea19f94..9646224b7 100644 --- a/database/build/get_test.go +++ b/database/build/get_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -34,7 +35,7 @@ func TestBuild_Engine_GetBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(context.TODO(), _build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -63,7 +64,7 @@ func TestBuild_Engine_GetBuild(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetBuild(1) + got, err := test.database.GetBuild(context.TODO(), 1) if test.failure { if err == nil { diff --git a/database/build/index.go b/database/build/index.go index 77e15e451..51dec6eba 100644 --- a/database/build/index.go +++ b/database/build/index.go @@ -4,6 +4,8 @@ package build +import "context" + const ( // CreateCreatedIndex represents a query to create an // index on the builds table for the created column. @@ -43,7 +45,7 @@ ON builds (status); ) // CreateBuildIndexes creates the indexes for the builds table in the database. -func (e *engine) CreateBuildIndexes() error { +func (e *engine) CreateBuildIndexes(ctx context.Context) error { e.logger.Tracef("creating indexes for builds table in the database") // create the created column index for the builds table diff --git a/database/build/index_test.go b/database/build/index_test.go index bd61ff5d2..35dd25008 100644 --- a/database/build/index_test.go +++ b/database/build/index_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -44,7 +45,7 @@ func TestBuild_Engine_CreateBuildIndexes(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateBuildIndexes() + err := test.database.CreateBuildIndexes(context.TODO()) if test.failure { if err == nil { diff --git a/database/build/interface.go b/database/build/interface.go index 6d05fa48b..d2b8d9f41 100644 --- a/database/build/interface.go +++ b/database/build/interface.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/library" ) @@ -18,46 +20,46 @@ type BuildInterface interface { // https://en.wikipedia.org/wiki/Data_definition_language // CreateBuildIndexes defines a function that creates the indexes for the builds table. - CreateBuildIndexes() error + CreateBuildIndexes(context.Context) error // CreateBuildTable defines a function that creates the builds table. - CreateBuildTable(string) error + CreateBuildTable(context.Context, string) error // Build Data Manipulation Language Functions // // https://en.wikipedia.org/wiki/Data_manipulation_language // CleanBuilds defines a function that sets pending or running builds to error created before a given time. - CleanBuilds(string, int64) (int64, error) + CleanBuilds(context.Context, string, int64) (int64, error) // CountBuilds defines a function that gets the count of all builds. - CountBuilds() (int64, error) + CountBuilds(context.Context) (int64, error) // CountBuildsForDeployment defines a function that gets the count of builds by deployment url. - CountBuildsForDeployment(*library.Deployment, map[string]interface{}) (int64, error) + CountBuildsForDeployment(context.Context, *library.Deployment, map[string]interface{}) (int64, error) // CountBuildsForOrg defines a function that gets the count of builds by org name. - CountBuildsForOrg(string, map[string]interface{}) (int64, error) + CountBuildsForOrg(context.Context, string, map[string]interface{}) (int64, error) // CountBuildsForRepo defines a function that gets the count of builds by repo ID. - CountBuildsForRepo(*library.Repo, map[string]interface{}) (int64, error) + CountBuildsForRepo(context.Context, *library.Repo, map[string]interface{}) (int64, error) // CountBuildsForStatus defines a function that gets the count of builds by status. - CountBuildsForStatus(string, map[string]interface{}) (int64, error) + CountBuildsForStatus(context.Context, string, map[string]interface{}) (int64, error) // CreateBuild defines a function that creates a new build. - CreateBuild(*library.Build) (*library.Build, error) + CreateBuild(context.Context, *library.Build) (*library.Build, error) // DeleteBuild defines a function that deletes an existing build. - DeleteBuild(*library.Build) error + DeleteBuild(context.Context, *library.Build) error // GetBuild defines a function that gets a build by ID. - GetBuild(int64) (*library.Build, error) + GetBuild(context.Context, int64) (*library.Build, error) // GetBuildForRepo defines a function that gets a build by repo ID and number. - GetBuildForRepo(*library.Repo, int) (*library.Build, error) + GetBuildForRepo(context.Context, *library.Repo, int) (*library.Build, error) // LastBuildForRepo defines a function that gets the last build ran by repo ID and branch. - LastBuildForRepo(*library.Repo, string) (*library.Build, error) + LastBuildForRepo(context.Context, *library.Repo, string) (*library.Build, error) // ListBuilds defines a function that gets a list of all builds. - ListBuilds() ([]*library.Build, error) + ListBuilds(context.Context) ([]*library.Build, error) // ListBuildsForDeployment defines a function that gets a list of builds by deployment url. - ListBuildsForDeployment(*library.Deployment, map[string]interface{}, int, int) ([]*library.Build, int64, error) + ListBuildsForDeployment(context.Context, *library.Deployment, map[string]interface{}, int, int) ([]*library.Build, int64, error) // ListBuildsForOrg defines a function that gets a list of builds by org name. - ListBuildsForOrg(string, map[string]interface{}, int, int) ([]*library.Build, int64, error) + ListBuildsForOrg(context.Context, string, map[string]interface{}, int, int) ([]*library.Build, int64, error) // ListBuildsForRepo defines a function that gets a list of builds by repo ID. - ListBuildsForRepo(*library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) + ListBuildsForRepo(context.Context, *library.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) // ListPendingAndRunningBuilds defines a function that gets a list of pending and running builds. - ListPendingAndRunningBuilds(string) ([]*library.BuildQueue, error) + ListPendingAndRunningBuilds(context.Context, string) ([]*library.BuildQueue, error) // UpdateBuild defines a function that updates an existing build. - UpdateBuild(*library.Build) (*library.Build, error) + UpdateBuild(context.Context, *library.Build) (*library.Build, error) } diff --git a/database/build/last_repo.go b/database/build/last_repo.go index ed0adebbf..81861c8b4 100644 --- a/database/build/last_repo.go +++ b/database/build/last_repo.go @@ -5,6 +5,7 @@ package build import ( + "context" "errors" "github.com/go-vela/types/constants" @@ -16,7 +17,7 @@ import ( ) // LastBuildForRepo gets the last build by repo ID and branch from the database. -func (e *engine) LastBuildForRepo(r *library.Repo, branch string) (*library.Build, error) { +func (e *engine) LastBuildForRepo(ctx context.Context, r *library.Repo, branch string) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/build/last_repo_test.go b/database/build/last_repo_test.go index 853c21711..07e5549b2 100644 --- a/database/build/last_repo_test.go +++ b/database/build/last_repo_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -44,7 +45,7 @@ func TestBuild_Engine_LastBuildForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(context.TODO(), _build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -73,7 +74,7 @@ func TestBuild_Engine_LastBuildForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.LastBuildForRepo(_repo, "master") + got, err := test.database.LastBuildForRepo(context.TODO(), _repo, "master") if test.failure { if err == nil { diff --git a/database/build/list.go b/database/build/list.go index 1139cf490..9809af5d9 100644 --- a/database/build/list.go +++ b/database/build/list.go @@ -5,13 +5,15 @@ package build import ( + "context" + "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() ([]*library.Build, error) { +func (e *engine) ListBuilds(ctx context.Context) ([]*library.Build, error) { e.logger.Trace("listing all builds from the database") // variables to store query results and return value @@ -20,7 +22,7 @@ func (e *engine) ListBuilds() ([]*library.Build, error) { builds := []*library.Build{} // count the results - count, err := e.CountBuilds() + count, err := e.CountBuilds(ctx) if err != nil { return nil, err } diff --git a/database/build/list_deployment.go b/database/build/list_deployment.go index ff397f2ae..0d931fae7 100644 --- a/database/build/list_deployment.go +++ b/database/build/list_deployment.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // ListBuildsForDeployment gets a list of builds by deployment url from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListBuildsForDeployment(d *library.Deployment, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { +func (e *engine) ListBuildsForDeployment(ctx context.Context, d *library.Deployment, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { e.logger.WithFields(logrus.Fields{ "deployment": d.GetURL(), }).Tracef("listing builds for deployment %s from the database", d.GetURL()) @@ -25,7 +27,7 @@ func (e *engine) ListBuildsForDeployment(d *library.Deployment, filters map[stri builds := []*library.Build{} // count the results - count, err := e.CountBuildsForDeployment(d, filters) + count, err := e.CountBuildsForDeployment(context.TODO(), d, filters) if err != nil { return builds, 0, err } diff --git a/database/build/list_deployment_test.go b/database/build/list_deployment_test.go index 53b984bba..57a54522d 100644 --- a/database/build/list_deployment_test.go +++ b/database/build/list_deployment_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -54,12 +55,12 @@ func TestBuild_Engine_ListBuildsForDeployment(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -90,7 +91,7 @@ func TestBuild_Engine_ListBuildsForDeployment(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListBuildsForDeployment(_deployment, filters, 1, 10) + got, _, err := test.database.ListBuildsForDeployment(context.TODO(), _deployment, filters, 1, 10) if test.failure { if err == nil { diff --git a/database/build/list_org.go b/database/build/list_org.go index 8f4e62e58..254c0c9e9 100644 --- a/database/build/list_org.go +++ b/database/build/list_org.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // 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(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) ([]*library.Build, int64, error) { e.logger.WithFields(logrus.Fields{ "org": org, }).Tracef("listing builds for org %s from the database", org) @@ -25,7 +27,7 @@ func (e *engine) ListBuildsForOrg(org string, filters map[string]interface{}, pa builds := []*library.Build{} // count the results - count, err := e.CountBuildsForOrg(org, filters) + count, err := e.CountBuildsForOrg(ctx, org, filters) if err != nil { return builds, 0, err } diff --git a/database/build/list_org_test.go b/database/build/list_org_test.go index 4e2ac91aa..95fc9a456 100644 --- a/database/build/list_org_test.go +++ b/database/build/list_org_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -94,12 +95,12 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -182,7 +183,7 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListBuildsForOrg("foo", test.filters, 1, 10) + got, _, err := test.database.ListBuildsForOrg(context.TODO(), "foo", test.filters, 1, 10) if test.failure { if err == nil { diff --git a/database/build/list_pending_running.go b/database/build/list_pending_running.go index bd2a219b5..dbee3e704 100644 --- a/database/build/list_pending_running.go +++ b/database/build/list_pending_running.go @@ -5,13 +5,15 @@ package build import ( + "context" + "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(after string) ([]*library.BuildQueue, error) { +func (e *engine) ListPendingAndRunningBuilds(ctx context.Context, after string) ([]*library.BuildQueue, error) { e.logger.Trace("listing all pending and running builds from the database") // variables to store query results and return value diff --git a/database/build/list_pending_running_test.go b/database/build/list_pending_running_test.go index 3b3aa4d3e..4ee71e1c7 100644 --- a/database/build/list_pending_running_test.go +++ b/database/build/list_pending_running_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -65,12 +66,12 @@ func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -109,7 +110,7 @@ func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListPendingAndRunningBuilds("0") + got, err := test.database.ListPendingAndRunningBuilds(context.TODO(), "0") if test.failure { if err == nil { diff --git a/database/build/list_repo.go b/database/build/list_repo.go index 83ebd4adb..8ee78e35c 100644 --- a/database/build/list_repo.go +++ b/database/build/list_repo.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // 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(r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { +func (e *engine) ListBuildsForRepo(ctx context.Context, r *library.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -26,7 +28,7 @@ func (e *engine) ListBuildsForRepo(r *library.Repo, filters map[string]interface builds := []*library.Build{} // count the results - count, err := e.CountBuildsForRepo(r, filters) + count, err := e.CountBuildsForRepo(ctx, r, filters) if err != nil { return builds, 0, err } diff --git a/database/build/list_repo_test.go b/database/build/list_repo_test.go index f2ccbbe9e..f16ed714d 100644 --- a/database/build/list_repo_test.go +++ b/database/build/list_repo_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" "time" @@ -59,12 +60,12 @@ func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -95,7 +96,7 @@ func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListBuildsForRepo(_repo, filters, time.Now().UTC().Unix(), 0, 1, 10) + got, _, err := test.database.ListBuildsForRepo(context.TODO(), _repo, filters, time.Now().UTC().Unix(), 0, 1, 10) if test.failure { if err == nil { diff --git a/database/build/list_test.go b/database/build/list_test.go index 958025b09..69d826755 100644 --- a/database/build/list_test.go +++ b/database/build/list_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -47,12 +48,12 @@ func TestBuild_Engine_ListBuilds(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_buildOne) + _, err := _sqlite.CreateBuild(context.TODO(), _buildOne) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } - _, err = _sqlite.CreateBuild(_buildTwo) + _, err = _sqlite.CreateBuild(context.TODO(), _buildTwo) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -81,7 +82,7 @@ func TestBuild_Engine_ListBuilds(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListBuilds() + got, err := test.database.ListBuilds(context.TODO()) if test.failure { if err == nil { diff --git a/database/build/opts.go b/database/build/opts.go index d5a5d4137..69c912435 100644 --- a/database/build/opts.go +++ b/database/build/opts.go @@ -5,6 +5,8 @@ package build import ( + "context" + "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -42,3 +44,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine for Builds. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/build/table.go b/database/build/table.go index faf76746f..91499ef4a 100644 --- a/database/build/table.go +++ b/database/build/table.go @@ -4,7 +4,11 @@ package build -import "github.com/go-vela/types/constants" +import ( + "context" + + "github.com/go-vela/types/constants" +) const ( // CreatePostgresTable represents a query to create the Postgres builds table. @@ -91,7 +95,7 @@ builds ( ) // CreateBuildTable creates the builds table in the database. -func (e *engine) CreateBuildTable(driver string) error { +func (e *engine) CreateBuildTable(ctx context.Context, driver string) error { e.logger.Tracef("creating builds table in the database") // handle the driver provided to create the table diff --git a/database/build/table_test.go b/database/build/table_test.go index 394a1287e..a08997fce 100644 --- a/database/build/table_test.go +++ b/database/build/table_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestBuild_Engine_CreateBuildTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateBuildTable(test.name) + err := test.database.CreateBuildTable(context.TODO(), test.name) if test.failure { if err == nil { diff --git a/database/build/update.go b/database/build/update.go index ad5c6087f..bdd506187 100644 --- a/database/build/update.go +++ b/database/build/update.go @@ -6,6 +6,8 @@ package build import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -13,7 +15,7 @@ import ( ) // UpdateBuild updates an existing build in the database. -func (e *engine) UpdateBuild(b *library.Build) (*library.Build, error) { +func (e *engine) UpdateBuild(ctx context.Context, b *library.Build) (*library.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("updating build %d in the database", b.GetNumber()) diff --git a/database/build/update_test.go b/database/build/update_test.go index 21b2d1d5a..7e5441145 100644 --- a/database/build/update_test.go +++ b/database/build/update_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -32,7 +33,7 @@ WHERE "id" = $31`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateBuild(_build) + _, err := _sqlite.CreateBuild(context.TODO(), _build) if err != nil { t.Errorf("unable to create test build for sqlite: %v", err) } @@ -58,7 +59,7 @@ WHERE "id" = $31`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.UpdateBuild(_build) + got, err := test.database.UpdateBuild(context.TODO(), _build) if test.failure { if err == nil { diff --git a/database/integration_test.go b/database/integration_test.go index 9741c764f..c99c3587a 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -187,7 +187,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // create the builds for _, build := range resources.Builds { - _, err := db.CreateBuild(build) + _, err := db.CreateBuild(context.TODO(), build) if err != nil { t.Errorf("unable to create build %d: %v", build.GetID(), err) } @@ -195,7 +195,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CreateBuild"] = true // count the builds - count, err := db.CountBuilds() + count, err := db.CountBuilds(context.TODO()) if err != nil { t.Errorf("unable to count builds: %v", err) } @@ -205,7 +205,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CountBuilds"] = true // count the builds for a deployment - count, err = db.CountBuildsForDeployment(resources.Deployments[0], nil) + count, err = db.CountBuildsForDeployment(context.TODO(), resources.Deployments[0], nil) if err != nil { t.Errorf("unable to count builds for deployment %d: %v", resources.Deployments[0].GetID(), err) } @@ -215,7 +215,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CountBuildsForDeployment"] = true // count the builds for an org - count, err = db.CountBuildsForOrg(resources.Repos[0].GetOrg(), nil) + count, err = db.CountBuildsForOrg(context.TODO(), resources.Repos[0].GetOrg(), nil) if err != nil { t.Errorf("unable to count builds for org %s: %v", resources.Repos[0].GetOrg(), err) } @@ -225,7 +225,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CountBuildsForOrg"] = true // count the builds for a repo - count, err = db.CountBuildsForRepo(resources.Repos[0], nil) + count, err = db.CountBuildsForRepo(context.TODO(), resources.Repos[0], nil) if err != nil { t.Errorf("unable to count builds for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -235,7 +235,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CountBuildsForRepo"] = true // count the builds for a status - count, err = db.CountBuildsForStatus("running", nil) + count, err = db.CountBuildsForStatus(context.TODO(), "running", nil) if err != nil { t.Errorf("unable to count builds for status %s: %v", "running", err) } @@ -245,7 +245,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["CountBuildsForStatus"] = true // list the builds - list, err := db.ListBuilds() + list, err := db.ListBuilds(context.TODO()) if err != nil { t.Errorf("unable to list builds: %v", err) } @@ -255,7 +255,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["ListBuilds"] = true // list the builds for a deployment - list, count, err = db.ListBuildsForDeployment(resources.Deployments[0], nil, 1, 10) + list, count, err = db.ListBuildsForDeployment(context.TODO(), resources.Deployments[0], nil, 1, 10) if err != nil { t.Errorf("unable to list builds for deployment %d: %v", resources.Deployments[0].GetID(), err) } @@ -268,7 +268,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["ListBuildsForDeployment"] = true // list the builds for an org - list, count, err = db.ListBuildsForOrg(resources.Repos[0].GetOrg(), nil, 1, 10) + list, count, err = db.ListBuildsForOrg(context.TODO(), resources.Repos[0].GetOrg(), nil, 1, 10) if err != nil { t.Errorf("unable to list builds for org %s: %v", resources.Repos[0].GetOrg(), err) } @@ -281,7 +281,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["ListBuildsForOrg"] = true // list the builds for a repo - list, count, err = db.ListBuildsForRepo(resources.Repos[0], nil, time.Now().UTC().Unix(), 0, 1, 10) + list, count, err = db.ListBuildsForRepo(context.TODO(), resources.Repos[0], nil, time.Now().UTC().Unix(), 0, 1, 10) if err != nil { t.Errorf("unable to list builds for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -294,7 +294,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["ListBuildsForRepo"] = true // list the pending and running builds - queueList, err := db.ListPendingAndRunningBuilds("0") + queueList, err := db.ListPendingAndRunningBuilds(context.TODO(), "0") if err != nil { t.Errorf("unable to list pending and running builds: %v", err) } @@ -304,7 +304,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["ListPendingAndRunningBuilds"] = true // lookup the last build by repo - got, err := db.LastBuildForRepo(resources.Repos[0], "main") + got, err := db.LastBuildForRepo(context.TODO(), resources.Repos[0], "main") if err != nil { t.Errorf("unable to get last build for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -316,7 +316,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] - got, err = db.GetBuildForRepo(repo, build.GetNumber()) + 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) } @@ -327,7 +327,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods["GetBuildForRepo"] = true // clean the builds - count, err = db.CleanBuilds("integration testing", 1563474090) + count, err = db.CleanBuilds(context.TODO(), "integration testing", 1563474090) if err != nil { t.Errorf("unable to clean builds: %v", err) } @@ -339,13 +339,13 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // update the builds for _, build := range resources.Builds { build.SetStatus("success") - _, err = db.UpdateBuild(build) + _, err = db.UpdateBuild(context.TODO(), build) if err != nil { t.Errorf("unable to update build %d: %v", build.GetID(), err) } // lookup the build by ID - got, err = db.GetBuild(build.GetID()) + got, err = db.GetBuild(context.TODO(), build.GetID()) if err != nil { t.Errorf("unable to get build %d by ID: %v", build.GetID(), err) } @@ -358,7 +358,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // delete the builds for _, build := range resources.Builds { - err = db.DeleteBuild(build) + err = db.DeleteBuild(context.TODO(), build) if err != nil { t.Errorf("unable to delete build %d: %v", build.GetID(), err) } diff --git a/database/resource.go b/database/resource.go index f9643b229..ce3dd853a 100644 --- a/database/resource.go +++ b/database/resource.go @@ -25,6 +25,7 @@ func (e *engine) NewResources(ctx context.Context) error { // create the database agnostic engine for builds e.BuildInterface, err = build.New( + build.WithContext(e.ctx), build.WithClient(e.client), build.WithLogger(e.logger), build.WithSkipCreation(e.config.SkipCreation), diff --git a/router/middleware/build/build.go b/router/middleware/build/build.go index 6016adf3c..3b0b4f0d8 100644 --- a/router/middleware/build/build.go +++ b/router/middleware/build/build.go @@ -30,6 +30,7 @@ func Establish() gin.HandlerFunc { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() if r == nil { retErr := fmt.Errorf("repo %s/%s not found", util.PathParameter(c, "org"), util.PathParameter(c, "repo")) @@ -64,7 +65,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading build %s/%d", r.GetFullName(), number) - b, err := database.FromContext(c).GetBuildForRepo(r, number) + b, err := database.FromContext(c).GetBuildForRepo(ctx, r, number) if err != nil { retErr := fmt.Errorf("unable to read build %s/%d: %w", r.GetFullName(), number, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index d0e0733a5..e4e68193a 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "net/http" "net/http/httptest" "reflect" @@ -89,13 +90,13 @@ func TestBuild_Establish(t *testing.T) { } defer func() { - db.DeleteBuild(want) + db.DeleteBuild(context.TODO(), want) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(want) + _, _ = db.CreateBuild(context.TODO(), want) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index a5af1cbbe..b51017c91 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -5,6 +5,7 @@ package perm import ( + _context "context" "fmt" "net/http" "net/http/httptest" @@ -441,14 +442,16 @@ func TestPerm_MustBuildAccess(t *testing.T) { t.Errorf("unable to create test database engine: %v", err) } + ctx := _context.TODO() + defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -524,6 +527,8 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -531,14 +536,14 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.DeleteUser(u) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -610,6 +615,8 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -617,13 +624,13 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -694,6 +701,8 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -701,13 +710,13 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/repo/foo/bar/baz", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -775,6 +784,8 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -782,13 +793,13 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/org/foo/*/baz", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -856,6 +867,8 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -863,13 +876,13 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/shared/foo/*/*", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -1819,6 +1832,8 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { resp := httptest.NewRecorder() context, engine := gin.CreateTestContext(resp) + ctx := _context.TODO() + // setup database db, err := database.NewTest() if err != nil { @@ -1826,12 +1841,12 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(ctx, b) db.DeleteRepo(r) db.Close() }() - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(ctx, b) _, _ = db.CreateRepo(r) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index 20c84c868..b2234659c 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -5,6 +5,7 @@ package service import ( + "context" "net/http" "net/http/httptest" "reflect" @@ -78,14 +79,14 @@ func TestService_Establish(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.DeleteService(want) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) _ = db.CreateService(want) // setup context @@ -220,13 +221,13 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) @@ -276,13 +277,13 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) @@ -332,13 +333,13 @@ func TestService_Establish_NoService(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index 85aa8c246..795463a7a 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -5,6 +5,7 @@ package step import ( + "context" "net/http" "net/http/httptest" "reflect" @@ -80,14 +81,14 @@ func TestStep_Establish(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.DeleteStep(want) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) _ = db.CreateStep(want) // setup context @@ -222,13 +223,13 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) @@ -278,13 +279,13 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) @@ -334,13 +335,13 @@ func TestStep_Establish_NoStep(t *testing.T) { } defer func() { - db.DeleteBuild(b) + db.DeleteBuild(context.TODO(), b) db.DeleteRepo(r) db.Close() }() _, _ = db.CreateRepo(r) - _, _ = db.CreateBuild(b) + _, _ = db.CreateBuild(context.TODO(), b) // setup context gin.SetMode(gin.TestMode) From 635c18bce1829390bff201a77ccbac33944306fb Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:33:23 -0600 Subject: [PATCH 286/298] refactor(db): return schedule on create and update (#915) * refactor(db): return schedule on create and update * fix integration tests --------- Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- api/schedule/create.go | 10 ++-------- api/schedule/update.go | 5 +---- cmd/vela-server/schedule.go | 2 +- database/integration_test.go | 9 ++------- database/schedule/count_active_test.go | 4 ++-- database/schedule/count_repo_test.go | 4 ++-- database/schedule/count_test.go | 4 ++-- database/schedule/create.go | 12 ++++++------ database/schedule/create_test.go | 7 ++++++- database/schedule/delete_test.go | 2 +- database/schedule/get_repo_test.go | 2 +- database/schedule/get_test.go | 2 +- database/schedule/interface.go | 5 +++-- database/schedule/list_active_test.go | 4 ++-- database/schedule/list_repo_test.go | 4 ++-- database/schedule/list_test.go | 4 ++-- database/schedule/update.go | 7 ++++--- database/schedule/update_test.go | 18 ++++++++++++++---- 18 files changed, 54 insertions(+), 51 deletions(-) diff --git a/api/schedule/create.go b/api/schedule/create.go index 3c5c4790a..c50f11744 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.go @@ -171,7 +171,7 @@ func CreateSchedule(c *gin.Context) { dbSchedule.SetActive(true) // send API call to update the schedule - err = database.FromContext(c).UpdateSchedule(ctx, dbSchedule, true) + s, err = database.FromContext(c).UpdateSchedule(ctx, dbSchedule, true) if err != nil { retErr := fmt.Errorf("unable to set schedule %s to active: %w", dbSchedule.GetName(), err) @@ -179,12 +179,9 @@ func CreateSchedule(c *gin.Context) { return } - - // send API call to capture the updated schedule - s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, dbSchedule.GetName()) } else { // send API call to create the schedule - err = database.FromContext(c).CreateSchedule(ctx, s) + s, err = database.FromContext(c).CreateSchedule(ctx, s) if err != nil { retErr := fmt.Errorf("unable to create new schedule %s: %w", r.GetName(), err) @@ -192,9 +189,6 @@ func CreateSchedule(c *gin.Context) { return } - - // send API call to capture the created schedule - s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, input.GetName()) } c.JSON(http.StatusCreated, s) diff --git a/api/schedule/update.go b/api/schedule/update.go index a58990f33..578639c8b 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -129,7 +129,7 @@ func UpdateSchedule(c *gin.Context) { s.SetUpdatedBy(u.GetName()) // update the schedule within the database - err = database.FromContext(c).UpdateSchedule(ctx, s, true) + s, err = database.FromContext(c).UpdateSchedule(ctx, s, true) if err != nil { retErr := fmt.Errorf("unable to update scheduled %s: %w", scheduleName, err) @@ -138,8 +138,5 @@ func UpdateSchedule(c *gin.Context) { return } - // capture the updated scheduled - s, _ = database.FromContext(c).GetScheduleForRepo(ctx, r, scheduleName) - c.JSON(http.StatusOK, s) } diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index cd1a19664..2144af965 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -116,7 +116,7 @@ func processSchedules(ctx context.Context, start time.Time, compiler compiler.En schedule.SetScheduledAt(time.Now().UTC().Unix()) // send API call to update schedule for ensuring scheduled_at field is set - err = database.UpdateSchedule(ctx, schedule, false) + _, err = database.UpdateSchedule(ctx, schedule, false) if err != nil { logrus.WithError(err).Warnf("%s %s", scheduleErr, schedule.GetName()) diff --git a/database/integration_test.go b/database/integration_test.go index c99c3587a..5d7fbe0cb 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -928,7 +928,7 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { // create the schedules for _, schedule := range resources.Schedules { - err := db.CreateSchedule(ctx, schedule) + _, err := db.CreateSchedule(ctx, schedule) if err != nil { t.Errorf("unable to create schedule %d: %v", schedule.GetID(), err) } @@ -1004,16 +1004,11 @@ func testSchedules(t *testing.T, db Interface, resources *Resources) { // update the schedules for _, schedule := range resources.Schedules { schedule.SetUpdatedAt(time.Now().UTC().Unix()) - err = db.UpdateSchedule(ctx, schedule, true) + got, err := db.UpdateSchedule(ctx, schedule, true) if err != nil { t.Errorf("unable to update schedule %d: %v", schedule.GetID(), err) } - // lookup the schedule by ID - got, err := db.GetSchedule(ctx, schedule.GetID()) - if err != nil { - t.Errorf("unable to get schedule %d by ID: %v", schedule.GetID(), err) - } if !reflect.DeepEqual(got, schedule) { t.Errorf("GetSchedule() is %v, want %v", got, schedule) } diff --git a/database/schedule/count_active_test.go b/database/schedule/count_active_test.go index 866e11425..5d555ea8c 100644 --- a/database/schedule/count_active_test.go +++ b/database/schedule/count_active_test.go @@ -47,12 +47,12 @@ func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/count_repo_test.go b/database/schedule/count_repo_test.go index 7bfbbe9bd..d2429c595 100644 --- a/database/schedule/count_repo_test.go +++ b/database/schedule/count_repo_test.go @@ -51,12 +51,12 @@ func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/count_test.go b/database/schedule/count_test.go index d8523b784..91537d919 100644 --- a/database/schedule/count_test.go +++ b/database/schedule/count_test.go @@ -45,12 +45,12 @@ func TestSchedule_Engine_CountSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/create.go b/database/schedule/create.go index f04b95508..8a5907263 100644 --- a/database/schedule/create.go +++ b/database/schedule/create.go @@ -7,6 +7,7 @@ package schedule import ( "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +15,7 @@ import ( ) // CreateSchedule creates a new schedule in the database. -func (e *engine) CreateSchedule(ctx context.Context, s *library.Schedule) error { +func (e *engine) CreateSchedule(ctx context.Context, s *library.Schedule) (*library.Schedule, error) { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("creating schedule %s in the database", s.GetName()) @@ -25,12 +26,11 @@ func (e *engine) CreateSchedule(ctx context.Context, s *library.Schedule) error // validate the necessary fields are populated err := schedule.Validate() if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TableSchedule). - Create(schedule). - Error + result := e.client.Table(constants.TableSchedule).Create(schedule) + + return schedule.ToLibrary(), result.Error } diff --git a/database/schedule/create_test.go b/database/schedule/create_test.go index 426115915..4a987b577 100644 --- a/database/schedule/create_test.go +++ b/database/schedule/create_test.go @@ -6,6 +6,7 @@ package schedule import ( "context" + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -59,7 +60,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateSchedule(context.TODO(), _schedule) + got, err := test.database.CreateSchedule(context.TODO(), _schedule) if test.failure { if err == nil { @@ -72,6 +73,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id"`). if err != nil { t.Errorf("CreateSchedule for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _schedule) { + t.Errorf("CreateSchedule for %s returned %s, want %s", test.name, got, _schedule) + } }) } } diff --git a/database/schedule/delete_test.go b/database/schedule/delete_test.go index 0e958de52..e302da6b9 100644 --- a/database/schedule/delete_test.go +++ b/database/schedule/delete_test.go @@ -33,7 +33,7 @@ func TestSchedule_Engine_DeleteSchedule(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _schedule) + _, err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/get_repo_test.go b/database/schedule/get_repo_test.go index 56b010e97..b29072ec7 100644 --- a/database/schedule/get_repo_test.go +++ b/database/schedule/get_repo_test.go @@ -44,7 +44,7 @@ func TestSchedule_Engine_GetScheduleForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _schedule) + _, err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/get_test.go b/database/schedule/get_test.go index 6fc0ed11e..b5175d8b0 100644 --- a/database/schedule/get_test.go +++ b/database/schedule/get_test.go @@ -38,7 +38,7 @@ func TestSchedule_Engine_GetSchedule(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _schedule) + _, err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/interface.go b/database/schedule/interface.go index 6f7309d16..402499ab1 100644 --- a/database/schedule/interface.go +++ b/database/schedule/interface.go @@ -6,6 +6,7 @@ package schedule import ( "context" + "github.com/go-vela/types/library" ) @@ -32,7 +33,7 @@ type ScheduleInterface interface { // CountSchedulesForRepo defines a function that gets the count of schedules by repo ID. CountSchedulesForRepo(context.Context, *library.Repo) (int64, error) // CreateSchedule defines a function that creates a new schedule. - CreateSchedule(context.Context, *library.Schedule) error + CreateSchedule(context.Context, *library.Schedule) (*library.Schedule, error) // DeleteSchedule defines a function that deletes an existing schedule. DeleteSchedule(context.Context, *library.Schedule) error // GetSchedule defines a function that gets a schedule by ID. @@ -46,5 +47,5 @@ type ScheduleInterface interface { // ListSchedulesForRepo defines a function that gets a list of schedules by repo ID. ListSchedulesForRepo(context.Context, *library.Repo, int, int) ([]*library.Schedule, int64, error) // UpdateSchedule defines a function that updates an existing schedule. - UpdateSchedule(context.Context, *library.Schedule, bool) error + UpdateSchedule(context.Context, *library.Schedule, bool) (*library.Schedule, error) } diff --git a/database/schedule/list_active_test.go b/database/schedule/list_active_test.go index 35591a4ad..90ae96cfe 100644 --- a/database/schedule/list_active_test.go +++ b/database/schedule/list_active_test.go @@ -56,12 +56,12 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/list_repo_test.go b/database/schedule/list_repo_test.go index 425e5dddb..2536f73be 100644 --- a/database/schedule/list_repo_test.go +++ b/database/schedule/list_repo_test.go @@ -60,12 +60,12 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/list_test.go b/database/schedule/list_test.go index cdb13f756..6dd64af6c 100644 --- a/database/schedule/list_test.go +++ b/database/schedule/list_test.go @@ -55,12 +55,12 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) + _, err := _sqlite.CreateSchedule(context.TODO(), _scheduleOne) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } - err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) + _, err = _sqlite.CreateSchedule(context.TODO(), _scheduleTwo) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } diff --git a/database/schedule/update.go b/database/schedule/update.go index 934b50c59..23ab855ba 100644 --- a/database/schedule/update.go +++ b/database/schedule/update.go @@ -6,6 +6,7 @@ package schedule import ( "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -13,7 +14,7 @@ import ( ) // UpdateSchedule updates an existing schedule in the database. -func (e *engine) UpdateSchedule(ctx context.Context, s *library.Schedule, fields bool) error { +func (e *engine) UpdateSchedule(ctx context.Context, s *library.Schedule, fields bool) (*library.Schedule, error) { e.logger.WithFields(logrus.Fields{ "schedule": s.GetName(), }).Tracef("updating schedule %s in the database", s.GetName()) @@ -24,7 +25,7 @@ func (e *engine) UpdateSchedule(ctx context.Context, s *library.Schedule, fields // validate the necessary fields are populated err := schedule.Validate() if err != nil { - return err + return nil, err } // If "fields" is true, update entire record; otherwise, just update scheduled_at (part of processSchedule) @@ -37,5 +38,5 @@ func (e *engine) UpdateSchedule(ctx context.Context, s *library.Schedule, fields err = e.client.Table(constants.TableSchedule).Model(schedule).UpdateColumn("scheduled_at", s.GetScheduledAt()).Error } - return err + return schedule.ToLibrary(), err } diff --git a/database/schedule/update_test.go b/database/schedule/update_test.go index 345c7b2db..c13e44ae8 100644 --- a/database/schedule/update_test.go +++ b/database/schedule/update_test.go @@ -6,6 +6,7 @@ package schedule import ( "context" + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ WHERE "id" = $10`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _schedule) + _, err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -67,7 +68,8 @@ WHERE "id" = $10`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSchedule(context.TODO(), _schedule, true) + got, err := test.database.UpdateSchedule(context.TODO(), _schedule, true) + _schedule.SetUpdatedAt(got.GetUpdatedAt()) if test.failure { if err == nil { @@ -80,6 +82,10 @@ WHERE "id" = $10`). if err != nil { t.Errorf("UpdateSchedule for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _schedule) { + t.Errorf("UpdateSchedule for %s returned %s, want %s", test.name, got, _schedule) + } }) } } @@ -113,7 +119,7 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSchedule(context.TODO(), _schedule) + _, err := _sqlite.CreateSchedule(context.TODO(), _schedule) if err != nil { t.Errorf("unable to create test schedule for sqlite: %v", err) } @@ -139,7 +145,7 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSchedule(context.TODO(), _schedule, false) + got, err := test.database.UpdateSchedule(context.TODO(), _schedule, false) if test.failure { if err == nil { @@ -152,6 +158,10 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { if err != nil { t.Errorf("UpdateSchedule for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _schedule) { + t.Errorf("CreateSchedule for %s returned %s, want %s", test.name, got, _schedule) + } }) } } From 7dc577fff37eed85d962a361b3273973888e9930 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 16 Aug 2023 08:17:30 -0600 Subject: [PATCH 287/298] refactor(db): return secret on created / updated (#928) --- api/admin/secret.go | 4 +- api/secret/create.go | 4 +- api/secret/update.go | 5 +- api/webhook/post.go | 2 +- database/integration_test.go | 9 +- database/secret/count_org_test.go | 4 +- database/secret/count_repo_test.go | 4 +- database/secret/count_team_test.go | 8 +- database/secret/count_test.go | 4 +- database/secret/create.go | 32 +++++-- database/secret/create_test.go | 7 +- database/secret/delete_test.go | 6 +- database/secret/get_org_test.go | 2 +- database/secret/get_repo_test.go | 2 +- database/secret/get_team_test.go | 2 +- database/secret/get_test.go | 2 +- database/secret/interface.go | 4 +- database/secret/list_org_test.go | 4 +- database/secret/list_repo_test.go | 4 +- database/secret/list_team_test.go | 8 +- database/secret/list_test.go | 4 +- database/secret/update.go | 29 +++++-- database/secret/update_test.go | 14 ++- secret/native/count_test.go | 2 +- secret/native/create.go | 4 +- secret/native/create_test.go | 14 +-- secret/native/delete_test.go | 2 +- secret/native/get_test.go | 2 +- secret/native/list_test.go | 4 +- secret/native/update.go | 6 +- secret/native/update_test.go | 8 +- secret/service.go | 4 +- secret/vault/create.go | 20 ++--- secret/vault/create_test.go | 72 +++++++++++----- secret/vault/update.go | 20 ++--- secret/vault/update_test.go | 133 +++++++++++++++-------------- 36 files changed, 253 insertions(+), 202 deletions(-) diff --git a/api/admin/secret.go b/api/admin/secret.go index d6df890d3..c9e1d8e73 100644 --- a/api/admin/secret.go +++ b/api/admin/secret.go @@ -66,7 +66,7 @@ func UpdateSecret(c *gin.Context) { } // send API call to update the secret - err = database.FromContext(c).UpdateSecret(input) + s, err := database.FromContext(c).UpdateSecret(input) if err != nil { retErr := fmt.Errorf("unable to update secret %d: %w", input.GetID(), err) @@ -75,5 +75,5 @@ func UpdateSecret(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, s) } diff --git a/api/secret/create.go b/api/secret/create.go index 3ba5061f9..82a1cac5a 100644 --- a/api/secret/create.go +++ b/api/secret/create.go @@ -229,7 +229,7 @@ func CreateSecret(c *gin.Context) { } // send API call to create the secret - err = secret.FromContext(c, e).Create(t, o, n, input) + s, err := secret.FromContext(c, e).Create(t, o, n, input) if err != nil { retErr := fmt.Errorf("unable to create secret %s for %s service: %w", entry, e, err) @@ -238,7 +238,5 @@ func CreateSecret(c *gin.Context) { return } - s, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) - c.JSON(http.StatusOK, s.Sanitize()) } diff --git a/api/secret/update.go b/api/secret/update.go index f71889701..1feaae4c3 100644 --- a/api/secret/update.go +++ b/api/secret/update.go @@ -161,7 +161,7 @@ func UpdateSecret(c *gin.Context) { } // send API call to update the secret - err = secret.FromContext(c, e).Update(t, o, n, input) + secret, err := secret.FromContext(c, e).Update(t, o, n, input) if err != nil { retErr := fmt.Errorf("unable to update secret %s for %s service: %w", entry, e, err) @@ -170,8 +170,5 @@ func UpdateSecret(c *gin.Context) { return } - // send API call to capture the updated secret - secret, _ := secret.FromContext(c, e).Get(t, o, n, input.GetName()) - c.JSON(http.StatusOK, secret.Sanitize()) } diff --git a/api/webhook/post.go b/api/webhook/post.go index 1d6f4edd8..f25fd872b 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -849,7 +849,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types secret.SetOrg(r.GetOrg()) secret.SetRepo(r.GetName()) - err = database.FromContext(c).UpdateSecret(secret) + _, err = database.FromContext(c).UpdateSecret(secret) if err != nil { return nil, fmt.Errorf("unable to update secret for repo %s/%s: %w", prevOrg, prevRepo, err) } diff --git a/database/integration_test.go b/database/integration_test.go index 5d7fbe0cb..0f1e9808d 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -1053,7 +1053,7 @@ func testSecrets(t *testing.T, db Interface, resources *Resources) { // create the secrets for _, secret := range resources.Secrets { - err := db.CreateSecret(secret) + _, err := db.CreateSecret(secret) if err != nil { t.Errorf("unable to create secret %d: %v", secret.GetID(), err) } @@ -1226,16 +1226,11 @@ func testSecrets(t *testing.T, db Interface, resources *Resources) { // update the secrets for _, secret := range resources.Secrets { secret.SetUpdatedAt(time.Now().UTC().Unix()) - err = db.UpdateSecret(secret) + got, err := db.UpdateSecret(secret) if err != nil { t.Errorf("unable to update secret %d: %v", secret.GetID(), err) } - // lookup the secret by ID - got, err := db.GetSecret(secret.GetID()) - if err != nil { - t.Errorf("unable to get secret %d by ID: %v", secret.GetID(), err) - } if !reflect.DeepEqual(got, secret) { t.Errorf("GetSecret() is %v, want %v", got, secret) } diff --git a/database/secret/count_org_test.go b/database/secret/count_org_test.go index 45e109157..6ce684c5e 100644 --- a/database/secret/count_org_test.go +++ b/database/secret/count_org_test.go @@ -51,12 +51,12 @@ func TestSecret_Engine_CountSecretsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/count_repo_test.go b/database/secret/count_repo_test.go index be2dc7a9c..8db30f4c5 100644 --- a/database/secret/count_repo_test.go +++ b/database/secret/count_repo_test.go @@ -62,12 +62,12 @@ func TestSecret_Engine_CountSecretsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/count_team_test.go b/database/secret/count_team_test.go index 7b029d9e8..50bad4ae4 100644 --- a/database/secret/count_team_test.go +++ b/database/secret/count_team_test.go @@ -52,12 +52,12 @@ func TestSecret_Engine_CountSecretsForTeam(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } @@ -158,12 +158,12 @@ func TestSecret_Engine_CountSecretsForTeams(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/count_test.go b/database/secret/count_test.go index b30dcdca2..d3b3f3c48 100644 --- a/database/secret/count_test.go +++ b/database/secret/count_test.go @@ -49,12 +49,12 @@ func TestSecret_Engine_CountSecrets(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/secret/create.go b/database/secret/create.go index e061c36a1..734281cf1 100644 --- a/database/secret/create.go +++ b/database/secret/create.go @@ -15,7 +15,7 @@ import ( ) // CreateSecret creates a new secret in the database. -func (e *engine) CreateSecret(s *library.Secret) error { +func (e *engine) CreateSecret(s *library.Secret) (*library.Secret, error) { // handle the secret based off the type switch s.GetType() { case constants.SecretShared: @@ -44,7 +44,7 @@ func (e *engine) CreateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Validate err := secret.Validate() if err != nil { - return err + return nil, err } // encrypt the fields for the secret @@ -54,15 +54,29 @@ func (e *engine) CreateSecret(s *library.Secret) error { if err != nil { switch s.GetType() { case constants.SecretShared: - return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + return nil, fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) default: - return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + return nil, fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) } } - // send query to the database - return e.client. - Table(constants.TableSecret). - Create(secret.Nullify()). - Error + // create secret record + result := e.client.Table(constants.TableSecret).Create(secret.Nullify()) + + if result.Error != nil { + return nil, result.Error + } + + // decrypt the fields for the secret to return + err = secret.Decrypt(e.config.EncryptionKey) + if err != nil { + switch s.GetType() { + case constants.SecretShared: + return nil, fmt.Errorf("unable to decrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + default: + return nil, fmt.Errorf("unable to decrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + } + } + + return secret.ToLibrary(), nil } diff --git a/database/secret/create_test.go b/database/secret/create_test.go index 1f6fbd3bd..ec4fa38e3 100644 --- a/database/secret/create_test.go +++ b/database/secret/create_test.go @@ -5,6 +5,7 @@ package secret import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -127,7 +128,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateSecret(test.secret) + got, err := test.database.CreateSecret(test.secret) if test.failure { if err == nil { @@ -140,6 +141,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) RETURNING "id"`). if err != nil { t.Errorf("CreateSecret for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, test.secret) { + t.Errorf("CreateSecret is %s, want %s", got, test.secret) + } }) } } diff --git a/database/secret/delete_test.go b/database/secret/delete_test.go index c44202544..46def2c55 100644 --- a/database/secret/delete_test.go +++ b/database/secret/delete_test.go @@ -70,17 +70,17 @@ func TestSecret_Engine_DeleteSecret(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretRepo) + _, err := _sqlite.CreateSecret(_secretRepo) if err != nil { t.Errorf("unable to create test repo secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretOrg) + _, err = _sqlite.CreateSecret(_secretOrg) if err != nil { t.Errorf("unable to create test org secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretShared) + _, err = _sqlite.CreateSecret(_secretShared) if err != nil { t.Errorf("unable to create test shared secret for sqlite: %v", err) } diff --git a/database/secret/get_org_test.go b/database/secret/get_org_test.go index 107c2d804..7747838b8 100644 --- a/database/secret/get_org_test.go +++ b/database/secret/get_org_test.go @@ -42,7 +42,7 @@ func TestSecret_Engine_GetSecretForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secret) + _, err := _sqlite.CreateSecret(_secret) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/get_repo_test.go b/database/secret/get_repo_test.go index 98b9f1da6..05d872373 100644 --- a/database/secret/get_repo_test.go +++ b/database/secret/get_repo_test.go @@ -52,7 +52,7 @@ func TestSecret_Engine_GetSecretForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secret) + _, err := _sqlite.CreateSecret(_secret) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/get_team_test.go b/database/secret/get_team_test.go index 8705a4e96..217415189 100644 --- a/database/secret/get_team_test.go +++ b/database/secret/get_team_test.go @@ -42,7 +42,7 @@ func TestSecret_Engine_GetSecretForTeam(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secret) + _, err := _sqlite.CreateSecret(_secret) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/get_test.go b/database/secret/get_test.go index c4499c0fc..e19e89291 100644 --- a/database/secret/get_test.go +++ b/database/secret/get_test.go @@ -40,7 +40,7 @@ func TestSecret_Engine_GetSecret(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secret) + _, err := _sqlite.CreateSecret(_secret) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/interface.go b/database/secret/interface.go index c6bee369a..dfb134d9b 100644 --- a/database/secret/interface.go +++ b/database/secret/interface.go @@ -37,7 +37,7 @@ type SecretInterface interface { // CountSecretsForTeams defines a function that gets the count of secrets by teams within an org. CountSecretsForTeams(string, []string, map[string]interface{}) (int64, error) // CreateSecret defines a function that creates a new secret. - CreateSecret(*library.Secret) error + CreateSecret(*library.Secret) (*library.Secret, error) // DeleteSecret defines a function that deletes an existing secret. DeleteSecret(*library.Secret) error // GetSecret defines a function that gets a secret by ID. @@ -59,5 +59,5 @@ type SecretInterface interface { // ListSecretsForTeams defines a function that gets a list of secrets by teams within an org. ListSecretsForTeams(string, []string, map[string]interface{}, int, int) ([]*library.Secret, int64, error) // UpdateSecret defines a function that updates an existing secret. - UpdateSecret(*library.Secret) error + UpdateSecret(*library.Secret) (*library.Secret, error) } diff --git a/database/secret/list_org_test.go b/database/secret/list_org_test.go index dbf6695a4..23acd7ead 100644 --- a/database/secret/list_org_test.go +++ b/database/secret/list_org_test.go @@ -62,12 +62,12 @@ func TestSecret_Engine_ListSecretsForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/list_repo_test.go b/database/secret/list_repo_test.go index 10f389f8a..db26d2543 100644 --- a/database/secret/list_repo_test.go +++ b/database/secret/list_repo_test.go @@ -73,12 +73,12 @@ func TestSecret_Engine_ListSecretsForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/list_team_test.go b/database/secret/list_team_test.go index 39492f52a..546877659 100644 --- a/database/secret/list_team_test.go +++ b/database/secret/list_team_test.go @@ -63,12 +63,12 @@ func TestSecret_Engine_ListSecretsForTeam(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } @@ -169,12 +169,12 @@ func TestSecret_Engine_ListSecretsForTeams(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/list_test.go b/database/secret/list_test.go index b962925ed..d0f4d9768 100644 --- a/database/secret/list_test.go +++ b/database/secret/list_test.go @@ -59,12 +59,12 @@ func TestSecret_Engine_ListSecrets(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretOne) + _, err := _sqlite.CreateSecret(_secretOne) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretTwo) + _, err = _sqlite.CreateSecret(_secretTwo) if err != nil { t.Errorf("unable to create test secret for sqlite: %v", err) } diff --git a/database/secret/update.go b/database/secret/update.go index 3f00efb09..823ede644 100644 --- a/database/secret/update.go +++ b/database/secret/update.go @@ -15,7 +15,7 @@ import ( ) // UpdateSecret updates an existing secret in the database. -func (e *engine) UpdateSecret(s *library.Secret) error { +func (e *engine) UpdateSecret(s *library.Secret) (*library.Secret, error) { // handle the secret based off the type switch s.GetType() { case constants.SecretShared: @@ -44,7 +44,7 @@ func (e *engine) UpdateSecret(s *library.Secret) error { // https://pkg.go.dev/github.com/go-vela/types/database#Secret.Validate err := secret.Validate() if err != nil { - return err + return nil, err } // encrypt the fields for the secret @@ -54,15 +54,26 @@ func (e *engine) UpdateSecret(s *library.Secret) error { if err != nil { switch s.GetType() { case constants.SecretShared: - return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + return nil, fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) default: - return fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + return nil, fmt.Errorf("unable to encrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) } } - // send query to the database - return e.client. - Table(constants.TableSecret). - Save(secret.Nullify()). - Error + err = e.client.Table(constants.TableSecret).Save(secret.Nullify()).Error + if err != nil { + return nil, err + } + + err = secret.Decrypt(e.config.EncryptionKey) + if err != nil { + switch s.GetType() { + case constants.SecretShared: + return nil, fmt.Errorf("unable to decrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetTeam(), s.GetName(), err) + default: + return nil, fmt.Errorf("unable to decrypt secret %s/%s/%s/%s: %w", s.GetType(), s.GetOrg(), s.GetRepo(), s.GetName(), err) + } + } + + return secret.ToLibrary(), nil } diff --git a/database/secret/update_test.go b/database/secret/update_test.go index fd9a24ff6..247b9d229 100644 --- a/database/secret/update_test.go +++ b/database/secret/update_test.go @@ -5,6 +5,7 @@ package secret import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -76,17 +77,17 @@ WHERE "id" = $14`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateSecret(_secretRepo) + _, err := _sqlite.CreateSecret(_secretRepo) if err != nil { t.Errorf("unable to create test repo secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretOrg) + _, err = _sqlite.CreateSecret(_secretOrg) if err != nil { t.Errorf("unable to create test org secret for sqlite: %v", err) } - err = _sqlite.CreateSecret(_secretShared) + _, err = _sqlite.CreateSecret(_secretShared) if err != nil { t.Errorf("unable to create test shared secret for sqlite: %v", err) } @@ -139,7 +140,8 @@ WHERE "id" = $14`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateSecret(test.secret) + got, err := test.database.UpdateSecret(test.secret) + got.SetUpdatedAt(test.secret.GetUpdatedAt()) if test.failure { if err == nil { @@ -152,6 +154,10 @@ WHERE "id" = $14`). if err != nil { t.Errorf("UpdateSecret for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, test.secret) { + t.Errorf("UpdateSecret for %s is %s, want %s", test.name, got, test.secret) + } }) } } diff --git a/secret/native/count_test.go b/secret/native/count_test.go index 2d1080029..42c71cc9b 100644 --- a/secret/native/count_test.go +++ b/secret/native/count_test.go @@ -38,7 +38,7 @@ func TestNative_Count(t *testing.T) { db.Close() }() - _ = db.CreateSecret(sec) + _, _ = db.CreateSecret(sec) // run test s, err := New( diff --git a/secret/native/create.go b/secret/native/create.go index 6b6c90512..b93869602 100644 --- a/secret/native/create.go +++ b/secret/native/create.go @@ -13,7 +13,7 @@ import ( ) // Create creates a new secret. -func (c *client) Create(sType, org, name string, s *library.Secret) error { +func (c *client) Create(sType, org, name string, s *library.Secret) (*library.Secret, error) { // handle the secret based off the type switch sType { case constants.SecretOrg: @@ -46,6 +46,6 @@ func (c *client) Create(sType, org, name string, s *library.Secret) error { // create the shared secret in the native service return c.Database.CreateSecret(s) default: - return fmt.Errorf("invalid secret type: %s", sType) + return nil, fmt.Errorf("invalid secret type: %s", sType) } } diff --git a/secret/native/create_test.go b/secret/native/create_test.go index 328b22ae0..93c6898a4 100644 --- a/secret/native/create_test.go +++ b/secret/native/create_test.go @@ -49,13 +49,11 @@ func TestNative_Create_Org(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("org", "foo", "*", want) + got, err := s.Create("org", "foo", "*", want) if err != nil { t.Errorf("Create returned err: %v", err) } - got, _ := s.Get("org", "foo", "*", "bar") - if !reflect.DeepEqual(got, want) { t.Errorf("Create is %v, want %v", got, want) } @@ -98,13 +96,11 @@ func TestNative_Create_Repo(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("repo", "foo", "bar", want) + got, err := s.Create("repo", "foo", "bar", want) if err != nil { t.Errorf("Create returned err: %v", err) } - got, _ := s.Get("repo", "foo", "bar", "baz") - if !reflect.DeepEqual(got, want) { t.Errorf("Create is %v, want %v", got, want) } @@ -147,13 +143,11 @@ func TestNative_Create_Shared(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("shared", "foo", "bar", want) + got, err := s.Create("shared", "foo", "bar", want) if err != nil { t.Errorf("Create returned err: %v", err) } - got, _ := s.Get("shared", "foo", "bar", "baz") - if !reflect.DeepEqual(got, want) { t.Errorf("Create is %v, want %v", got, want) } @@ -196,7 +190,7 @@ func TestNative_Create_Invalid(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("invalid", "foo", "bar", sec) + _, err = s.Create("invalid", "foo", "bar", sec) if err == nil { t.Errorf("Create should have returned err") } diff --git a/secret/native/delete_test.go b/secret/native/delete_test.go index e1c49c133..e2e21a5f7 100644 --- a/secret/native/delete_test.go +++ b/secret/native/delete_test.go @@ -38,7 +38,7 @@ func TestNative_Delete(t *testing.T) { db.Close() }() - _ = db.CreateSecret(sec) + _, _ = db.CreateSecret(sec) // run test s, err := New( diff --git a/secret/native/get_test.go b/secret/native/get_test.go index 438ede6a7..218236dc6 100644 --- a/secret/native/get_test.go +++ b/secret/native/get_test.go @@ -50,7 +50,7 @@ func TestNative_Get(t *testing.T) { t.Errorf("New returned err: %v", err) } - _ = s.Create("repo", "foo", "bar", want) + _, _ = s.Create("repo", "foo", "bar", want) got, err := s.Get("repo", "foo", "bar", "baz") if err != nil { diff --git a/secret/native/list_test.go b/secret/native/list_test.go index ae0870cd6..2cec7b78e 100644 --- a/secret/native/list_test.go +++ b/secret/native/list_test.go @@ -68,9 +68,9 @@ func TestNative_List(t *testing.T) { t.Errorf("New returned err: %v", err) } - _ = s.Create("repo", "foo", "bar", sOne) + _, _ = s.Create("repo", "foo", "bar", sOne) - _ = s.Create("repo", "foo", "bar", sTwo) + _, _ = s.Create("repo", "foo", "bar", sTwo) got, err := s.List("repo", "foo", "bar", 1, 10, []string{}) if err != nil { diff --git a/secret/native/update.go b/secret/native/update.go index ceda7e842..045b340c2 100644 --- a/secret/native/update.go +++ b/secret/native/update.go @@ -13,11 +13,11 @@ import ( ) // Update updates an existing secret. -func (c *client) Update(sType, org, name string, s *library.Secret) error { +func (c *client) Update(sType, org, name string, s *library.Secret) (*library.Secret, error) { // capture the secret from the native service secret, err := c.Get(sType, org, name, s.GetName()) if err != nil { - return err + return nil, err } // update the events if set @@ -78,6 +78,6 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { // update the shared secret in the native service return c.Database.UpdateSecret(secret) default: - return fmt.Errorf("invalid secret type: %s", sType) + return nil, fmt.Errorf("invalid secret type: %s", sType) } } diff --git a/secret/native/update_test.go b/secret/native/update_test.go index f8c7bf3cb..66e637ad3 100644 --- a/secret/native/update_test.go +++ b/secret/native/update_test.go @@ -58,7 +58,7 @@ func TestNative_Update(t *testing.T) { db.Close() }() - _ = db.CreateSecret(original) + _, _ = db.CreateSecret(original) // run test s, err := New( @@ -68,13 +68,11 @@ func TestNative_Update(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", want) + got, err := s.Update("repo", "foo", "bar", want) if err != nil { t.Errorf("Update returned err: %v", err) } - got, _ := s.Get("repo", "foo", "bar", "baz") - if !reflect.DeepEqual(got, want) { t.Errorf("Update is %v, want %v", got, want) } @@ -101,7 +99,7 @@ func TestNative_Update_Invalid(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", sec) + _, err = s.Update("repo", "foo", "bar", sec) if err == nil { t.Errorf("Update should have returned err") } diff --git a/secret/service.go b/secret/service.go index 855ae1863..aacb9a0d3 100644 --- a/secret/service.go +++ b/secret/service.go @@ -22,9 +22,9 @@ type Service interface { // Count defines a function that counts a list of secrets. Count(string, string, string, []string) (int64, error) // Create defines a function that creates a new secret. - Create(string, string, string, *library.Secret) error + Create(string, string, string, *library.Secret) (*library.Secret, error) // Update defines a function that updates an existing secret. - Update(string, string, string, *library.Secret) error + Update(string, string, string, *library.Secret) (*library.Secret, error) // Delete defines a function that deletes a secret. Delete(string, string, string, string) error diff --git a/secret/vault/create.go b/secret/vault/create.go index bdcde401d..ba34883ef 100644 --- a/secret/vault/create.go +++ b/secret/vault/create.go @@ -16,7 +16,7 @@ import ( ) // Create creates a new secret. -func (c *client) Create(sType, org, name string, s *library.Secret) error { +func (c *client) Create(sType, org, name string, s *library.Secret) (*library.Secret, error) { // create log fields from secret metadata fields := logrus.Fields{ "org": org, @@ -41,7 +41,7 @@ func (c *client) Create(sType, org, name string, s *library.Secret) error { // validate the secret err := database.SecretFromLibrary(s).Validate() if err != nil { - return err + return nil, err } // convert our secret to a Vault secret @@ -56,31 +56,31 @@ func (c *client) Create(sType, org, name string, s *library.Secret) error { case constants.SecretShared: return c.createShared(org, name, s.GetName(), vault.Data) default: - return fmt.Errorf("invalid secret type: %v", sType) + return nil, fmt.Errorf("invalid secret type: %v", sType) } } // createOrg is a helper function to create // the org secret for the provided path. -func (c *client) createOrg(org, path string, data map[string]interface{}) error { +func (c *client) createOrg(org, path string, data map[string]interface{}) (*library.Secret, error) { return c.create(fmt.Sprintf("%s/org/%s/%s", c.config.Prefix, org, path), data) } // createRepo is a helper function to create // the repo secret for the provided path. -func (c *client) createRepo(org, repo, path string, data map[string]interface{}) error { +func (c *client) createRepo(org, repo, path string, data map[string]interface{}) (*library.Secret, error) { return c.create(fmt.Sprintf("%s/repo/%s/%s/%s", c.config.Prefix, org, repo, path), data) } // createShared is a helper function to create // the shared secret for the provided path. -func (c *client) createShared(org, team, path string, data map[string]interface{}) error { +func (c *client) createShared(org, team, path string, data map[string]interface{}) (*library.Secret, error) { return c.create(fmt.Sprintf("%s/shared/%s/%s/%s", c.config.Prefix, org, team, path), data) } // create is a helper function to create // the secret for the provided path. -func (c *client) create(path string, data map[string]interface{}) error { +func (c *client) create(path string, data map[string]interface{}) (*library.Secret, error) { if strings.HasPrefix("secret/data", c.config.Prefix) { data = map[string]interface{}{ "data": data, @@ -88,10 +88,10 @@ func (c *client) create(path string, data map[string]interface{}) error { } // send API call to create the secret - _, err := c.Vault.Logical().Write(path, data) + s, err := c.Vault.Logical().Write(path, data) if err != nil { - return err + return nil, err } - return nil + return secretFromVault(s), nil } diff --git a/secret/vault/create_test.go b/secret/vault/create_test.go index d6e03d920..3213925f1 100644 --- a/secret/vault/create_test.go +++ b/secret/vault/create_test.go @@ -7,6 +7,7 @@ package vault import ( "net/http" "net/http/httptest" + "reflect" "testing" "github.com/go-vela/types/library" @@ -23,15 +24,21 @@ func TestVault_Create_Org(t *testing.T) { // setup mock server engine.PUT("/v1/secret/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/org.json") }) engine.PUT("/v1/secret/data/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/org.json") }) engine.PUT("/v1/secret/data/prefix/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/org.json") }) fake := httptest.NewServer(engine) @@ -41,13 +48,11 @@ func TestVault_Create_Org(t *testing.T) { sec := new(library.Secret) sec.SetOrg("foo") sec.SetRepo("*") - sec.SetTeam("") sec.SetName("bar") sec.SetValue("baz") sec.SetType("org") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -77,7 +82,7 @@ func TestVault_Create_Org(t *testing.T) { if err != nil { t.Errorf("New returned err: %v", err) } - err = s.Create("org", "foo", "*", sec) + got, err := s.Create("org", "foo", "*", sec) if resp.Code != http.StatusOK { t.Errorf("Create returned %v, want %v", resp.Code, http.StatusOK) @@ -86,6 +91,10 @@ func TestVault_Create_Org(t *testing.T) { if err != nil { t.Errorf("Create returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Create returned %s, want %s", got, sec) + } }) } } @@ -99,15 +108,21 @@ func TestVault_Create_Repo(t *testing.T) { // setup mock server engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/repo.json") }) engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/repo.json") }) engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/repo.json") }) fake := httptest.NewServer(engine) @@ -117,13 +132,11 @@ func TestVault_Create_Repo(t *testing.T) { sec := new(library.Secret) sec.SetOrg("foo") sec.SetRepo("bar") - sec.SetTeam("") sec.SetName("baz") sec.SetValue("foob") sec.SetType("repo") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -153,7 +166,8 @@ func TestVault_Create_Repo(t *testing.T) { if err != nil { t.Errorf("New returned err: %v", err) } - err = s.Create("repo", "foo", "bar", sec) + + got, err := s.Create("repo", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Create returned %v, want %v", resp.Code, http.StatusOK) @@ -162,6 +176,10 @@ func TestVault_Create_Repo(t *testing.T) { if err != nil { t.Errorf("Create returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Create returned %s, want %s", got, sec) + } }) } } @@ -175,13 +193,21 @@ func TestVault_Create_Shared(t *testing.T) { // setup mock server engine.PUT("/v1/secret/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/shared.json") }) + engine.PUT("/v1/secret/data/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/shared.json") }) + engine.PUT("/v1/secret/data/prefix/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/shared.json") }) fake := httptest.NewServer(engine) @@ -190,14 +216,12 @@ func TestVault_Create_Shared(t *testing.T) { // setup types sec := new(library.Secret) sec.SetOrg("foo") - sec.SetRepo("") sec.SetTeam("bar") sec.SetName("baz") sec.SetValue("foob") sec.SetType("shared") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -227,7 +251,8 @@ func TestVault_Create_Shared(t *testing.T) { if err != nil { t.Errorf("New returned err: %v", err) } - err = s.Create("shared", "foo", "bar", sec) + + got, err := s.Create("shared", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Create returned %v, want %v", resp.Code, http.StatusOK) @@ -236,6 +261,10 @@ func TestVault_Create_Shared(t *testing.T) { if err != nil { t.Errorf("Create returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Create returned %s, want %s", got, sec) + } }) } } @@ -303,7 +332,8 @@ func TestVault_Create_InvalidSecret(t *testing.T) { if err != nil { t.Errorf("New returned err: %v", err) } - err = s.Create("repo", "foo", "bar", sec) + + _, err = s.Create("repo", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Create returned %v, want %v", resp.Code, http.StatusOK) @@ -362,7 +392,7 @@ func TestVault_Create_InvalidType(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("invalid", "foo", "bar", sec) + _, err = s.Create("invalid", "foo", "bar", sec) if err == nil { t.Errorf("Create should have returned err") } @@ -416,7 +446,7 @@ func TestVault_Create_ClosedServer(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Create("repo", "foo", "bar", sec) + _, err = s.Create("repo", "foo", "bar", sec) if err == nil { t.Errorf("Create should have returned err") } diff --git a/secret/vault/update.go b/secret/vault/update.go index ef0f1e131..453d15e3e 100644 --- a/secret/vault/update.go +++ b/secret/vault/update.go @@ -16,7 +16,7 @@ import ( ) // Update updates a secret. -func (c *client) Update(sType, org, name string, s *library.Secret) error { +func (c *client) Update(sType, org, name string, s *library.Secret) (*library.Secret, error) { // create log fields from secret metadata fields := logrus.Fields{ "org": org, @@ -41,7 +41,7 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { // capture the secret from the Vault service sec, err := c.Get(sType, org, name, s.GetName()) if err != nil { - return err + return nil, err } // convert the Vault secret our secret @@ -65,7 +65,7 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { // validate the secret err = database.SecretFromLibrary(secretFromVault(vault)).Validate() if err != nil { - return err + return nil, err } // update the secret for the Vault service @@ -83,35 +83,35 @@ func (c *client) Update(sType, org, name string, s *library.Secret) error { // updateOrg is a helper function to update // the org secret for the provided path. -func (c *client) updateOrg(org, path string, data map[string]interface{}) error { +func (c *client) updateOrg(org, path string, data map[string]interface{}) (*library.Secret, error) { return c.update(fmt.Sprintf("%s/%s/%s/%s", c.config.Prefix, constants.SecretOrg, org, path), data) } // updateRepo is a helper function to update // the repo secret for the provided path. -func (c *client) updateRepo(org, repo, path string, data map[string]interface{}) error { +func (c *client) updateRepo(org, repo, path string, data map[string]interface{}) (*library.Secret, error) { return c.update(fmt.Sprintf("%s/%s/%s/%s/%s", c.config.Prefix, constants.SecretRepo, org, repo, path), data) } // updateShared is a helper function to update // the shared secret for the provided path. -func (c *client) updateShared(org, team, path string, data map[string]interface{}) error { +func (c *client) updateShared(org, team, path string, data map[string]interface{}) (*library.Secret, error) { return c.update(fmt.Sprintf("%s/%s/%s/%s/%s", c.config.Prefix, constants.SecretShared, org, team, path), data) } // update is a helper function to update // the secret for the provided path. -func (c *client) update(path string, data map[string]interface{}) error { +func (c *client) update(path string, data map[string]interface{}) (*library.Secret, error) { if strings.HasPrefix("secret/data", c.config.Prefix) { data = map[string]interface{}{ "data": data, } } - _, err := c.Vault.Logical().Write(path, data) + s, err := c.Vault.Logical().Write(path, data) if err != nil { - return err + return nil, err } - return nil + return secretFromVault(s), nil } diff --git a/secret/vault/update_test.go b/secret/vault/update_test.go index a0f54de42..49e04a1b2 100644 --- a/secret/vault/update_test.go +++ b/secret/vault/update_test.go @@ -7,6 +7,7 @@ package vault import ( "net/http" "net/http/httptest" + "reflect" "testing" "github.com/go-vela/types/library" @@ -22,31 +23,37 @@ func TestVault_Update_Org(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/v1/secret/org/foo/bar", func(c *gin.Context) { + engine.PUT("/v1/secret/org/foo/bar", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v1/org.json") }) - engine.PUT("/v1/secret/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/org/foo/bar", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/org.json") }) - engine.GET("/v1/secret/data/org/foo/bar", func(c *gin.Context) { + engine.PUT("/v1/secret/data/org/foo/bar", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/org.json") }) - engine.PUT("/v1/secret/data/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/org/foo/bar", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/org.json") }) - engine.GET("/v1/secret/data/prefix/org/foo/bar", func(c *gin.Context) { + engine.PUT("/v1/secret/data/prefix/org/foo/bar", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/org.json") }) - engine.PUT("/v1/secret/data/prefix/org/foo/bar", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/prefix/org/foo/bar", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/org.json") }) fake := httptest.NewServer(engine) @@ -56,13 +63,11 @@ func TestVault_Update_Org(t *testing.T) { sec := new(library.Secret) sec.SetOrg("foo") sec.SetRepo("*") - sec.SetTeam("") sec.SetName("bar") sec.SetValue("baz") sec.SetType("org") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -93,7 +98,7 @@ func TestVault_Update_Org(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("org", "foo", "*", sec) + got, err := s.Update("org", "foo", "*", sec) if resp.Code != http.StatusOK { t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) @@ -102,6 +107,10 @@ func TestVault_Update_Org(t *testing.T) { if err != nil { t.Errorf("Update returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Update returned %s, want %s", got, sec) + } }) } } @@ -114,31 +123,37 @@ func TestVault_Update_Repo(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v1/repo.json") }) - engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/repo.json") }) - engine.GET("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/repo.json") }) - engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/repo.json") }) - engine.GET("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/repo.json") }) - engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/repo.json") }) fake := httptest.NewServer(engine) @@ -153,7 +168,6 @@ func TestVault_Update_Repo(t *testing.T) { sec.SetType("repo") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -184,7 +198,7 @@ func TestVault_Update_Repo(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", sec) + got, err := s.Update("repo", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) @@ -193,6 +207,10 @@ func TestVault_Update_Repo(t *testing.T) { if err != nil { t.Errorf("Update returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Update returned %s, want %s", got, sec) + } }) } } @@ -205,31 +223,37 @@ func TestVault_Update_Shared(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/v1/secret/shared/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/shared/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v1/shared.json") }) - engine.PUT("/v1/secret/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/shared/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v1/shared.json") }) - engine.GET("/v1/secret/data/shared/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/shared/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/shared.json") }) - engine.PUT("/v1/secret/data/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/shared/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/shared.json") }) - engine.GET("/v1/secret/data/prefix/shared/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/prefix/shared/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/shared.json") }) - engine.PUT("/v1/secret/data/prefix/shared/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") + engine.GET("/v1/secret/data/prefix/shared/foo/bar/baz", func(c *gin.Context) { + c.Header("Content-Type", "application/json") + c.Status(http.StatusOK) + c.File("testdata/v2/shared.json") }) fake := httptest.NewServer(engine) @@ -244,7 +268,6 @@ func TestVault_Update_Shared(t *testing.T) { sec.SetType("shared") sec.SetImages([]string{"foo", "bar"}) sec.SetEvents([]string{"foo", "bar"}) - sec.SetAllowCommand(false) type args struct { version string @@ -275,7 +298,7 @@ func TestVault_Update_Shared(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("shared", "foo", "bar", sec) + got, err := s.Update("shared", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) @@ -284,6 +307,10 @@ func TestVault_Update_Shared(t *testing.T) { if err != nil { t.Errorf("Update returned err: %v", err) } + + if !reflect.DeepEqual(got, sec) { + t.Errorf("Update returned %s, want %s", got, sec) + } }) } } @@ -296,32 +323,23 @@ func TestVault_Update_InvalidSecret(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v1/invalid_repo.json") }) - engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") - }) - engine.GET("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/invalid_repo.json") }) - engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") - }) - engine.GET("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { + engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { c.Header("Content-Type", "application/json") c.Status(http.StatusOK) c.File("testdata/v2/invalid_repo.json") }) - engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { - c.String(http.StatusNoContent, "") - }) fake := httptest.NewServer(engine) defer fake.Close() @@ -366,7 +384,7 @@ func TestVault_Update_InvalidSecret(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", sec) + _, err = s.Update("repo", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) @@ -423,7 +441,7 @@ func TestVault_Update_InvalidType(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("invalid", "foo", "bar", sec) + _, err = s.Update("invalid", "foo", "bar", sec) if err == nil { t.Errorf("Update should have returned err") } @@ -475,7 +493,7 @@ func TestVault_Update_ClosedServer(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", sec) + _, err = s.Update("repo", "foo", "bar", sec) if err == nil { t.Errorf("Update should have returned err") } @@ -491,29 +509,14 @@ func TestVault_Update_NoWrite(t *testing.T) { _, engine := gin.CreateTestContext(resp) // setup mock server - engine.GET("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/v1/repo.json") - }) engine.PUT("/v1/secret/repo/foo/bar/baz", func(c *gin.Context) { c.Status(http.StatusNotFound) }) - engine.GET("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/v2/repo.json") - }) engine.PUT("/v1/secret/data/repo/foo/bar/baz", func(c *gin.Context) { c.Status(http.StatusNotFound) }) - engine.GET("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { - c.Header("Content-Type", "application/json") - c.Status(http.StatusOK) - c.File("testdata/v2/repo.json") - }) engine.PUT("/v1/secret/data/prefix/repo/foo/bar/baz", func(c *gin.Context) { c.Status(http.StatusNotFound) }) @@ -560,7 +563,7 @@ func TestVault_Update_NoWrite(t *testing.T) { t.Errorf("New returned err: %v", err) } - err = s.Update("repo", "foo", "bar", sec) + _, err = s.Update("repo", "foo", "bar", sec) if resp.Code != http.StatusOK { t.Errorf("Update returned %v, want %v", resp.Code, http.StatusOK) From 9750002ab9aba14eb0c4cbb4ea09ab5ad15af8c6 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:07:06 -0500 Subject: [PATCH 288/298] chore: add context to repos functions (#930) * enhance: add context to Repos * chore: add WithContext test --- api/admin/repo.go | 5 +- api/build/create.go | 2 +- api/build/get_id.go | 2 +- api/build/restart.go | 2 +- api/metrics.go | 2 +- api/repo/chown.go | 3 +- api/repo/create.go | 7 +- api/repo/delete.go | 3 +- api/repo/list.go | 3 +- api/repo/list_org.go | 3 +- api/repo/repair.go | 3 +- api/repo/update.go | 3 +- api/scm/sync.go | 3 +- api/scm/sync_org.go | 7 +- api/user/get_source.go | 3 +- api/webhook/post.go | 26 ++++--- cmd/vela-server/schedule.go | 6 +- database/integration_test.go | 26 +++---- database/repo/count.go | 4 +- database/repo/count_org.go | 4 +- database/repo/count_org_test.go | 7 +- database/repo/count_test.go | 7 +- database/repo/count_user.go | 4 +- database/repo/count_user_test.go | 7 +- database/repo/create.go | 3 +- database/repo/create_test.go | 3 +- database/repo/delete.go | 4 +- database/repo/delete_test.go | 5 +- database/repo/get.go | 4 +- database/repo/get_org.go | 4 +- database/repo/get_org_test.go | 5 +- database/repo/get_test.go | 5 +- database/repo/index.go | 4 +- database/repo/index_test.go | 3 +- database/repo/interface.go | 28 ++++---- database/repo/list.go | 6 +- database/repo/list_org.go | 6 +- database/repo/list_org_test.go | 7 +- database/repo/list_test.go | 7 +- database/repo/list_user.go | 6 +- database/repo/list_user_test.go | 7 +- database/repo/opts.go | 11 +++ database/repo/opts_test.go | 50 +++++++++++++ database/repo/repo.go | 7 +- database/repo/table.go | 8 ++- database/repo/table_test.go | 3 +- database/repo/update.go | 3 +- database/repo/update_test.go | 5 +- database/resource.go | 2 + router/middleware/build/build_test.go | 16 ++--- router/middleware/org/org_test.go | 5 +- router/middleware/perm/perm_test.go | 80 ++++++++++----------- router/middleware/pipeline/pipeline_test.go | 13 ++-- router/middleware/repo/repo.go | 3 +- router/middleware/repo/repo_test.go | 5 +- router/middleware/service/service_test.go | 20 +++--- router/middleware/step/step_test.go | 20 +++--- 57 files changed, 311 insertions(+), 189 deletions(-) diff --git a/api/admin/repo.go b/api/admin/repo.go index 53ad236b9..b24fb7013 100644 --- a/api/admin/repo.go +++ b/api/admin/repo.go @@ -53,6 +53,9 @@ import ( func UpdateRepo(c *gin.Context) { logrus.Info("Admin: updating repo in database") + // capture middleware values + ctx := c.Request.Context() + // capture body from API request input := new(library.Repo) @@ -66,7 +69,7 @@ func UpdateRepo(c *gin.Context) { } // send API call to update the repo - r, err := database.FromContext(c).UpdateRepo(input) + r, err := database.FromContext(c).UpdateRepo(ctx, input) if err != nil { retErr := fmt.Errorf("unable to update repo %d: %w", input.GetID(), err) diff --git a/api/build/create.go b/api/build/create.go index 8b97062ae..0591945e5 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -330,7 +330,7 @@ func CreateBuild(c *gin.Context) { } // send API call to update repo for ensuring counter is incremented - r, err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to create new build: failed to update repo %s: %w", r.GetFullName(), err) diff --git a/api/build/get_id.go b/api/build/get_id.go index 1bbd47d69..439cd9b81 100644 --- a/api/build/get_id.go +++ b/api/build/get_id.go @@ -90,7 +90,7 @@ func GetBuildByID(c *gin.Context) { } // Get repo from database using repo ID field from build - r, err = database.FromContext(c).GetRepo(b.GetRepoID()) + r, err = database.FromContext(c).GetRepo(ctx, b.GetRepoID()) if err != nil { retErr := fmt.Errorf("unable to get repo: %w", err) diff --git a/api/build/restart.go b/api/build/restart.go index e2280cce2..63847d2d3 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -321,7 +321,7 @@ func RestartBuild(c *gin.Context) { } // send API call to update repo for ensuring counter is incremented - r, err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to restart build: failed to update repo %s: %w", r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/api/metrics.go b/api/metrics.go index c8c120868..08994e65c 100644 --- a/api/metrics.go +++ b/api/metrics.go @@ -261,7 +261,7 @@ func recordGauges(c *gin.Context) { // repo_count if q.RepoCount { // send API call to capture the total number of repos - r, err := database.FromContext(c).CountRepos() + r, err := database.FromContext(c).CountRepos(ctx) if err != nil { logrus.Errorf("unable to get count of all repos: %v", err) } diff --git a/api/repo/chown.go b/api/repo/chown.go index 671e5a438..93a4ec5fa 100644 --- a/api/repo/chown.go +++ b/api/repo/chown.go @@ -54,6 +54,7 @@ func ChownRepo(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -68,7 +69,7 @@ func ChownRepo(c *gin.Context) { r.SetUserID(u.GetID()) // send API call to update the repo - _, err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to change owner of repo %s to %s: %w", r.GetFullName(), u.GetName(), err) diff --git a/api/repo/create.go b/api/repo/create.go index ca0dc2d6e..d76aae325 100644 --- a/api/repo/create.go +++ b/api/repo/create.go @@ -75,6 +75,7 @@ func CreateRepo(c *gin.Context) { defaultTimeout := c.Value("defaultTimeout").(int64) maxBuildLimit := c.Value("maxBuildLimit").(int64) defaultRepoEvents := c.Value("defaultRepoEvents").([]string) + ctx := c.Request.Context() // capture body from API request input := new(library.Repo) @@ -221,7 +222,7 @@ func CreateRepo(c *gin.Context) { } // send API call to capture the repo from the database - dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + dbRepo, err := database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName()) if err == nil && dbRepo.GetActive() { retErr := fmt.Errorf("unable to activate repo: %s is already active", r.GetFullName()) @@ -283,7 +284,7 @@ func CreateRepo(c *gin.Context) { dbRepo.SetActive(true) // send API call to update the repo - r, err = database.FromContext(c).UpdateRepo(dbRepo) + r, err = database.FromContext(c).UpdateRepo(ctx, dbRepo) if err != nil { retErr := fmt.Errorf("unable to set repo %s to active: %w", dbRepo.GetFullName(), err) @@ -293,7 +294,7 @@ func CreateRepo(c *gin.Context) { } } else { // send API call to create the repo - r, err = database.FromContext(c).CreateRepo(r) + r, err = database.FromContext(c).CreateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to create new repo %s: %w", r.GetFullName(), err) diff --git a/api/repo/delete.go b/api/repo/delete.go index cc3ca66b9..4ddaf11f7 100644 --- a/api/repo/delete.go +++ b/api/repo/delete.go @@ -59,6 +59,7 @@ func DeleteRepo(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -88,7 +89,7 @@ func DeleteRepo(c *gin.Context) { // Mark the repo as inactive r.SetActive(false) - _, err = database.FromContext(c).UpdateRepo(r) + _, err = database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to set repo %s to inactive: %w", r.GetFullName(), err) diff --git a/api/repo/list.go b/api/repo/list.go index c4ea06c54..77c127b3c 100644 --- a/api/repo/list.go +++ b/api/repo/list.go @@ -66,6 +66,7 @@ import ( func ListRepos(c *gin.Context) { // capture middleware values u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -108,7 +109,7 @@ func ListRepos(c *gin.Context) { } // send API call to capture the list of repos for the user - r, t, err := database.FromContext(c).ListReposForUser(u, sortBy, filters, page, perPage) + r, t, err := database.FromContext(c).ListReposForUser(ctx, u, sortBy, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get repos for user %s: %w", u.GetName(), err) diff --git a/api/repo/list_org.go b/api/repo/list_org.go index 2a8353d03..727b91b5d 100644 --- a/api/repo/list_org.go +++ b/api/repo/list_org.go @@ -88,6 +88,7 @@ func ListReposForOrg(c *gin.Context) { // capture middleware values o := org.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -141,7 +142,7 @@ func ListReposForOrg(c *gin.Context) { } // send API call to capture the list of repos for the org - r, t, err := database.FromContext(c).ListReposForOrg(o, sortBy, filters, page, perPage) + r, t, err := database.FromContext(c).ListReposForOrg(ctx, o, sortBy, filters, page, perPage) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", o, err) diff --git a/api/repo/repair.go b/api/repo/repair.go index 7b7f0e98d..337f52d91 100644 --- a/api/repo/repair.go +++ b/api/repo/repair.go @@ -55,6 +55,7 @@ func RepairRepo(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -122,7 +123,7 @@ func RepairRepo(c *gin.Context) { r.SetActive(true) // send API call to update the repo - _, err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to set repo %s to active: %w", r.GetFullName(), err) diff --git a/api/repo/update.go b/api/repo/update.go index 2f299bdc1..a7684c393 100644 --- a/api/repo/update.go +++ b/api/repo/update.go @@ -77,6 +77,7 @@ func UpdateRepo(c *gin.Context) { r := repo.Retrieve(c) u := user.Retrieve(c) maxBuildLimit := c.Value("maxBuildLimit").(int64) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -295,7 +296,7 @@ func UpdateRepo(c *gin.Context) { } // send API call to update the repo - r, err = database.FromContext(c).UpdateRepo(r) + r, err = database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) diff --git a/api/scm/sync.go b/api/scm/sync.go index c98ea82e4..dc264f264 100644 --- a/api/scm/sync.go +++ b/api/scm/sync.go @@ -59,6 +59,7 @@ func SyncRepo(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -80,7 +81,7 @@ func SyncRepo(c *gin.Context) { r.SetActive(false) // update repo in database - _, err := database.FromContext(c).UpdateRepo(r) + _, err := database.FromContext(c).UpdateRepo(ctx, r) if err != nil { retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) diff --git a/api/scm/sync_org.go b/api/scm/sync_org.go index 9cda091ef..944a33adc 100644 --- a/api/scm/sync_org.go +++ b/api/scm/sync_org.go @@ -52,6 +52,7 @@ func SyncReposForOrg(c *gin.Context) { // capture middleware values o := org.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -79,7 +80,7 @@ func SyncReposForOrg(c *gin.Context) { } // send API call to capture the total number of repos for the org - t, err := database.FromContext(c).CountReposForOrg(o, map[string]interface{}{}) + t, err := database.FromContext(c).CountReposForOrg(ctx, o, map[string]interface{}{}) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) @@ -92,7 +93,7 @@ func SyncReposForOrg(c *gin.Context) { page := 0 // capture all repos belonging to a certain org in database for orgRepos := int64(0); orgRepos < t; orgRepos += 100 { - r, _, err := database.FromContext(c).ListReposForOrg(o, "name", map[string]interface{}{}, page, 100) + r, _, err := database.FromContext(c).ListReposForOrg(ctx, o, "name", map[string]interface{}{}, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repo count for org %s: %w", o, err) @@ -113,7 +114,7 @@ func SyncReposForOrg(c *gin.Context) { if err != nil { repo.SetActive(false) - _, err := database.FromContext(c).UpdateRepo(repo) + _, err := database.FromContext(c).UpdateRepo(ctx, repo) if err != nil { retErr := fmt.Errorf("unable to update repo for org %s: %w", o, err) diff --git a/api/user/get_source.go b/api/user/get_source.go index 2ea8734c3..9892f319e 100644 --- a/api/user/get_source.go +++ b/api/user/get_source.go @@ -41,6 +41,7 @@ import ( func GetSourceRepos(c *gin.Context) { // capture middleware values u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -88,7 +89,7 @@ func GetSourceRepos(c *gin.Context) { for page > 0 { // send API call to capture the list of repos for the org - dbReposPart, _, err := database.FromContext(c).ListReposForOrg(org, "name", filters, page, 100) + dbReposPart, _, err := database.FromContext(c).ListReposForOrg(ctx, org, "name", filters, page, 100) if err != nil { retErr := fmt.Errorf("unable to get repos for org %s: %w", org, err) diff --git a/api/webhook/post.go b/api/webhook/post.go index f25fd872b..8d5ca369b 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -6,6 +6,7 @@ package webhook import ( "bytes" + "context" "fmt" "io" "net/http" @@ -135,7 +136,7 @@ func PostWebhook(c *gin.Context) { // if event is repository event, handle separately and return if strings.EqualFold(h.GetEvent(), constants.EventRepository) { - r, err = handleRepositoryEvent(c, m, h, r) + r, err = handleRepositoryEvent(ctx, c, m, h, r) if err != nil { util.HandleError(c, http.StatusInternalServerError, err) return @@ -184,7 +185,7 @@ func PostWebhook(c *gin.Context) { }() // send API call to capture parsed repo from webhook - repo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + repo, err := database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName()) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -445,7 +446,7 @@ func PostWebhook(c *gin.Context) { } // send API call to capture repo for the counter (grabbing repo again to ensure counter is correct) - repo, err = database.FromContext(c).GetRepoForOrg(repo.GetOrg(), repo.GetName()) + repo, err = database.FromContext(c).GetRepoForOrg(ctx, repo.GetOrg(), repo.GetName()) if err != nil { retErr := fmt.Errorf("%s: unable to get repo %s: %w", baseErr, r.GetFullName(), err) @@ -621,7 +622,7 @@ func PostWebhook(c *gin.Context) { } // end of retry loop // send API call to update repo for ensuring counter is incremented - repo, err = database.FromContext(c).UpdateRepo(repo) + repo, err = database.FromContext(c).UpdateRepo(ctx, repo) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, repo.GetFullName(), err) util.HandleError(c, http.StatusBadRequest, retErr) @@ -689,7 +690,7 @@ func PostWebhook(c *gin.Context) { ) } -func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r *library.Repo) (*library.Repo, error) { +func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *types.Metadata, h *library.Hook, r *library.Repo) (*library.Repo, error) { logrus.Debugf("webhook is repository event, making necessary updates to repo %s", r.GetFullName()) defer func() { @@ -703,7 +704,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r switch h.GetEventAction() { // if action is rename, go through rename routine case constants.ActionRenamed, constants.ActionTransferred: - r, err := renameRepository(h, r, c, m) + r, err := renameRepository(ctx, h, r, c, m) if err != nil { h.SetStatus(constants.StatusFailure) h.SetError(err.Error()) @@ -716,7 +717,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r case "archived", "unarchived", constants.ActionEdited: logrus.Debugf("repository action %s for %s", h.GetEventAction(), r.GetFullName()) // send call to get repository from database - dbRepo, err := database.FromContext(c).GetRepoForOrg(r.GetOrg(), r.GetName()) + dbRepo, err := database.FromContext(c).GetRepoForOrg(ctx, r.GetOrg(), r.GetName()) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s: %w", baseErr, r.GetFullName(), err) @@ -760,7 +761,7 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r } // update repo object in the database after applying edits - dbRepo, err = database.FromContext(c).UpdateRepo(dbRepo) + dbRepo, err = database.FromContext(c).UpdateRepo(ctx, dbRepo) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s: %w", baseErr, r.GetFullName(), err) @@ -781,17 +782,14 @@ func handleRepositoryEvent(c *gin.Context, m *types.Metadata, h *library.Hook, r // queries the database for the repo that matches that name and org, and updates // that repo to its new name in order to preserve it. It also updates the secrets // associated with that repo as well as build links for the UI. -func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) (*library.Repo, error) { +func renameRepository(ctx context.Context, h *library.Hook, r *library.Repo, c *gin.Context, m *types.Metadata) (*library.Repo, error) { logrus.Infof("renaming repository from %s to %s", r.GetPreviousName(), r.GetName()) - // capture context from gin - ctx := c.Request.Context() - // get the old name of the repo prevOrg, prevRepo := util.SplitFullName(r.GetPreviousName()) // get the repo from the database that matches the old name - dbR, err := database.FromContext(c).GetRepoForOrg(prevOrg, prevRepo) + dbR, err := database.FromContext(c).GetRepoForOrg(ctx, prevOrg, prevRepo) if err != nil { retErr := fmt.Errorf("%s: failed to get repo %s/%s from database", baseErr, prevOrg, prevRepo) util.HandleError(c, http.StatusBadRequest, retErr) @@ -896,7 +894,7 @@ func renameRepository(h *library.Hook, r *library.Repo, c *gin.Context, m *types dbR.SetPreviousName(r.GetPreviousName()) // update the repo in the database - dbR, err = database.FromContext(c).UpdateRepo(dbR) + dbR, err = database.FromContext(c).UpdateRepo(ctx, dbR) if err != nil { retErr := fmt.Errorf("%s: failed to update repo %s/%s in database", baseErr, prevOrg, prevRepo) util.HandleError(c, http.StatusBadRequest, retErr) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 2144af965..804da21f3 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -138,7 +138,7 @@ func processSchedules(ctx context.Context, start time.Time, compiler compiler.En //nolint:funlen // ignore function length and number of statements func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler.Engine, database database.Interface, metadata *types.Metadata, queue queue.Service, scm scm.Service) error { // send API call to capture the repo for the schedule - r, err := database.GetRepo(s.GetRepoID()) + r, err := database.GetRepo(ctx, s.GetRepoID()) if err != nil { return fmt.Errorf("unable to fetch repo: %w", err) } @@ -249,7 +249,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // send API call to capture repo for the counter (grabbing repo again to ensure counter is correct) - r, err = database.GetRepoForOrg(r.GetOrg(), r.GetName()) + r, err = database.GetRepoForOrg(ctx, r.GetOrg(), r.GetName()) if err != nil { err = fmt.Errorf("unable to get repo %s: %w", r.GetFullName(), err) @@ -374,7 +374,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // end of retry loop // send API call to update repo for ensuring counter is incremented - r, err = database.UpdateRepo(r) + r, err = database.UpdateRepo(ctx, r) if err != nil { return fmt.Errorf("unable to update repo %s: %w", r.GetFullName(), err) } diff --git a/database/integration_test.go b/database/integration_test.go index 0f1e9808d..d8f8a6e67 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -165,7 +165,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // create the repos for build related functions for _, repo := range resources.Repos { - _, err := db.CreateRepo(repo) + _, err := db.CreateRepo(context.TODO(), repo) if err != nil { t.Errorf("unable to create repo %d: %v", repo.GetID(), err) } @@ -367,7 +367,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // delete the repos for build related functions for _, repo := range resources.Repos { - err = db.DeleteRepo(repo) + err = db.DeleteRepo(context.TODO(), repo) if err != nil { t.Errorf("unable to delete repo %d: %v", repo.GetID(), err) } @@ -784,7 +784,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { // create the repos for _, repo := range resources.Repos { - _, err := db.CreateRepo(repo) + _, err := db.CreateRepo(context.TODO(), repo) if err != nil { t.Errorf("unable to create repo %d: %v", repo.GetID(), err) } @@ -792,7 +792,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["CreateRepo"] = true // count the repos - count, err := db.CountRepos() + count, err := db.CountRepos(context.TODO()) if err != nil { t.Errorf("unable to count repos: %v", err) } @@ -802,7 +802,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["CountRepos"] = true // count the repos for an org - count, err = db.CountReposForOrg(resources.Repos[0].GetOrg(), nil) + count, err = db.CountReposForOrg(context.TODO(), resources.Repos[0].GetOrg(), nil) if err != nil { t.Errorf("unable to count repos for org %s: %v", resources.Repos[0].GetOrg(), err) } @@ -812,7 +812,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["CountReposForOrg"] = true // count the repos for a user - count, err = db.CountReposForUser(resources.Users[0], nil) + count, err = db.CountReposForUser(context.TODO(), resources.Users[0], nil) if err != nil { t.Errorf("unable to count repos for user %d: %v", resources.Users[0].GetID(), err) } @@ -822,7 +822,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["CountReposForUser"] = true // list the repos - list, err := db.ListRepos() + list, err := db.ListRepos(context.TODO()) if err != nil { t.Errorf("unable to list repos: %v", err) } @@ -832,7 +832,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["ListRepos"] = true // list the repos for an org - list, count, err = db.ListReposForOrg(resources.Repos[0].GetOrg(), "name", nil, 1, 10) + list, count, err = db.ListReposForOrg(context.TODO(), resources.Repos[0].GetOrg(), "name", nil, 1, 10) if err != nil { t.Errorf("unable to list repos for org %s: %v", resources.Repos[0].GetOrg(), err) } @@ -845,7 +845,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { methods["ListReposForOrg"] = true // list the repos for a user - list, count, err = db.ListReposForUser(resources.Users[0], "name", nil, 1, 10) + list, count, err = db.ListReposForUser(context.TODO(), resources.Users[0], "name", nil, 1, 10) if err != nil { t.Errorf("unable to list repos for user %d: %v", resources.Users[0].GetID(), err) } @@ -859,7 +859,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { // lookup the repos by name for _, repo := range resources.Repos { - got, err := db.GetRepoForOrg(repo.GetOrg(), repo.GetName()) + got, err := db.GetRepoForOrg(context.TODO(), repo.GetOrg(), repo.GetName()) if err != nil { t.Errorf("unable to get repo %d by org: %v", repo.GetID(), err) } @@ -872,13 +872,13 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { // update the repos for _, repo := range resources.Repos { repo.SetActive(false) - _, err = db.UpdateRepo(repo) + _, err = db.UpdateRepo(context.TODO(), repo) if err != nil { t.Errorf("unable to update repo %d: %v", repo.GetID(), err) } // lookup the repo by ID - got, err := db.GetRepo(repo.GetID()) + got, err := db.GetRepo(context.TODO(), repo.GetID()) if err != nil { t.Errorf("unable to get repo %d by ID: %v", repo.GetID(), err) } @@ -891,7 +891,7 @@ func testRepos(t *testing.T, db Interface, resources *Resources) { // delete the repos for _, repo := range resources.Repos { - err = db.DeleteRepo(repo) + err = db.DeleteRepo(context.TODO(), repo) if err != nil { t.Errorf("unable to delete repo %d: %v", repo.GetID(), err) } diff --git a/database/repo/count.go b/database/repo/count.go index 032e7d780..3ef5297d1 100644 --- a/database/repo/count.go +++ b/database/repo/count.go @@ -5,11 +5,13 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" ) // CountRepos gets the count of all repos from the database. -func (e *engine) CountRepos() (int64, error) { +func (e *engine) CountRepos(ctx context.Context) (int64, error) { e.logger.Tracef("getting count of all repos from the database") // variable to store query results diff --git a/database/repo/count_org.go b/database/repo/count_org.go index 938f151c6..0e44516e9 100644 --- a/database/repo/count_org.go +++ b/database/repo/count_org.go @@ -5,12 +5,14 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" ) // CountReposForOrg gets the count of repos by org name from the database. -func (e *engine) CountReposForOrg(org string, filters map[string]interface{}) (int64, error) { +func (e *engine) CountReposForOrg(ctx context.Context, org string, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "org": org, }).Tracef("getting count of repos for org %s from the database", org) diff --git a/database/repo/count_org_test.go b/database/repo/count_org_test.go index fd4797dad..f3657f3eb 100644 --- a/database/repo/count_org_test.go +++ b/database/repo/count_org_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -43,12 +44,12 @@ func TestRepo_Engine_CountReposForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -79,7 +80,7 @@ func TestRepo_Engine_CountReposForOrg(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountReposForOrg("foo", filters) + got, err := test.database.CountReposForOrg(context.TODO(), "foo", filters) if test.failure { if err == nil { diff --git a/database/repo/count_test.go b/database/repo/count_test.go index 104cccc65..668018315 100644 --- a/database/repo/count_test.go +++ b/database/repo/count_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -43,12 +44,12 @@ func TestRepo_Engine_CountRepos(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -77,7 +78,7 @@ func TestRepo_Engine_CountRepos(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountRepos() + got, err := test.database.CountRepos(context.TODO()) if test.failure { if err == nil { diff --git a/database/repo/count_user.go b/database/repo/count_user.go index dbd226dac..bfa7f56ee 100644 --- a/database/repo/count_user.go +++ b/database/repo/count_user.go @@ -5,13 +5,15 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // CountReposForUser gets the count of repos by user ID from the database. -func (e *engine) CountReposForUser(u *library.User, filters map[string]interface{}) (int64, error) { +func (e *engine) CountReposForUser(ctx context.Context, u *library.User, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "user": u.GetName(), }).Tracef("getting count of repos for user %s from the database", u.GetName()) diff --git a/database/repo/count_user_test.go b/database/repo/count_user_test.go index 45ea309ab..58342226e 100644 --- a/database/repo/count_user_test.go +++ b/database/repo/count_user_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -49,12 +50,12 @@ func TestRepo_Engine_CountReposForUser(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -85,7 +86,7 @@ func TestRepo_Engine_CountReposForUser(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountReposForUser(_user, filters) + got, err := test.database.CountReposForUser(context.TODO(), _user, filters) if test.failure { if err == nil { diff --git a/database/repo/create.go b/database/repo/create.go index 850d854aa..800365e55 100644 --- a/database/repo/create.go +++ b/database/repo/create.go @@ -6,6 +6,7 @@ package repo import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -15,7 +16,7 @@ import ( ) // CreateRepo creates a new repo in the database. -func (e *engine) CreateRepo(r *library.Repo) (*library.Repo, error) { +func (e *engine) CreateRepo(ctx context.Context, r *library.Repo) (*library.Repo, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/repo/create_test.go b/database/repo/create_test.go index 4241ce4ab..4e59b2d99 100644 --- a/database/repo/create_test.go +++ b/database/repo/create_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -62,7 +63,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$ // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CreateRepo(_repo) + got, err := test.database.CreateRepo(context.TODO(), _repo) if test.failure { if err == nil { diff --git a/database/repo/delete.go b/database/repo/delete.go index 64a515610..4e0df1918 100644 --- a/database/repo/delete.go +++ b/database/repo/delete.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // DeleteRepo deletes an existing repo from the database. -func (e *engine) DeleteRepo(r *library.Repo) error { +func (e *engine) DeleteRepo(ctx context.Context, r *library.Repo) error { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/repo/delete_test.go b/database/repo/delete_test.go index a4504d6bc..f7f64e1aa 100644 --- a/database/repo/delete_test.go +++ b/database/repo/delete_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -32,7 +33,7 @@ func TestRepo_Engine_DeleteRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(context.TODO(), _repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -58,7 +59,7 @@ func TestRepo_Engine_DeleteRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.DeleteRepo(_repo) + err = test.database.DeleteRepo(context.TODO(), _repo) if test.failure { if err == nil { diff --git a/database/repo/get.go b/database/repo/get.go index 5a162ffb2..3adbaaffd 100644 --- a/database/repo/get.go +++ b/database/repo/get.go @@ -5,13 +5,15 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // GetRepo gets a repo by ID from the database. -func (e *engine) GetRepo(id int64) (*library.Repo, error) { +func (e *engine) GetRepo(ctx context.Context, id int64) (*library.Repo, error) { e.logger.Tracef("getting repo %d from the database", id) // variable to store query results diff --git a/database/repo/get_org.go b/database/repo/get_org.go index f03260b99..2188e0a5e 100644 --- a/database/repo/get_org.go +++ b/database/repo/get_org.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // GetRepoForOrg gets a repo by org and repo name from the database. -func (e *engine) GetRepoForOrg(org, name string) (*library.Repo, error) { +func (e *engine) GetRepoForOrg(ctx context.Context, org, name string) (*library.Repo, error) { e.logger.WithFields(logrus.Fields{ "org": org, "repo": name, diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go index b60faefde..1eb1b5940 100644 --- a/database/repo/get_org_test.go +++ b/database/repo/get_org_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -39,7 +40,7 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(context.TODO(), _repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -68,7 +69,7 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetRepoForOrg("foo", "bar") + got, err := test.database.GetRepoForOrg(context.TODO(), "foo", "bar") if test.failure { if err == nil { diff --git a/database/repo/get_test.go b/database/repo/get_test.go index e098626de..02ea9dd98 100644 --- a/database/repo/get_test.go +++ b/database/repo/get_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -39,7 +40,7 @@ func TestRepo_Engine_GetRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(context.TODO(), _repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -68,7 +69,7 @@ func TestRepo_Engine_GetRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetRepo(1) + got, err := test.database.GetRepo(context.TODO(), 1) if test.failure { if err == nil { diff --git a/database/repo/index.go b/database/repo/index.go index 2bc7c5ffa..8c90262a7 100644 --- a/database/repo/index.go +++ b/database/repo/index.go @@ -4,6 +4,8 @@ package repo +import "context" + const ( // CreateOrgNameIndex represents a query to create an // index on the repos table for the org and name columns. @@ -16,7 +18,7 @@ ON repos (org, name); ) // CreateRepoIndexes creates the indexes for the repos table in the database. -func (e *engine) CreateRepoIndexes() error { +func (e *engine) CreateRepoIndexes(ctx context.Context) error { e.logger.Tracef("creating indexes for repos table in the database") // create the org and name columns index for the repos table diff --git a/database/repo/index_test.go b/database/repo/index_test.go index 90550cae8..d9a527b61 100644 --- a/database/repo/index_test.go +++ b/database/repo/index_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestRepo_Engine_CreateRepoIndexes(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateRepoIndexes() + err := test.database.CreateRepoIndexes(context.TODO()) if test.failure { if err == nil { diff --git a/database/repo/interface.go b/database/repo/interface.go index 1b641da35..6dad94d20 100644 --- a/database/repo/interface.go +++ b/database/repo/interface.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/go-vela/types/library" ) @@ -18,34 +20,34 @@ type RepoInterface interface { // https://en.wikipedia.org/wiki/Data_definition_language // CreateRepoIndexes defines a function that creates the indexes for the repos table. - CreateRepoIndexes() error + CreateRepoIndexes(context.Context) error // CreateRepoTable defines a function that creates the repos table. - CreateRepoTable(string) error + CreateRepoTable(context.Context, string) error // Repo Data Manipulation Language Functions // // https://en.wikipedia.org/wiki/Data_manipulation_language // CountRepos defines a function that gets the count of all repos. - CountRepos() (int64, error) + CountRepos(context.Context) (int64, error) // CountReposForOrg defines a function that gets the count of repos by org name. - CountReposForOrg(string, map[string]interface{}) (int64, error) + CountReposForOrg(context.Context, string, map[string]interface{}) (int64, error) // CountReposForUser defines a function that gets the count of repos by user ID. - CountReposForUser(*library.User, map[string]interface{}) (int64, error) + CountReposForUser(context.Context, *library.User, map[string]interface{}) (int64, error) // CreateRepo defines a function that creates a new repo. - CreateRepo(*library.Repo) (*library.Repo, error) + CreateRepo(context.Context, *library.Repo) (*library.Repo, error) // DeleteRepo defines a function that deletes an existing repo. - DeleteRepo(*library.Repo) error + DeleteRepo(context.Context, *library.Repo) error // GetRepo defines a function that gets a repo by ID. - GetRepo(int64) (*library.Repo, error) + GetRepo(context.Context, int64) (*library.Repo, error) // GetRepoForOrg defines a function that gets a repo by org and repo name. - GetRepoForOrg(string, string) (*library.Repo, error) + GetRepoForOrg(context.Context, string, string) (*library.Repo, error) // ListRepos defines a function that gets a list of all repos. - ListRepos() ([]*library.Repo, error) + ListRepos(context.Context) ([]*library.Repo, error) // ListReposForOrg defines a function that gets a list of repos by org name. - ListReposForOrg(string, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) + ListReposForOrg(context.Context, string, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) // ListReposForUser defines a function that gets a list of repos by user ID. - ListReposForUser(*library.User, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) + ListReposForUser(context.Context, *library.User, string, map[string]interface{}, int, int) ([]*library.Repo, int64, error) // UpdateRepo defines a function that updates an existing repo. - UpdateRepo(*library.Repo) (*library.Repo, error) + UpdateRepo(context.Context, *library.Repo) (*library.Repo, error) } diff --git a/database/repo/list.go b/database/repo/list.go index 1b9b5d11c..c65754c16 100644 --- a/database/repo/list.go +++ b/database/repo/list.go @@ -5,13 +5,15 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListRepos gets a list of all repos from the database. -func (e *engine) ListRepos() ([]*library.Repo, error) { +func (e *engine) ListRepos(ctx context.Context) ([]*library.Repo, error) { e.logger.Trace("listing all repos from the database") // variables to store query results and return value @@ -20,7 +22,7 @@ func (e *engine) ListRepos() ([]*library.Repo, error) { repos := []*library.Repo{} // count the results - count, err := e.CountRepos() + count, err := e.CountRepos(ctx) if err != nil { return nil, err } diff --git a/database/repo/list_org.go b/database/repo/list_org.go index c673d2d88..9809716bf 100644 --- a/database/repo/list_org.go +++ b/database/repo/list_org.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // ListReposForOrg gets a list of repos by org name from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListReposForOrg(org, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { +func (e *engine) ListReposForOrg(ctx context.Context, org, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { e.logger.WithFields(logrus.Fields{ "org": org, }).Tracef("listing repos for org %s from the database", org) @@ -25,7 +27,7 @@ func (e *engine) ListReposForOrg(org, sortBy string, filters map[string]interfac repos := []*library.Repo{} // count the results - count, err := e.CountReposForOrg(org, filters) + count, err := e.CountReposForOrg(ctx, org, filters) if err != nil { return repos, 0, err } diff --git a/database/repo/list_org_test.go b/database/repo/list_org_test.go index e54a11bf4..c87707385 100644 --- a/database/repo/list_org_test.go +++ b/database/repo/list_org_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" "time" @@ -87,12 +88,12 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -155,7 +156,7 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListReposForOrg("foo", test.sort, filters, 1, 10) + got, _, err := test.database.ListReposForOrg(context.TODO(), "foo", test.sort, filters, 1, 10) if test.failure { if err == nil { diff --git a/database/repo/list_test.go b/database/repo/list_test.go index 6936406e6..01b6a257f 100644 --- a/database/repo/list_test.go +++ b/database/repo/list_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -57,12 +58,12 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -91,7 +92,7 @@ func TestRepo_Engine_ListRepos(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListRepos() + got, err := test.database.ListRepos(context.TODO()) if test.failure { if err == nil { diff --git a/database/repo/list_user.go b/database/repo/list_user.go index a28a466aa..bf9b6ea8b 100644 --- a/database/repo/list_user.go +++ b/database/repo/list_user.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // ListReposForUser gets a list of repos by user ID from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListReposForUser(u *library.User, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { +func (e *engine) ListReposForUser(ctx context.Context, u *library.User, sortBy string, filters map[string]interface{}, page, perPage int) ([]*library.Repo, int64, error) { e.logger.WithFields(logrus.Fields{ "user": u.GetName(), }).Tracef("listing repos for user %s from the database", u.GetName()) @@ -25,7 +27,7 @@ func (e *engine) ListReposForUser(u *library.User, sortBy string, filters map[st repos := []*library.Repo{} // count the results - count, err := e.CountReposForUser(u, filters) + count, err := e.CountReposForUser(ctx, u, filters) if err != nil { return repos, 0, err } diff --git a/database/repo/list_user_test.go b/database/repo/list_user_test.go index 7bff6fe2c..7f4fe0629 100644 --- a/database/repo/list_user_test.go +++ b/database/repo/list_user_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" "time" @@ -92,12 +93,12 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repoOne) + _, err := _sqlite.CreateRepo(context.TODO(), _repoOne) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - _, err = _sqlite.CreateRepo(_repoTwo) + _, err = _sqlite.CreateRepo(context.TODO(), _repoTwo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -160,7 +161,7 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListReposForUser(_user, test.sort, filters, 1, 10) + got, _, err := test.database.ListReposForUser(context.TODO(), _user, test.sort, filters, 1, 10) if test.failure { if err == nil { diff --git a/database/repo/opts.go b/database/repo/opts.go index 95957a598..41a2b9492 100644 --- a/database/repo/opts.go +++ b/database/repo/opts.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -52,3 +54,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine for Repos. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/repo/opts_test.go b/database/repo/opts_test.go index 78bfb826e..4f9e981ae 100644 --- a/database/repo/opts_test.go +++ b/database/repo/opts_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -208,3 +209,52 @@ func TestRepo_EngineOpt_WithSkipCreation(t *testing.T) { }) } } + +func TestRepo_EngineOpt_WithContext(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + ctx context.Context + want context.Context + }{ + { + failure: false, + name: "context set to TODO", + ctx: context.TODO(), + want: context.TODO(), + }, + { + failure: false, + name: "context set to nil", + ctx: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithContext(test.ctx)(e) + + if test.failure { + if err == nil { + t.Errorf("WithContext for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithContext returned err: %v", err) + } + + if !reflect.DeepEqual(e.ctx, test.want) { + t.Errorf("WithContext is %v, want %v", e.ctx, test.want) + } + }) + } +} diff --git a/database/repo/repo.go b/database/repo/repo.go index 1da6a8ab8..a74c34956 100644 --- a/database/repo/repo.go +++ b/database/repo/repo.go @@ -5,6 +5,7 @@ package repo import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -27,6 +28,8 @@ type ( // engine configuration settings used in repo functions config *config + ctx context.Context + // gorm.io/gorm database client used in repo functions // // https://pkg.go.dev/gorm.io/gorm#DB @@ -67,13 +70,13 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the repos table - err := e.CreateRepoTable(e.client.Config.Dialector.Name()) + err := e.CreateRepoTable(e.ctx, e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TableRepo, err) } // create the indexes for the repos table - err = e.CreateRepoIndexes() + err = e.CreateRepoIndexes(e.ctx) if err != nil { return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TableRepo, err) } diff --git a/database/repo/table.go b/database/repo/table.go index 1df91afff..aa570dd43 100644 --- a/database/repo/table.go +++ b/database/repo/table.go @@ -4,7 +4,11 @@ package repo -import "github.com/go-vela/types/constants" +import ( + "context" + + "github.com/go-vela/types/constants" +) const ( // CreatePostgresTable represents a query to create the Postgres repos table. @@ -75,7 +79,7 @@ repos ( ) // CreateRepoTable creates the repos table in the database. -func (e *engine) CreateRepoTable(driver string) error { +func (e *engine) CreateRepoTable(ctx context.Context, driver string) error { e.logger.Tracef("creating repos table in the database") // handle the driver provided to create the table diff --git a/database/repo/table_test.go b/database/repo/table_test.go index 7680c02d6..021f76673 100644 --- a/database/repo/table_test.go +++ b/database/repo/table_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestRepo_Engine_CreateRepoTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateRepoTable(test.name) + err := test.database.CreateRepoTable(context.TODO(), test.name) if test.failure { if err == nil { diff --git a/database/repo/update.go b/database/repo/update.go index cf7111499..fbbce6b64 100644 --- a/database/repo/update.go +++ b/database/repo/update.go @@ -6,6 +6,7 @@ package repo import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -15,7 +16,7 @@ import ( ) // UpdateRepo updates an existing repo in the database. -func (e *engine) UpdateRepo(r *library.Repo) (*library.Repo, error) { +func (e *engine) UpdateRepo(ctx context.Context, r *library.Repo) (*library.Repo, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/repo/update_test.go b/database/repo/update_test.go index 66f4fa6a9..459a4325a 100644 --- a/database/repo/update_test.go +++ b/database/repo/update_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "reflect" "testing" @@ -38,7 +39,7 @@ WHERE "id" = $24`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreateRepo(_repo) + _, err := _sqlite.CreateRepo(context.TODO(), _repo) if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -64,7 +65,7 @@ WHERE "id" = $24`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.UpdateRepo(_repo) + got, err := test.database.UpdateRepo(context.TODO(), _repo) if test.failure { if err == nil { diff --git a/database/resource.go b/database/resource.go index ce3dd853a..a2e177353 100644 --- a/database/resource.go +++ b/database/resource.go @@ -6,6 +6,7 @@ package database import ( "context" + "github.com/go-vela/server/database/build" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" @@ -68,6 +69,7 @@ func (e *engine) NewResources(ctx context.Context) error { // create the database agnostic engine for repos e.RepoInterface, err = repo.New( + repo.WithContext(e.ctx), repo.WithClient(e.client), repo.WithEncryptionKey(e.config.EncryptionKey), repo.WithLogger(e.logger), diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index e4e68193a..40e52f52f 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -91,11 +91,11 @@ func TestBuild_Establish(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), want) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), want) // setup context @@ -173,11 +173,11 @@ func TestBuild_Establish_NoBuildParameter(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) @@ -221,11 +221,11 @@ func TestBuild_Establish_InvalidBuildParameter(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) @@ -269,11 +269,11 @@ func TestBuild_Establish_NoBuild(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/org/org_test.go b/router/middleware/org/org_test.go index 4c98de87e..7e6007bc1 100644 --- a/router/middleware/org/org_test.go +++ b/router/middleware/org/org_test.go @@ -5,6 +5,7 @@ package org import ( + "context" "net/http" "net/http/httptest" "reflect" @@ -65,11 +66,11 @@ func TestOrg_Establish(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index b51017c91..b1495ab19 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -446,11 +446,11 @@ func TestPerm_MustBuildAccess(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -537,12 +537,12 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) _ = db.CreateUser(u) @@ -625,11 +625,11 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) @@ -711,11 +711,11 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/repo/foo/bar/baz", nil) @@ -794,11 +794,11 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/org/foo/*/baz", nil) @@ -877,11 +877,11 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _, _ = db.CreateBuild(ctx, b) context.Request, _ = http.NewRequest(http.MethodGet, "/test/native/shared/foo/*/*", nil) @@ -957,12 +957,12 @@ func TestPerm_MustAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1055,12 +1055,12 @@ func TestPerm_MustAdmin_PlatAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1153,12 +1153,12 @@ func TestPerm_MustAdmin_NotAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1251,12 +1251,12 @@ func TestPerm_MustWrite(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1349,12 +1349,12 @@ func TestPerm_MustWrite_PlatAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1447,12 +1447,12 @@ func TestPerm_MustWrite_RepoAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1545,12 +1545,12 @@ func TestPerm_MustWrite_NotWrite(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1643,12 +1643,12 @@ func TestPerm_MustRead(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1741,12 +1741,12 @@ func TestPerm_MustRead_PlatAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -1842,12 +1842,12 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { defer func() { db.DeleteBuild(ctx, b) - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.Close() }() _, _ = db.CreateBuild(ctx, b) - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar/builds/1", nil) context.Request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tok)) @@ -1925,12 +1925,12 @@ func TestPerm_MustRead_RepoAdmin(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2023,12 +2023,12 @@ func TestPerm_MustRead_RepoWrite(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2121,12 +2121,12 @@ func TestPerm_MustRead_RepoPublic(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) @@ -2219,12 +2219,12 @@ func TestPerm_MustRead_NotRead(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(_context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(_context.TODO(), r) _ = db.CreateUser(u) context.Request, _ = http.NewRequest(http.MethodGet, "/test/foo/bar", nil) diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index 4e7912372..ff410c1da 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "flag" "fmt" "net/http" @@ -103,11 +104,11 @@ func TestPipeline_Establish(t *testing.T) { defer func() { db.DeletePipeline(want) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreatePipeline(want) // setup context @@ -185,11 +186,11 @@ func TestPipeline_Establish_NoPipelineParameter(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) @@ -288,12 +289,12 @@ func TestPipeline_Establish_NoPipeline(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.DeleteUser(u) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _ = db.CreateUser(u) // setup context diff --git a/router/middleware/repo/repo.go b/router/middleware/repo/repo.go index d8cc5447e..fcc898f9e 100644 --- a/router/middleware/repo/repo.go +++ b/router/middleware/repo/repo.go @@ -27,6 +27,7 @@ func Establish() gin.HandlerFunc { return func(c *gin.Context) { o := org.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() rParam := util.PathParameter(c, "repo") if len(rParam) == 0 { @@ -45,7 +46,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading repo %s/%s", o, rParam) - r, err := database.FromContext(c).GetRepoForOrg(o, rParam) + r, err := database.FromContext(c).GetRepoForOrg(ctx, o, rParam) if err != nil { retErr := fmt.Errorf("unable to read repo %s/%s: %w", o, rParam, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index 50b6c8cc7..0274db0ec 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -5,6 +5,7 @@ package repo import ( + "context" "net/http" "net/http/httptest" "reflect" @@ -72,11 +73,11 @@ func TestRepo_Establish(t *testing.T) { } defer func() { - db.DeleteRepo(want) + db.DeleteRepo(context.TODO(), want) db.Close() }() - _, _ = db.CreateRepo(want) + _, _ = db.CreateRepo(context.TODO(), want) // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index b2234659c..d900394b7 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -80,12 +80,12 @@ func TestService_Establish(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.DeleteService(want) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) _ = db.CreateService(want) @@ -168,11 +168,11 @@ func TestService_Establish_NoBuild(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) @@ -222,11 +222,11 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context @@ -278,11 +278,11 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context @@ -334,11 +334,11 @@ func TestService_Establish_NoService(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index 795463a7a..6c9aede32 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -82,12 +82,12 @@ func TestStep_Establish(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.DeleteStep(want) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) _ = db.CreateStep(want) @@ -170,11 +170,11 @@ func TestStep_Establish_NoBuild(t *testing.T) { } defer func() { - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) // setup context gin.SetMode(gin.TestMode) @@ -224,11 +224,11 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context @@ -280,11 +280,11 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context @@ -336,11 +336,11 @@ func TestStep_Establish_NoStep(t *testing.T) { defer func() { db.DeleteBuild(context.TODO(), b) - db.DeleteRepo(r) + db.DeleteRepo(context.TODO(), r) db.Close() }() - _, _ = db.CreateRepo(r) + _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) // setup context From 26aa0b67266384527dd09e94f3af463e0ef63e83 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:16:13 -0500 Subject: [PATCH 289/298] chore: add WithContext test to builds (#931) --- database/build/opts_test.go | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/database/build/opts_test.go b/database/build/opts_test.go index 2d41cc676..69afe0b4a 100644 --- a/database/build/opts_test.go +++ b/database/build/opts_test.go @@ -5,6 +5,7 @@ package build import ( + "context" "reflect" "testing" @@ -159,3 +160,52 @@ func TestBuild_EngineOpt_WithSkipCreation(t *testing.T) { }) } } + +func TestBuild_EngineOpt_WithContext(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + ctx context.Context + want context.Context + }{ + { + failure: false, + name: "context set to TODO", + ctx: context.TODO(), + want: context.TODO(), + }, + { + failure: false, + name: "context set to nil", + ctx: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithContext(test.ctx)(e) + + if test.failure { + if err == nil { + t.Errorf("WithContext for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithContext returned err: %v", err) + } + + if !reflect.DeepEqual(e.ctx, test.want) { + t.Errorf("WithContext is %v, want %v", e.ctx, test.want) + } + }) + } +} From c41cb14ac9cd29ca2e253d0dd58c570fe8643db7 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:24:02 -0500 Subject: [PATCH 290/298] chore: add context to pipeline functions (#923) --- api/build/create.go | 4 +- api/build/restart.go | 4 +- api/pipeline/create.go | 3 +- api/pipeline/delete.go | 3 +- api/pipeline/list.go | 3 +- api/pipeline/update.go | 3 +- api/webhook/post.go | 4 +- cmd/vela-server/schedule.go | 4 +- database/integration_test.go | 18 ++++---- database/pipeline/count.go | 4 +- database/pipeline/count_repo.go | 4 +- database/pipeline/count_repo_test.go | 7 +-- database/pipeline/count_test.go | 7 +-- database/pipeline/create.go | 4 +- database/pipeline/create_test.go | 3 +- database/pipeline/delete.go | 4 +- database/pipeline/delete_test.go | 5 ++- database/pipeline/get.go | 4 +- database/pipeline/get_repo.go | 4 +- database/pipeline/get_repo_test.go | 5 ++- database/pipeline/get_test.go | 5 ++- database/pipeline/index.go | 4 +- database/pipeline/index_test.go | 3 +- database/pipeline/interface.go | 24 +++++----- database/pipeline/list.go | 6 ++- database/pipeline/list_repo.go | 6 ++- database/pipeline/list_repo_test.go | 7 +-- database/pipeline/list_test.go | 7 +-- database/pipeline/opts.go | 11 +++++ database/pipeline/opts_test.go | 50 +++++++++++++++++++++ database/pipeline/pipeline.go | 8 +++- database/pipeline/pipeline_test.go | 4 ++ database/pipeline/table.go | 8 +++- database/pipeline/table_test.go | 3 +- database/pipeline/update.go | 4 +- database/pipeline/update_test.go | 5 ++- database/resource.go | 1 + router/middleware/pipeline/pipeline.go | 3 +- router/middleware/pipeline/pipeline_test.go | 4 +- 39 files changed, 186 insertions(+), 74 deletions(-) diff --git a/api/build/create.go b/api/build/create.go index 0591945e5..ee0d0f64b 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -232,7 +232,7 @@ func CreateBuild(c *gin.Context) { ) // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(input.GetCommit(), r) + pipeline, err = database.FromContext(c).GetPipelineForRepo(ctx, input.GetCommit(), r) if err != nil { // assume the pipeline doesn't exist in the database yet // send API call to capture the pipeline configuration file config, err = scm.FromContext(c).ConfigBackoff(u, r, input.GetCommit()) @@ -309,7 +309,7 @@ func CreateBuild(c *gin.Context) { pipeline.SetRef(input.GetRef()) // send API call to create the pipeline - pipeline, err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(ctx, pipeline) if err != nil { retErr := fmt.Errorf("unable to create new build: failed to create pipeline for %s: %w", r.GetFullName(), err) diff --git a/api/build/restart.go b/api/build/restart.go index 63847d2d3..804ad88bd 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -223,7 +223,7 @@ func RestartBuild(c *gin.Context) { ) // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), r) + pipeline, err = database.FromContext(c).GetPipelineForRepo(ctx, b.GetCommit(), r) if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) // send API call to capture the pipeline configuration file config, err = scm.FromContext(c).ConfigBackoff(u, r, b.GetCommit()) @@ -300,7 +300,7 @@ func RestartBuild(c *gin.Context) { pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - pipeline, err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(ctx, pipeline) if err != nil { retErr := fmt.Errorf("unable to create pipeline for %s: %w", r.GetFullName(), err) diff --git a/api/pipeline/create.go b/api/pipeline/create.go index f6a4938bc..87bfb6634 100644 --- a/api/pipeline/create.go +++ b/api/pipeline/create.go @@ -70,6 +70,7 @@ func CreatePipeline(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -98,7 +99,7 @@ func CreatePipeline(c *gin.Context) { input.SetRepoID(r.GetID()) // send API call to create the pipeline - p, err := database.FromContext(c).CreatePipeline(input) + p, err := database.FromContext(c).CreatePipeline(ctx, input) if err != nil { retErr := fmt.Errorf("unable to create pipeline %s/%s: %w", r.GetFullName(), input.GetCommit(), err) diff --git a/api/pipeline/delete.go b/api/pipeline/delete.go index da8b0ecf1..1012b3094 100644 --- a/api/pipeline/delete.go +++ b/api/pipeline/delete.go @@ -65,6 +65,7 @@ func DeletePipeline(c *gin.Context) { p := pipeline.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) @@ -79,7 +80,7 @@ func DeletePipeline(c *gin.Context) { }).Infof("deleting pipeline %s", entry) // send API call to remove the build - err := database.FromContext(c).DeletePipeline(p) + err := database.FromContext(c).DeletePipeline(ctx, p) if err != nil { retErr := fmt.Errorf("unable to delete pipeline %s: %w", entry, err) diff --git a/api/pipeline/list.go b/api/pipeline/list.go index a2582eb08..a43f33788 100644 --- a/api/pipeline/list.go +++ b/api/pipeline/list.go @@ -80,6 +80,7 @@ func ListPipelines(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -117,7 +118,7 @@ func ListPipelines(c *gin.Context) { //nolint:gomnd // ignore magic number perPage = util.MaxInt(1, util.MinInt(100, perPage)) - p, t, err := database.FromContext(c).ListPipelinesForRepo(r, page, perPage) + p, t, err := database.FromContext(c).ListPipelinesForRepo(ctx, r, page, perPage) if err != nil { retErr := fmt.Errorf("unable to list pipelines for repo %s: %w", r.GetFullName(), err) diff --git a/api/pipeline/update.go b/api/pipeline/update.go index 9c10d40b6..8c349f5bb 100644 --- a/api/pipeline/update.go +++ b/api/pipeline/update.go @@ -72,6 +72,7 @@ func UpdatePipeline(c *gin.Context) { p := pipeline.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() entry := fmt.Sprintf("%s/%s", r.GetFullName(), p.GetCommit()) @@ -170,7 +171,7 @@ func UpdatePipeline(c *gin.Context) { } // send API call to update the pipeline - p, err = database.FromContext(c).UpdatePipeline(p) + p, err = database.FromContext(c).UpdatePipeline(ctx, p) if err != nil { retErr := fmt.Errorf("unable to update pipeline %s: %w", entry, err) diff --git a/api/webhook/post.go b/api/webhook/post.go index 8d5ca369b..ce11a614f 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -427,7 +427,7 @@ func PostWebhook(c *gin.Context) { } // send API call to attempt to capture the pipeline - pipeline, err = database.FromContext(c).GetPipelineForRepo(b.GetCommit(), repo) + pipeline, err = database.FromContext(c).GetPipelineForRepo(ctx, b.GetCommit(), repo) if err != nil { // assume the pipeline doesn't exist in the database yet // send API call to capture the pipeline configuration file config, err = scm.FromContext(c).ConfigBackoff(u, repo, b.GetCommit()) @@ -562,7 +562,7 @@ func PostWebhook(c *gin.Context) { pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - pipeline, err = database.FromContext(c).CreatePipeline(pipeline) + pipeline, err = database.FromContext(c).CreatePipeline(ctx, pipeline) if err != nil { retErr := fmt.Errorf("%s: failed to create pipeline for %s: %w", baseErr, repo.GetFullName(), err) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index 804da21f3..a8d927a1b 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -237,7 +237,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // send API call to attempt to capture the pipeline - pipeline, err = database.GetPipelineForRepo(b.GetCommit(), r) + pipeline, err = database.GetPipelineForRepo(context.TODO(), b.GetCommit(), r) if err != nil { // assume the pipeline doesn't exist in the database yet // send API call to capture the pipeline configuration file config, err = scm.ConfigBackoff(u, r, b.GetCommit()) @@ -326,7 +326,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler pipeline.SetRef(b.GetRef()) // send API call to create the pipeline - pipeline, err = database.CreatePipeline(pipeline) + pipeline, err = database.CreatePipeline(context.TODO(), pipeline) if err != nil { err = fmt.Errorf("failed to create pipeline for %s: %w", r.GetFullName(), err) diff --git a/database/integration_test.go b/database/integration_test.go index d8f8a6e67..d8dede18b 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -664,7 +664,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { // create the pipelines for _, pipeline := range resources.Pipelines { - _, err := db.CreatePipeline(pipeline) + _, err := db.CreatePipeline(context.TODO(), pipeline) if err != nil { t.Errorf("unable to create pipeline %d: %v", pipeline.GetID(), err) } @@ -672,7 +672,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { methods["CreatePipeline"] = true // count the pipelines - count, err := db.CountPipelines() + count, err := db.CountPipelines(context.TODO()) if err != nil { t.Errorf("unable to count pipelines: %v", err) } @@ -682,7 +682,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { methods["CountPipelines"] = true // count the pipelines for a repo - count, err = db.CountPipelinesForRepo(resources.Repos[0]) + count, err = db.CountPipelinesForRepo(context.TODO(), resources.Repos[0]) if err != nil { t.Errorf("unable to count pipelines for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -692,7 +692,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { methods["CountPipelinesForRepo"] = true // list the pipelines - list, err := db.ListPipelines() + list, err := db.ListPipelines(context.TODO()) if err != nil { t.Errorf("unable to list pipelines: %v", err) } @@ -702,7 +702,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { methods["ListPipelines"] = true // list the pipelines for a repo - list, count, err = db.ListPipelinesForRepo(resources.Repos[0], 1, 10) + list, count, err = db.ListPipelinesForRepo(context.TODO(), resources.Repos[0], 1, 10) if err != nil { t.Errorf("unable to list pipelines for repo %d: %v", resources.Repos[0].GetID(), err) } @@ -717,7 +717,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { // lookup the pipelines by name for _, pipeline := range resources.Pipelines { repo := resources.Repos[pipeline.GetRepoID()-1] - got, err := db.GetPipelineForRepo(pipeline.GetCommit(), repo) + got, err := db.GetPipelineForRepo(context.TODO(), pipeline.GetCommit(), repo) if err != nil { t.Errorf("unable to get pipeline %d for repo %d: %v", pipeline.GetID(), repo.GetID(), err) } @@ -730,13 +730,13 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { // update the pipelines for _, pipeline := range resources.Pipelines { pipeline.SetVersion("2") - _, err = db.UpdatePipeline(pipeline) + _, err = db.UpdatePipeline(context.TODO(), pipeline) if err != nil { t.Errorf("unable to update pipeline %d: %v", pipeline.GetID(), err) } // lookup the pipeline by ID - got, err := db.GetPipeline(pipeline.GetID()) + got, err := db.GetPipeline(context.TODO(), pipeline.GetID()) if err != nil { t.Errorf("unable to get pipeline %d by ID: %v", pipeline.GetID(), err) } @@ -749,7 +749,7 @@ func testPipelines(t *testing.T, db Interface, resources *Resources) { // delete the pipelines for _, pipeline := range resources.Pipelines { - err = db.DeletePipeline(pipeline) + err = db.DeletePipeline(context.TODO(), pipeline) if err != nil { t.Errorf("unable to delete pipeline %d: %v", pipeline.GetID(), err) } diff --git a/database/pipeline/count.go b/database/pipeline/count.go index 67845adff..33377d105 100644 --- a/database/pipeline/count.go +++ b/database/pipeline/count.go @@ -5,11 +5,13 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" ) // CountPipelines gets the count of all pipelines from the database. -func (e *engine) CountPipelines() (int64, error) { +func (e *engine) CountPipelines(ctx context.Context) (int64, error) { e.logger.Tracef("getting count of all pipelines from the database") // variable to store query results diff --git a/database/pipeline/count_repo.go b/database/pipeline/count_repo.go index 50de5cae7..a3318a4e6 100644 --- a/database/pipeline/count_repo.go +++ b/database/pipeline/count_repo.go @@ -5,13 +5,15 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/library" "github.com/sirupsen/logrus" ) // CountPipelinesForRepo gets the count of pipelines by repo ID from the database. -func (e *engine) CountPipelinesForRepo(r *library.Repo) (int64, error) { +func (e *engine) CountPipelinesForRepo(ctx context.Context, r *library.Repo) (int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), diff --git a/database/pipeline/count_repo_test.go b/database/pipeline/count_repo_test.go index cc3650d12..0d2469e77 100644 --- a/database/pipeline/count_repo_test.go +++ b/database/pipeline/count_repo_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -42,12 +43,12 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - _, err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(context.TODO(), _pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -76,7 +77,7 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}) + got, err := test.database.CountPipelinesForRepo(context.TODO(), &library.Repo{ID: _pipelineOne.RepoID}) if test.failure { if err == nil { diff --git a/database/pipeline/count_test.go b/database/pipeline/count_test.go index bbc654fb5..6b638420a 100644 --- a/database/pipeline/count_test.go +++ b/database/pipeline/count_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -41,12 +42,12 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - _, err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(context.TODO(), _pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -75,7 +76,7 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CountPipelines() + got, err := test.database.CountPipelines(context.TODO()) if test.failure { if err == nil { diff --git a/database/pipeline/create.go b/database/pipeline/create.go index 424c24c23..04b344c95 100644 --- a/database/pipeline/create.go +++ b/database/pipeline/create.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // CreatePipeline creates a new pipeline in the database. -func (e *engine) CreatePipeline(p *library.Pipeline) (*library.Pipeline, error) { +func (e *engine) CreatePipeline(ctx context.Context, p *library.Pipeline) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "pipeline": p.GetCommit(), }).Tracef("creating pipeline %s in the database", p.GetCommit()) diff --git a/database/pipeline/create_test.go b/database/pipeline/create_test.go index 5a19c7e84..9077dad5e 100644 --- a/database/pipeline/create_test.go +++ b/database/pipeline/create_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -59,7 +60,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.CreatePipeline(_pipeline) + got, err := test.database.CreatePipeline(context.TODO(), _pipeline) if test.failure { if err == nil { diff --git a/database/pipeline/delete.go b/database/pipeline/delete.go index eb03db88c..d473d5d4f 100644 --- a/database/pipeline/delete.go +++ b/database/pipeline/delete.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // DeletePipeline deletes an existing pipeline from the database. -func (e *engine) DeletePipeline(p *library.Pipeline) error { +func (e *engine) DeletePipeline(ctx context.Context, p *library.Pipeline) error { e.logger.WithFields(logrus.Fields{ "pipeline": p.GetCommit(), }).Tracef("deleting pipeline %s from the database", p.GetCommit()) diff --git a/database/pipeline/delete_test.go b/database/pipeline/delete_test.go index 6bef174c7..39e47a7dd 100644 --- a/database/pipeline/delete_test.go +++ b/database/pipeline/delete_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -31,7 +32,7 @@ func TestPipeline_Engine_DeletePipeline(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -57,7 +58,7 @@ func TestPipeline_Engine_DeletePipeline(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.DeletePipeline(_pipeline) + err = test.database.DeletePipeline(context.TODO(), _pipeline) if test.failure { if err == nil { diff --git a/database/pipeline/get.go b/database/pipeline/get.go index e8eb4b23a..17ec6ab78 100644 --- a/database/pipeline/get.go +++ b/database/pipeline/get.go @@ -5,13 +5,15 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // GetPipeline gets a pipeline by ID from the database. -func (e *engine) GetPipeline(id int64) (*library.Pipeline, error) { +func (e *engine) GetPipeline(ctx context.Context, id int64) (*library.Pipeline, error) { e.logger.Tracef("getting pipeline %d from the database", id) // variable to store query results diff --git a/database/pipeline/get_repo.go b/database/pipeline/get_repo.go index 1d431ca10..f165c18eb 100644 --- a/database/pipeline/get_repo.go +++ b/database/pipeline/get_repo.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // GetPipelineForRepo gets a pipeline by number and repo ID from the database. -func (e *engine) GetPipelineForRepo(commit string, r *library.Repo) (*library.Pipeline, error) { +func (e *engine) GetPipelineForRepo(ctx context.Context, commit string, r *library.Repo) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "pipeline": commit, diff --git a/database/pipeline/get_repo_test.go b/database/pipeline/get_repo_test.go index ab810ba5f..67161931d 100644 --- a/database/pipeline/get_repo_test.go +++ b/database/pipeline/get_repo_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -37,7 +38,7 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -66,7 +67,7 @@ func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetPipelineForRepo("48afb5bdc41ad69bf22588491333f7cf71135163", &library.Repo{ID: _pipeline.RepoID}) + got, err := test.database.GetPipelineForRepo(context.TODO(), "48afb5bdc41ad69bf22588491333f7cf71135163", &library.Repo{ID: _pipeline.RepoID}) if test.failure { if err == nil { diff --git a/database/pipeline/get_test.go b/database/pipeline/get_test.go index f7c3565d3..ca6d789f2 100644 --- a/database/pipeline/get_test.go +++ b/database/pipeline/get_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -37,7 +38,7 @@ func TestPipeline_Engine_GetPipeline(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -66,7 +67,7 @@ func TestPipeline_Engine_GetPipeline(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.GetPipeline(1) + got, err := test.database.GetPipeline(context.TODO(), 1) if test.failure { if err == nil { diff --git a/database/pipeline/index.go b/database/pipeline/index.go index 506fddfa8..3189b728d 100644 --- a/database/pipeline/index.go +++ b/database/pipeline/index.go @@ -4,6 +4,8 @@ package pipeline +import "context" + const ( // CreateRepoIDIndex represents a query to create an // index on the pipelines table for the repo_id column. @@ -16,7 +18,7 @@ ON pipelines (repo_id); ) // CreatePipelineIndexes creates the indexes for the pipelines table in the database. -func (e *engine) CreatePipelineIndexes() error { +func (e *engine) CreatePipelineIndexes(ctx context.Context) error { e.logger.Tracef("creating indexes for pipelines table in the database") // create the repo_id column index for the pipelines table diff --git a/database/pipeline/index_test.go b/database/pipeline/index_test.go index 1fa77b7b0..e72b5a593 100644 --- a/database/pipeline/index_test.go +++ b/database/pipeline/index_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestPipeline_Engine_CreatePipelineIndexes(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreatePipelineIndexes() + err := test.database.CreatePipelineIndexes(context.TODO()) if test.failure { if err == nil { diff --git a/database/pipeline/interface.go b/database/pipeline/interface.go index c28c30da8..ae75ebd54 100644 --- a/database/pipeline/interface.go +++ b/database/pipeline/interface.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/library" ) @@ -18,30 +20,30 @@ type PipelineInterface interface { // https://en.wikipedia.org/wiki/Data_definition_language // CreatePipelineIndexes defines a function that creates the indexes for the pipelines table. - CreatePipelineIndexes() error + CreatePipelineIndexes(context.Context) error // CreatePipelineTable defines a function that creates the pipelines table. - CreatePipelineTable(string) error + CreatePipelineTable(context.Context, string) error // Pipeline Data Manipulation Language Functions // // https://en.wikipedia.org/wiki/Data_manipulation_language // CountPipelines defines a function that gets the count of all pipelines. - CountPipelines() (int64, error) + CountPipelines(context.Context) (int64, error) // CountPipelinesForRepo defines a function that gets the count of pipelines by repo ID. - CountPipelinesForRepo(*library.Repo) (int64, error) + CountPipelinesForRepo(context.Context, *library.Repo) (int64, error) // CreatePipeline defines a function that creates a new pipeline. - CreatePipeline(*library.Pipeline) (*library.Pipeline, error) + CreatePipeline(context.Context, *library.Pipeline) (*library.Pipeline, error) // DeletePipeline defines a function that deletes an existing pipeline. - DeletePipeline(*library.Pipeline) error + DeletePipeline(context.Context, *library.Pipeline) error // GetPipeline defines a function that gets a pipeline by ID. - GetPipeline(int64) (*library.Pipeline, error) + GetPipeline(context.Context, int64) (*library.Pipeline, error) // GetPipelineForRepo defines a function that gets a pipeline by commit SHA and repo ID. - GetPipelineForRepo(string, *library.Repo) (*library.Pipeline, error) + GetPipelineForRepo(context.Context, string, *library.Repo) (*library.Pipeline, error) // ListPipelines defines a function that gets a list of all pipelines. - ListPipelines() ([]*library.Pipeline, error) + ListPipelines(context.Context) ([]*library.Pipeline, error) // ListPipelinesForRepo defines a function that gets a list of pipelines by repo ID. - ListPipelinesForRepo(*library.Repo, int, int) ([]*library.Pipeline, int64, error) + ListPipelinesForRepo(context.Context, *library.Repo, int, int) ([]*library.Pipeline, int64, error) // UpdatePipeline defines a function that updates an existing pipeline. - UpdatePipeline(*library.Pipeline) (*library.Pipeline, error) + UpdatePipeline(context.Context, *library.Pipeline) (*library.Pipeline, error) } diff --git a/database/pipeline/list.go b/database/pipeline/list.go index 9159a87aa..54f8015c4 100644 --- a/database/pipeline/list.go +++ b/database/pipeline/list.go @@ -5,13 +5,15 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListPipelines gets a list of all pipelines from the database. -func (e *engine) ListPipelines() ([]*library.Pipeline, error) { +func (e *engine) ListPipelines(ctx context.Context) ([]*library.Pipeline, error) { e.logger.Trace("listing all pipelines from the database") // variables to store query results and return value @@ -20,7 +22,7 @@ func (e *engine) ListPipelines() ([]*library.Pipeline, error) { pipelines := []*library.Pipeline{} // count the results - count, err := e.CountPipelines() + count, err := e.CountPipelines(ctx) if err != nil { return nil, err } diff --git a/database/pipeline/list_repo.go b/database/pipeline/list_repo.go index 609dcc340..e8c38afab 100644 --- a/database/pipeline/list_repo.go +++ b/database/pipeline/list_repo.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -14,7 +16,7 @@ import ( // ListPipelinesForRepo gets a list of pipelines by repo ID from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListPipelinesForRepo(r *library.Repo, page, perPage int) ([]*library.Pipeline, int64, error) { +func (e *engine) ListPipelinesForRepo(ctx context.Context, r *library.Repo, page, perPage int) ([]*library.Pipeline, int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -26,7 +28,7 @@ func (e *engine) ListPipelinesForRepo(r *library.Repo, page, perPage int) ([]*li pipelines := []*library.Pipeline{} // count the results - count, err := e.CountPipelinesForRepo(r) + count, err := e.CountPipelinesForRepo(context.TODO(), r) if err != nil { return pipelines, 0, err } diff --git a/database/pipeline/list_repo_test.go b/database/pipeline/list_repo_test.go index dc64e8a0f..35cc2e769 100644 --- a/database/pipeline/list_repo_test.go +++ b/database/pipeline/list_repo_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -53,12 +54,12 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - _, err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(context.TODO(), _pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -87,7 +88,7 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, _, err := test.database.ListPipelinesForRepo(&library.Repo{ID: _pipelineOne.RepoID}, 1, 10) + got, _, err := test.database.ListPipelinesForRepo(context.TODO(), &library.Repo{ID: _pipelineOne.RepoID}, 1, 10) if test.failure { if err == nil { diff --git a/database/pipeline/list_test.go b/database/pipeline/list_test.go index 36f65199d..e1d14166e 100644 --- a/database/pipeline/list_test.go +++ b/database/pipeline/list_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -53,12 +54,12 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipelineOne) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipelineOne) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } - _, err = _sqlite.CreatePipeline(_pipelineTwo) + _, err = _sqlite.CreatePipeline(context.TODO(), _pipelineTwo) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -87,7 +88,7 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListPipelines() + got, err := test.database.ListPipelines(context.TODO()) if test.failure { if err == nil { diff --git a/database/pipeline/opts.go b/database/pipeline/opts.go index f04796ff7..e4d1e6d46 100644 --- a/database/pipeline/opts.go +++ b/database/pipeline/opts.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -52,3 +54,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine for Pipelines. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/pipeline/opts_test.go b/database/pipeline/opts_test.go index 94822e33b..2380bdda7 100644 --- a/database/pipeline/opts_test.go +++ b/database/pipeline/opts_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -214,3 +215,52 @@ func TestPipeline_EngineOpt_WithSkipCreation(t *testing.T) { }) } } + +func TestPipeline_EngineOpt_WithContext(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + ctx context.Context + want context.Context + }{ + { + failure: false, + name: "context set to TODO", + ctx: context.TODO(), + want: context.TODO(), + }, + { + failure: false, + name: "context set to nil", + ctx: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithContext(test.ctx)(e) + + if test.failure { + if err == nil { + t.Errorf("WithContext for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithContext returned err: %v", err) + } + + if !reflect.DeepEqual(e.ctx, test.want) { + t.Errorf("WithContext is %v, want %v", e.ctx, test.want) + } + }) + } +} diff --git a/database/pipeline/pipeline.go b/database/pipeline/pipeline.go index a48cc6e07..7c9f29d8f 100644 --- a/database/pipeline/pipeline.go +++ b/database/pipeline/pipeline.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -27,6 +28,8 @@ type ( // engine configuration settings used in pipeline functions config *config + ctx context.Context + // gorm.io/gorm database client used in pipeline functions // // https://pkg.go.dev/gorm.io/gorm#DB @@ -50,6 +53,7 @@ func New(opts ...EngineOpt) (*engine, error) { e.client = new(gorm.DB) e.config = new(config) e.logger = new(logrus.Entry) + e.ctx = context.TODO() // apply all provided configuration options for _, opt := range opts { @@ -67,13 +71,13 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the pipelines table - err := e.CreatePipelineTable(e.client.Config.Dialector.Name()) + err := e.CreatePipelineTable(e.ctx, e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TablePipeline, err) } // create the indexes for the pipelines table - err = e.CreatePipelineIndexes() + err = e.CreatePipelineIndexes(e.ctx) if err != nil { return nil, fmt.Errorf("unable to create indexes for %s table: %w", constants.TablePipeline, err) } diff --git a/database/pipeline/pipeline_test.go b/database/pipeline/pipeline_test.go index f478fe37f..13d01393a 100644 --- a/database/pipeline/pipeline_test.go +++ b/database/pipeline/pipeline_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "database/sql/driver" "reflect" "testing" @@ -65,6 +66,7 @@ func TestPipeline_New(t *testing.T) { want: &engine{ client: _postgres, config: &config{CompressionLevel: 1, SkipCreation: false}, + ctx: context.TODO(), logger: logger, }, }, @@ -78,6 +80,7 @@ func TestPipeline_New(t *testing.T) { want: &engine{ client: _sqlite, config: &config{CompressionLevel: 1, SkipCreation: false}, + ctx: context.TODO(), logger: logger, }, }, @@ -87,6 +90,7 @@ func TestPipeline_New(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { got, err := New( + WithContext(context.TODO()), WithClient(test.client), WithCompressionLevel(test.level), WithLogger(test.logger), diff --git a/database/pipeline/table.go b/database/pipeline/table.go index bc463da68..eef8b885a 100644 --- a/database/pipeline/table.go +++ b/database/pipeline/table.go @@ -4,7 +4,11 @@ package pipeline -import "github.com/go-vela/types/constants" +import ( + "context" + + "github.com/go-vela/types/constants" +) const ( // CreatePostgresTable represents a query to create the Postgres pipelines table. @@ -57,7 +61,7 @@ pipelines ( ) // CreatePipelineTable creates the pipelines table in the database. -func (e *engine) CreatePipelineTable(driver string) error { +func (e *engine) CreatePipelineTable(ctx context.Context, driver string) error { e.logger.Tracef("creating pipelines table in the database") // handle the driver provided to create the table diff --git a/database/pipeline/table_test.go b/database/pipeline/table_test.go index 5b05e4313..72add7aee 100644 --- a/database/pipeline/table_test.go +++ b/database/pipeline/table_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestPipeline_Engine_CreatePipelineTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreatePipelineTable(test.name) + err := test.database.CreatePipelineTable(context.TODO(), test.name) if test.failure { if err == nil { diff --git a/database/pipeline/update.go b/database/pipeline/update.go index 59b552164..64d9dd561 100644 --- a/database/pipeline/update.go +++ b/database/pipeline/update.go @@ -5,6 +5,8 @@ package pipeline import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // UpdatePipeline updates an existing pipeline in the database. -func (e *engine) UpdatePipeline(p *library.Pipeline) (*library.Pipeline, error) { +func (e *engine) UpdatePipeline(ctx context.Context, p *library.Pipeline) (*library.Pipeline, error) { e.logger.WithFields(logrus.Fields{ "pipeline": p.GetCommit(), }).Tracef("updating pipeline %s in the database", p.GetCommit()) diff --git a/database/pipeline/update_test.go b/database/pipeline/update_test.go index d321d63b5..f8ab6b3d3 100644 --- a/database/pipeline/update_test.go +++ b/database/pipeline/update_test.go @@ -5,6 +5,7 @@ package pipeline import ( + "context" "reflect" "testing" @@ -35,7 +36,7 @@ WHERE "id" = $15`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - _, err := _sqlite.CreatePipeline(_pipeline) + _, err := _sqlite.CreatePipeline(context.TODO(), _pipeline) if err != nil { t.Errorf("unable to create test pipeline for sqlite: %v", err) } @@ -61,7 +62,7 @@ WHERE "id" = $15`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.UpdatePipeline(_pipeline) + got, err := test.database.UpdatePipeline(context.TODO(), _pipeline) if test.failure { if err == nil { diff --git a/database/resource.go b/database/resource.go index a2e177353..e6784b2e1 100644 --- a/database/resource.go +++ b/database/resource.go @@ -58,6 +58,7 @@ func (e *engine) NewResources(ctx context.Context) error { // create the database agnostic engine for pipelines e.PipelineInterface, err = pipeline.New( + pipeline.WithContext(e.ctx), pipeline.WithClient(e.client), pipeline.WithCompressionLevel(e.config.CompressionLevel), pipeline.WithLogger(e.logger), diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go index 1910e2c0f..b3f2e57af 100644 --- a/router/middleware/pipeline/pipeline.go +++ b/router/middleware/pipeline/pipeline.go @@ -32,6 +32,7 @@ func Establish() gin.HandlerFunc { o := org.Retrieve(c) r := repo.Retrieve(c) u := user.Retrieve(c) + ctx := c.Request.Context() if r == nil { retErr := fmt.Errorf("repo %s/%s not found", util.PathParameter(c, "org"), util.PathParameter(c, "repo")) @@ -62,7 +63,7 @@ func Establish() gin.HandlerFunc { "user": u.GetName(), }).Debugf("reading pipeline %s", entry) - pipeline, err := database.FromContext(c).GetPipelineForRepo(p, r) + pipeline, err := database.FromContext(c).GetPipelineForRepo(ctx, p, r) if err != nil { // assume the pipeline doesn't exist in the database yet (before pipeline support was added) // send API call to capture the pipeline configuration file config, err := scm.FromContext(c).ConfigBackoff(u, r, p) diff --git a/router/middleware/pipeline/pipeline_test.go b/router/middleware/pipeline/pipeline_test.go index ff410c1da..0fc1e8b29 100644 --- a/router/middleware/pipeline/pipeline_test.go +++ b/router/middleware/pipeline/pipeline_test.go @@ -103,13 +103,13 @@ func TestPipeline_Establish(t *testing.T) { } defer func() { - db.DeletePipeline(want) + db.DeletePipeline(context.TODO(), want) db.DeleteRepo(context.TODO(), r) db.Close() }() _, _ = db.CreateRepo(context.TODO(), r) - _, _ = db.CreatePipeline(want) + _, _ = db.CreatePipeline(context.TODO(), want) // setup context gin.SetMode(gin.TestMode) From ee0d2a0ff64fc5774cbc31e0e4c54bdfe79feaf6 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:57:15 -0600 Subject: [PATCH 291/298] refactor(db): return service on created and updated (#932) --- api/admin/service.go | 4 ++-- api/build/cancel.go | 2 +- api/build/clean.go | 2 +- api/service/create.go | 5 +---- api/service/plan.go | 8 +------- api/service/update.go | 5 +---- database/integration_test.go | 11 +++-------- database/service/clean_test.go | 8 ++++---- database/service/count_build_test.go | 4 ++-- database/service/count_test.go | 4 ++-- database/service/create.go | 11 +++++------ database/service/create_test.go | 7 ++++++- database/service/delete_test.go | 2 +- database/service/get_build_test.go | 2 +- database/service/get_test.go | 2 +- database/service/interface.go | 4 ++-- database/service/list_build_test.go | 4 ++-- database/service/list_image_test.go | 4 ++-- database/service/list_status_test.go | 4 ++-- database/service/list_test.go | 4 ++-- database/service/update.go | 11 +++++------ database/service/update_test.go | 9 +++++++-- router/middleware/service/service_test.go | 2 +- 23 files changed, 55 insertions(+), 64 deletions(-) diff --git a/api/admin/service.go b/api/admin/service.go index 2cd295c4c..24ddae3dc 100644 --- a/api/admin/service.go +++ b/api/admin/service.go @@ -67,7 +67,7 @@ func UpdateService(c *gin.Context) { } // send API call to update the service - err = database.FromContext(c).UpdateService(input) + s, err := database.FromContext(c).UpdateService(input) if err != nil { retErr := fmt.Errorf("unable to update service %d: %w", input.GetID(), err) @@ -76,5 +76,5 @@ func UpdateService(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, s) } diff --git a/api/build/cancel.go b/api/build/cancel.go index 923d2eb77..d8d4e6c06 100644 --- a/api/build/cancel.go +++ b/api/build/cancel.go @@ -272,7 +272,7 @@ func CancelBuild(c *gin.Context) { if service.GetStatus() == constants.StatusRunning || service.GetStatus() == constants.StatusPending { service.SetStatus(constants.StatusCanceled) - err = database.FromContext(c).UpdateService(service) + _, err = database.FromContext(c).UpdateService(service) if err != nil { retErr := fmt.Errorf("unable to update service %s for build %s: %w", service.GetName(), diff --git a/api/build/clean.go b/api/build/clean.go index 8344694b7..a93a9355c 100644 --- a/api/build/clean.go +++ b/api/build/clean.go @@ -37,7 +37,7 @@ func CleanBuild(ctx context.Context, database database.Interface, b *library.Bui s.SetFinished(time.Now().UTC().Unix()) // send API call to update the service - err := database.UpdateService(s) + _, err := database.UpdateService(s) if err != nil { logrus.Errorf("unable to kill service %s for build %d: %v", s.GetName(), b.GetNumber(), err) } diff --git a/api/service/create.go b/api/service/create.go index 426f13760..2dcccbd26 100644 --- a/api/service/create.go +++ b/api/service/create.go @@ -112,7 +112,7 @@ func CreateService(c *gin.Context) { } // send API call to create the service - err = database.FromContext(c).CreateService(input) + s, err := database.FromContext(c).CreateService(input) if err != nil { retErr := fmt.Errorf("unable to create service for build %s: %w", entry, err) @@ -121,8 +121,5 @@ func CreateService(c *gin.Context) { return } - // send API call to capture the created service - s, _ := database.FromContext(c).GetServiceForBuild(b, input.GetNumber()) - c.JSON(http.StatusCreated, s) } diff --git a/api/service/plan.go b/api/service/plan.go index 4912f38d1..a0200767e 100644 --- a/api/service/plan.go +++ b/api/service/plan.go @@ -34,17 +34,11 @@ func PlanServices(database database.Interface, p *pipeline.Build, b *library.Bui s.SetCreated(time.Now().UTC().Unix()) // send API call to create the service - err := database.CreateService(s) + s, err := database.CreateService(s) if err != nil { return services, fmt.Errorf("unable to create service %s: %w", s.GetName(), err) } - // send API call to capture the created service - s, err = database.GetServiceForBuild(b, s.GetNumber()) - if err != nil { - return services, fmt.Errorf("unable to get service %s: %w", s.GetName(), err) - } - // populate environment variables from service library // // https://pkg.go.dev/github.com/go-vela/types/library#Service.Environment diff --git a/api/service/update.go b/api/service/update.go index bed781f88..7c1a5859f 100644 --- a/api/service/update.go +++ b/api/service/update.go @@ -133,7 +133,7 @@ func UpdateService(c *gin.Context) { } // send API call to update the service - err = database.FromContext(c).UpdateService(s) + s, err = database.FromContext(c).UpdateService(s) if err != nil { retErr := fmt.Errorf("unable to update service %s: %w", entry, err) @@ -142,8 +142,5 @@ func UpdateService(c *gin.Context) { return } - // send API call to capture the updated service - s, _ = database.FromContext(c).GetServiceForBuild(b, s.GetNumber()) - c.JSON(http.StatusOK, s) } diff --git a/database/integration_test.go b/database/integration_test.go index d8dede18b..cd4e3f9a7 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -1275,7 +1275,7 @@ func testServices(t *testing.T, db Interface, resources *Resources) { // create the services for _, service := range resources.Services { - err := db.CreateService(service) + _, err := db.CreateService(service) if err != nil { t.Errorf("unable to create service %d: %v", service.GetID(), err) } @@ -1380,18 +1380,13 @@ func testServices(t *testing.T, db Interface, resources *Resources) { // update the services for _, service := range resources.Services { service.SetStatus("success") - err = db.UpdateService(service) + got, err := db.UpdateService(service) if err != nil { t.Errorf("unable to update service %d: %v", service.GetID(), err) } - // lookup the service by ID - got, err := db.GetService(service.GetID()) - if err != nil { - t.Errorf("unable to get service %d by ID: %v", service.GetID(), err) - } if !reflect.DeepEqual(got, service) { - t.Errorf("GetService() is %v, want %v", got, service) + t.Errorf("UpdateService() is %v, want %v", got, service) } } methods["UpdateService"] = true diff --git a/database/service/clean_test.go b/database/service/clean_test.go index 3bd9baf15..17301e119 100644 --- a/database/service/clean_test.go +++ b/database/service/clean_test.go @@ -64,22 +64,22 @@ func TestService_Engine_CleanService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceThree) + _, err = _sqlite.CreateService(_serviceThree) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceFour) + _, err = _sqlite.CreateService(_serviceFour) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/count_build_test.go b/database/service/count_build_test.go index 08c964da7..160dfa5f8 100644 --- a/database/service/count_build_test.go +++ b/database/service/count_build_test.go @@ -46,12 +46,12 @@ func TestService_Engine_CountServicesForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/count_test.go b/database/service/count_test.go index 226d4b879..4152c18e9 100644 --- a/database/service/count_test.go +++ b/database/service/count_test.go @@ -41,12 +41,12 @@ func TestService_Engine_CountServices(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/create.go b/database/service/create.go index 56574e23b..f748be077 100644 --- a/database/service/create.go +++ b/database/service/create.go @@ -12,7 +12,7 @@ import ( ) // CreateService creates a new service in the database. -func (e *engine) CreateService(s *library.Service) error { +func (e *engine) CreateService(s *library.Service) (*library.Service, error) { e.logger.WithFields(logrus.Fields{ "service": s.GetNumber(), }).Tracef("creating service %s in the database", s.GetName()) @@ -27,12 +27,11 @@ func (e *engine) CreateService(s *library.Service) error { // https://pkg.go.dev/github.com/go-vela/types/database#Service.Validate err := service.Validate() if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TableService). - Create(service). - Error + result := e.client.Table(constants.TableService).Create(service) + + return service.ToLibrary(), result.Error } diff --git a/database/service/create_test.go b/database/service/create_test.go index 4e84ed090..26771f31c 100644 --- a/database/service/create_test.go +++ b/database/service/create_test.go @@ -5,6 +5,7 @@ package service import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -57,7 +58,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateService(_service) + got, err := test.database.CreateService(_service) if test.failure { if err == nil { @@ -70,6 +71,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) RETURNING "id"`). if err != nil { t.Errorf("CreateService for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _service) { + t.Errorf("CreateService for %s returned %s, want %s", test.name, got, _service) + } }) } } diff --git a/database/service/delete_test.go b/database/service/delete_test.go index d63c55c05..04d08fdc8 100644 --- a/database/service/delete_test.go +++ b/database/service/delete_test.go @@ -31,7 +31,7 @@ func TestService_Engine_DeleteService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_service) + _, err := _sqlite.CreateService(_service) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/get_build_test.go b/database/service/get_build_test.go index 36747ad65..4b6a629de 100644 --- a/database/service/get_build_test.go +++ b/database/service/get_build_test.go @@ -41,7 +41,7 @@ func TestService_Engine_GetServiceForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_service) + _, err := _sqlite.CreateService(_service) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/get_test.go b/database/service/get_test.go index 13bd6691a..1c2734b36 100644 --- a/database/service/get_test.go +++ b/database/service/get_test.go @@ -36,7 +36,7 @@ func TestService_Engine_GetService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_service) + _, err := _sqlite.CreateService(_service) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/interface.go b/database/service/interface.go index d22595859..0a05c626d 100644 --- a/database/service/interface.go +++ b/database/service/interface.go @@ -31,7 +31,7 @@ type ServiceInterface interface { // CountServicesForBuild defines a function that gets the count of services by build ID. CountServicesForBuild(*library.Build, map[string]interface{}) (int64, error) // CreateService defines a function that creates a new service. - CreateService(*library.Service) error + CreateService(*library.Service) (*library.Service, error) // DeleteService defines a function that deletes an existing service. DeleteService(*library.Service) error // GetService defines a function that gets a service by ID. @@ -47,5 +47,5 @@ type ServiceInterface interface { // ListServiceStatusCount defines a function that gets a list of all service statuses and the count of their occurrence. ListServiceStatusCount() (map[string]float64, error) // UpdateService defines a function that updates an existing service. - UpdateService(*library.Service) error + UpdateService(*library.Service) (*library.Service, error) } diff --git a/database/service/list_build_test.go b/database/service/list_build_test.go index 3b6d97161..1f0a860f4 100644 --- a/database/service/list_build_test.go +++ b/database/service/list_build_test.go @@ -56,12 +56,12 @@ func TestService_Engine_ListServicesForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/list_image_test.go b/database/service/list_image_test.go index f4e2f228e..8f0d588d0 100644 --- a/database/service/list_image_test.go +++ b/database/service/list_image_test.go @@ -41,12 +41,12 @@ func TestService_Engine_ListServiceImageCount(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/list_status_test.go b/database/service/list_status_test.go index 85b7808af..d1cb46649 100644 --- a/database/service/list_status_test.go +++ b/database/service/list_status_test.go @@ -46,12 +46,12 @@ func TestService_Engine_ListServiceStatusCount(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/list_test.go b/database/service/list_test.go index 72b60d5cf..a7351a8b6 100644 --- a/database/service/list_test.go +++ b/database/service/list_test.go @@ -51,12 +51,12 @@ func TestService_Engine_ListServices(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_serviceOne) + _, err := _sqlite.CreateService(_serviceOne) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } - err = _sqlite.CreateService(_serviceTwo) + _, err = _sqlite.CreateService(_serviceTwo) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } diff --git a/database/service/update.go b/database/service/update.go index ceaa7b6b8..d9b0bd595 100644 --- a/database/service/update.go +++ b/database/service/update.go @@ -12,7 +12,7 @@ import ( ) // UpdateService updates an existing service in the database. -func (e *engine) UpdateService(s *library.Service) error { +func (e *engine) UpdateService(s *library.Service) (*library.Service, error) { e.logger.WithFields(logrus.Fields{ "service": s.GetNumber(), }).Tracef("updating service %s in the database", s.GetName()) @@ -27,12 +27,11 @@ func (e *engine) UpdateService(s *library.Service) error { // https://pkg.go.dev/github.com/go-vela/types/database#Service.Validate err := service.Validate() if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TableService). - Save(service). - Error + result := e.client.Table(constants.TableService).Save(service) + + return service.ToLibrary(), result.Error } diff --git a/database/service/update_test.go b/database/service/update_test.go index e9fe61955..12979dce9 100644 --- a/database/service/update_test.go +++ b/database/service/update_test.go @@ -5,6 +5,7 @@ package service import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -31,7 +32,7 @@ func TestService_Engine_UpdateService(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateService(_service) + _, err := _sqlite.CreateService(_service) if err != nil { t.Errorf("unable to create test service for sqlite: %v", err) } @@ -57,7 +58,7 @@ func TestService_Engine_UpdateService(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateService(_service) + got, err := test.database.UpdateService(_service) if test.failure { if err == nil { @@ -70,6 +71,10 @@ func TestService_Engine_UpdateService(t *testing.T) { if err != nil { t.Errorf("UpdateService for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _service) { + t.Errorf("UpdateService for %s returned %s, want %s", test.name, got, _service) + } }) } } diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index d900394b7..70a8024c3 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -87,7 +87,7 @@ func TestService_Establish(t *testing.T) { _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) - _ = db.CreateService(want) + _, _ = db.CreateService(want) // setup context gin.SetMode(gin.TestMode) From 6874831153a63b72c3409ecfc97c29909089a9b5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:32:01 -0400 Subject: [PATCH 292/298] feat(queuing)!: build executable server-side implementation (#927) * init commit * adding db tests * compiled to build itinerary * add mock * itinerary -> executable * fix mock * update some extra db configs * pull in updated types * encrypt and decrypt * Update database/executable/interface.go Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> * pesky linter * add integration test for executables * try this * with encryption resource opt * Update database/executable/opts.go Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> --------- Co-authored-by: dave vader <48764154+plyr4@users.noreply.github.com> Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/build/executable.go | 93 +++++++++ api/build/publish.go | 26 ++- database/database.go | 2 + database/executable/create.go | 56 ++++++ database/executable/create_test.go | 71 +++++++ database/executable/executable.go | 80 ++++++++ database/executable/executable_test.go | 213 ++++++++++++++++++++ database/executable/interface.go | 25 +++ database/executable/opts.go | 74 +++++++ database/executable/opts_test.go | 265 +++++++++++++++++++++++++ database/executable/pop.go | 78 ++++++++ database/executable/pop_test.go | 84 ++++++++ database/executable/table.go | 50 +++++ database/executable/table_test.go | 59 ++++++ database/integration_test.go | 62 ++++++ database/interface.go | 4 + database/resource.go | 13 ++ database/resource_test.go | 3 + go.mod | 2 +- go.sum | 4 +- mock/server/build.go | 32 +++ mock/server/server.go | 1 + queue/redis/length_test.go | 7 +- queue/redis/pop_test.go | 7 +- queue/redis/push_test.go | 7 +- router/build.go | 2 + 26 files changed, 1304 insertions(+), 16 deletions(-) create mode 100644 api/build/executable.go create mode 100644 database/executable/create.go create mode 100644 database/executable/create_test.go create mode 100644 database/executable/executable.go create mode 100644 database/executable/executable_test.go create mode 100644 database/executable/interface.go create mode 100644 database/executable/opts.go create mode 100644 database/executable/opts_test.go create mode 100644 database/executable/pop.go create mode 100644 database/executable/pop_test.go create mode 100644 database/executable/table.go create mode 100644 database/executable/table_test.go diff --git a/api/build/executable.go b/api/build/executable.go new file mode 100644 index 000000000..832e5abeb --- /dev/null +++ b/api/build/executable.go @@ -0,0 +1,93 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package build + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" + "github.com/go-vela/server/router/middleware/build" + "github.com/go-vela/server/router/middleware/claims" + "github.com/go-vela/server/router/middleware/org" + "github.com/go-vela/server/router/middleware/repo" + "github.com/go-vela/server/util" + "github.com/sirupsen/logrus" +) + +// swagger:operation GET /api/v1/repos/{org}/{repo}/builds/{build}/executable builds GetBuildExecutable +// +// Get a build executable in the configured backend +// +// --- +// produces: +// - application/json +// parameters: +// - in: path +// name: org +// description: Name of the org +// required: true +// type: string +// - in: path +// name: repo +// description: Name of the repo +// required: true +// type: string +// - in: path +// name: build +// description: Build number to retrieve +// required: true +// type: integer +// security: +// - ApiKeyAuth: [] +// responses: +// '200': +// description: Successfully retrieved the build executable +// type: json +// schema: +// "$ref": "#/definitions/Build" +// '400': +// description: Bad request +// schema: +// "$ref": "#/definitions/Error" +// '401': +// description: Unauthorized +// schema: +// "$ref": "#/definitions/Error" +// '500': +// description: Could not retrieve build executable +// schema: +// "$ref": "#/definitions/Error" + +// GetBuildExecutable represents the API handler to capture +// a build executable for a repo from the configured backend. +func GetBuildExecutable(c *gin.Context) { + // capture middleware values + b := build.Retrieve(c) + o := org.Retrieve(c) + r := repo.Retrieve(c) + cl := claims.Retrieve(c) + + // update engine logger with API metadata + // + // https://pkg.go.dev/github.com/sirupsen/logrus?tab=doc#Entry.WithFields + logrus.WithFields(logrus.Fields{ + "build": b.GetNumber(), + "org": o, + "repo": r.GetName(), + "subject": cl.Subject, + }).Infof("reading build executable %s/%d", r.GetFullName(), b.GetNumber()) + + bExecutable, err := database.FromContext(c).PopBuildExecutable(b.GetID()) + if err != nil { + retErr := fmt.Errorf("unable to pop build executable: %w", err) + util.HandleError(c, http.StatusInternalServerError, retErr) + + return + } + + c.JSON(http.StatusOK, bExecutable) +} diff --git a/api/build/publish.go b/api/build/publish.go index 7e1b3d5a3..f5e144232 100644 --- a/api/build/publish.go +++ b/api/build/publish.go @@ -20,7 +20,31 @@ import ( // PublishToQueue is a helper function that creates // a build item and publishes it to the queue. func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { - item := types.ToItem(p, b, r, u) + byteExecutable, err := json.Marshal(p) + if err != nil { + logrus.Errorf("Failed to marshal build executable %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + // error out the build + CleanBuild(ctx, db, b, nil, nil, err) + + return + } + + bExecutable := new(library.BuildExecutable) + bExecutable.SetBuildID(b.GetID()) + bExecutable.SetData(byteExecutable) + + err = db.CreateBuildExecutable(bExecutable) + if err != nil { + logrus.Errorf("Failed to publish build executable to database %d for %s: %v", b.GetNumber(), r.GetFullName(), err) + + // error out the build + CleanBuild(ctx, db, b, nil, nil, err) + + return + } + + item := types.ToItem(b, r, u) logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) diff --git a/database/database.go b/database/database.go index d0317e3ff..ea93bfaaf 100644 --- a/database/database.go +++ b/database/database.go @@ -10,6 +10,7 @@ import ( "time" "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/executable" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -61,6 +62,7 @@ type ( logger *logrus.Entry build.BuildInterface + executable.BuildExecutableInterface hook.HookInterface log.LogInterface pipeline.PipelineInterface diff --git a/database/executable/create.go b/database/executable/create.go new file mode 100644 index 000000000..002ac03bc --- /dev/null +++ b/database/executable/create.go @@ -0,0 +1,56 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" +) + +// CreateBuildExecutable creates a new build executable in the database. +func (e *engine) CreateBuildExecutable(b *library.BuildExecutable) error { + e.logger.WithFields(logrus.Fields{ + "build": b.GetBuildID(), + }).Tracef("creating build executable for build %d in the database", b.GetBuildID()) + + // cast the library type to database type + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutableFromLibrary + executable := database.BuildExecutableFromLibrary(b) + + // validate the necessary fields are populated + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutable.Validate + err := executable.Validate() + if err != nil { + return err + } + + // compress data for the build executable + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutable.Compress + err = executable.Compress(e.config.CompressionLevel) + if err != nil { + return err + } + + // encrypt the data field for the build executable + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutable.Encrypt + err = executable.Encrypt(e.config.EncryptionKey) + if err != nil { + return fmt.Errorf("unable to encrypt build executable for build %d: %w", b.GetBuildID(), err) + } + + // send query to the database + return e.client. + Table(constants.TableBuildExecutable). + Create(executable). + Error +} diff --git a/database/executable/create_test.go b/database/executable/create_test.go new file mode 100644 index 000000000..abf047f79 --- /dev/null +++ b/database/executable/create_test.go @@ -0,0 +1,71 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestExecutable_Engine_CreateBuildExecutable(t *testing.T) { + // setup types + _bExecutable := testBuildExecutable() + _bExecutable.SetID(1) + _bExecutable.SetBuildID(1) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows([]string{"id"}).AddRow(1) + + // ensure the mock expects the query + _mock.ExpectQuery(`INSERT INTO "build_executables" +("build_id","data","id") +VALUES ($1,$2,$3) RETURNING "id"`). + WithArgs(1, AnyArgument{}, 1). + WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateBuildExecutable(_bExecutable) + + if test.failure { + if err == nil { + t.Errorf("CreateBuildExecutable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateBuildExecutable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/executable/executable.go b/database/executable/executable.go new file mode 100644 index 000000000..c53759192 --- /dev/null +++ b/database/executable/executable.go @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "fmt" + + "github.com/go-vela/types/constants" + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +type ( + // config represents the settings required to create the engine that implements the BuildExecutableService interface. + config struct { + // specifies the level of compression to use for the BuildExecutable engine + CompressionLevel int + // specifies the encryption key to use for the BuildExecutable engine + EncryptionKey string + // specifies to skip creating tables and indexes for the BuildExecutable engine + SkipCreation bool + // specifies the driver for proper popping query + Driver string + } + + // engine represents the build executable functionality that implements the BuildExecutableService interface. + engine struct { + // engine configuration settings used in build executable functions + config *config + + // gorm.io/gorm database client used in build executable functions + // + // https://pkg.go.dev/gorm.io/gorm#DB + client *gorm.DB + + // sirupsen/logrus logger used in build executable functions + // + // https://pkg.go.dev/github.com/sirupsen/logrus#Entry + logger *logrus.Entry + } +) + +// New creates and returns a Vela service for integrating with build executables in the database. +// +//nolint:revive // ignore returning unexported engine +func New(opts ...EngineOpt) (*engine, error) { + // create new BuildExecutable engine + e := new(engine) + + // create new fields + e.client = new(gorm.DB) + e.config = new(config) + e.logger = new(logrus.Entry) + + // apply all provided configuration options + for _, opt := range opts { + err := opt(e) + if err != nil { + return nil, err + } + } + + // check if we should skip creating build executable database objects + if e.config.SkipCreation { + e.logger.Warning("skipping creation of build executables table and indexes in the database") + + return e, nil + } + + // create the build executables table + err := e.CreateBuildExecutableTable(e.client.Config.Dialector.Name()) + if err != nil { + return nil, fmt.Errorf("unable to create %s table: %w", constants.TableBuildExecutable, err) + } + + return e, nil +} diff --git a/database/executable/executable_test.go b/database/executable/executable_test.go new file mode 100644 index 000000000..20ebd6b49 --- /dev/null +++ b/database/executable/executable_test.go @@ -0,0 +1,213 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "database/sql/driver" + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/sirupsen/logrus" + + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func TestExecutable_New(t *testing.T) { + // setup types + logger := logrus.NewEntry(logrus.StandardLogger()) + + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + defer _sql.Close() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _config := &gorm.Config{SkipDefaultTransaction: true} + + _postgres, err := gorm.Open(postgres.New(postgres.Config{Conn: _sql}), _config) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _sqlite, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), _config) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + defer func() { _sql, _ := _sqlite.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + level int + key string + logger *logrus.Entry + skipCreation bool + want *engine + }{ + { + failure: false, + name: "postgres", + client: _postgres, + level: 1, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _postgres, + config: &config{ + CompressionLevel: 1, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + Driver: "postgres", + }, + logger: logger, + }, + }, + { + failure: false, + name: "sqlite3", + client: _sqlite, + level: 1, + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + logger: logger, + skipCreation: false, + want: &engine{ + client: _sqlite, + config: &config{ + CompressionLevel: 1, + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + Driver: "sqlite3", + }, + logger: logger, + }, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := New( + WithClient(test.client), + WithCompressionLevel(test.level), + WithEncryptionKey(test.key), + WithLogger(test.logger), + WithSkipCreation(test.skipCreation), + WithDriver(test.name), + ) + + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("New for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} + +// 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 + // + // https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#New + _sql, _mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual)) + if err != nil { + t.Errorf("unable to create new SQL mock: %v", err) + } + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + // create the new mock Postgres database client + // + // https://pkg.go.dev/gorm.io/gorm#Open + _postgres, err := gorm.Open( + postgres.New(postgres.Config{Conn: _sql}), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new postgres database: %v", err) + } + + _engine, err := New( + WithClient(_postgres), + WithCompressionLevel(0), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + WithDriver(constants.DriverPostgres), + ) + if err != nil { + t.Errorf("unable to create new postgres build_itnerary engine: %v", err) + } + + return _engine, _mock +} + +// testSqlite is a helper function to create a Sqlite engine for testing. +func testSqlite(t *testing.T) *engine { + _sqlite, err := gorm.Open( + sqlite.Open("file::memory:?cache=shared"), + &gorm.Config{SkipDefaultTransaction: true}, + ) + if err != nil { + t.Errorf("unable to create new sqlite database: %v", err) + } + + _engine, err := New( + WithClient(_sqlite), + WithCompressionLevel(0), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), + WithLogger(logrus.NewEntry(logrus.StandardLogger())), + WithSkipCreation(false), + WithDriver(constants.DriverSqlite), + ) + if err != nil { + t.Errorf("unable to create new sqlite build_itnerary engine: %v", err) + } + + return _engine +} + +// testBuildExecutable is a test helper function to create a library +// BuildExecutable type with all fields set to their zero values. +func testBuildExecutable() *library.BuildExecutable { + return &library.BuildExecutable{ + ID: new(int64), + BuildID: new(int64), + 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. +// +// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime +type AnyArgument struct{} + +// Match satisfies sqlmock.Argument interface. +func (a AnyArgument) Match(v driver.Value) bool { + return v != nil +} diff --git a/database/executable/interface.go b/database/executable/interface.go new file mode 100644 index 000000000..852d77872 --- /dev/null +++ b/database/executable/interface.go @@ -0,0 +1,25 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import "github.com/go-vela/types/library" + +// BuildExecutableInterface represents the Vela interface for build executable +// functions with the supported Database backends. +type BuildExecutableInterface interface { + // BuildExecutable Data Definition Language Functions + // + // https://en.wikipedia.org/wiki/Data_definition_language + CreateBuildExecutableTable(string) error + + // BuildExecutable Data Manipulation Language Functions + // + // https://en.wikipedia.org/wiki/Data_manipulation_language + + // CreateBuildExecutable defines a function that creates a build executable. + CreateBuildExecutable(*library.BuildExecutable) error + // PopBuildExecutable defines a function that gets and deletes a build executable. + PopBuildExecutable(int64) (*library.BuildExecutable, error) +} diff --git a/database/executable/opts.go b/database/executable/opts.go new file mode 100644 index 000000000..1d91a4a54 --- /dev/null +++ b/database/executable/opts.go @@ -0,0 +1,74 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +// EngineOpt represents a configuration option to initialize the database engine for build executables. +type EngineOpt func(*engine) error + +// WithClient sets the gorm.io/gorm client in the database engine for build executables. +func WithClient(client *gorm.DB) EngineOpt { + return func(e *engine) error { + // set the gorm.io/gorm client in the build executable engine + e.client = client + + return nil + } +} + +// WithCompressionLevel sets the compression level in the database engine for build executables. +func WithCompressionLevel(level int) EngineOpt { + return func(e *engine) error { + // set the compression level in the build executable engine + e.config.CompressionLevel = level + + return nil + } +} + +// WithEncryptionKey sets the encryption key in the database engine for build executables. +func WithEncryptionKey(key string) EngineOpt { + return func(e *engine) error { + // set the encryption key in the build executables engine + e.config.EncryptionKey = key + + return nil + } +} + +// WithDriver sets the driver type in the database engine for build executables. +func WithDriver(driver string) EngineOpt { + return func(e *engine) error { + // set the driver type in the build executable engine + e.config.Driver = driver + + return nil + } +} + +// WithLogger sets the github.com/sirupsen/logrus logger in the database engine for build executables. +func WithLogger(logger *logrus.Entry) EngineOpt { + return func(e *engine) error { + // set the github.com/sirupsen/logrus logger in the build executable engine + e.logger = logger + + return nil + } +} + +// WithSkipCreation sets the skip creation logic in the database engine for build executables. +func WithSkipCreation(skipCreation bool) EngineOpt { + return func(e *engine) error { + // set to skip creating tables and indexes in the build executable engine + e.config.SkipCreation = skipCreation + + return nil + } +} diff --git a/database/executable/opts_test.go b/database/executable/opts_test.go new file mode 100644 index 000000000..6bb89d0ae --- /dev/null +++ b/database/executable/opts_test.go @@ -0,0 +1,265 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "reflect" + "testing" + + "github.com/sirupsen/logrus" + + "gorm.io/gorm" +) + +func TestExecutable_EngineOpt_WithClient(t *testing.T) { + // setup types + e := &engine{client: new(gorm.DB)} + + // setup tests + tests := []struct { + failure bool + name string + client *gorm.DB + want *gorm.DB + }{ + { + failure: false, + name: "client set to new database", + client: new(gorm.DB), + want: new(gorm.DB), + }, + { + failure: false, + name: "client set to nil", + client: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithClient(test.client)(e) + + if test.failure { + if err == nil { + t.Errorf("WithClient for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithClient returned err: %v", err) + } + + if !reflect.DeepEqual(e.client, test.want) { + t.Errorf("WithClient is %v, want %v", e.client, test.want) + } + }) + } +} + +func TestExecutable_EngineOpt_WithCompressionLevel(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + level int + want int + }{ + { + failure: false, + name: "compression level set to -1", + level: -1, + want: -1, + }, + { + failure: false, + name: "compression level set to 0", + level: 0, + want: 0, + }, + { + failure: false, + name: "compression level set to 1", + level: 1, + want: 1, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithCompressionLevel(test.level)(e) + + if test.failure { + if err == nil { + t.Errorf("WithCompressionLevel for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithCompressionLevel returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.CompressionLevel, test.want) { + t.Errorf("WithCompressionLevel is %v, want %v", e.config.CompressionLevel, test.want) + } + }) + } +} + +func TestExecutable_EngineOpt_WithEncryptionKey(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + key string + want string + }{ + { + failure: false, + name: "encryption key set", + key: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + want: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + }, + { + failure: false, + name: "encryption key not set", + key: "", + want: "", + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithEncryptionKey(test.key)(e) + + if test.failure { + if err == nil { + t.Errorf("WithEncryptionKey for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithEncryptionKey returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.EncryptionKey, test.want) { + t.Errorf("WithEncryptionKey is %v, want %v", e.config.EncryptionKey, test.want) + } + }) + } +} + +func TestExecutable_EngineOpt_WithLogger(t *testing.T) { + // setup types + e := &engine{logger: new(logrus.Entry)} + + // setup tests + tests := []struct { + failure bool + name string + logger *logrus.Entry + want *logrus.Entry + }{ + { + failure: false, + name: "logger set to new entry", + logger: new(logrus.Entry), + want: new(logrus.Entry), + }, + { + failure: false, + name: "logger set to nil", + logger: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithLogger(test.logger)(e) + + if test.failure { + if err == nil { + t.Errorf("WithLogger for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithLogger returned err: %v", err) + } + + if !reflect.DeepEqual(e.logger, test.want) { + t.Errorf("WithLogger is %v, want %v", e.logger, test.want) + } + }) + } +} + +func TestExecutable_EngineOpt_WithSkipCreation(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + skipCreation bool + want bool + }{ + { + failure: false, + name: "skip creation set to true", + skipCreation: true, + want: true, + }, + { + failure: false, + name: "skip creation set to false", + skipCreation: false, + want: false, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithSkipCreation(test.skipCreation)(e) + + if test.failure { + if err == nil { + t.Errorf("WithSkipCreation for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithSkipCreation returned err: %v", err) + } + + if !reflect.DeepEqual(e.config.SkipCreation, test.want) { + t.Errorf("WithSkipCreation is %v, want %v", e.config.SkipCreation, test.want) + } + }) + } +} diff --git a/database/executable/pop.go b/database/executable/pop.go new file mode 100644 index 000000000..c38d472bc --- /dev/null +++ b/database/executable/pop.go @@ -0,0 +1,78 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "github.com/go-vela/types/constants" + "github.com/go-vela/types/database" + "github.com/go-vela/types/library" + "gorm.io/gorm/clause" +) + +// PopBuildExecutable pops a build executable by build_id from the database. +func (e *engine) PopBuildExecutable(id int64) (*library.BuildExecutable, error) { + e.logger.Tracef("popping build executable for build %d from the database", id) + + // variable to store query results + b := new(database.BuildExecutable) + + // at the time of coding, GORM does not implement a version of Sqlite3 that supports RETURNING. + // so we have to select and delete for the Sqlite driver. + switch e.config.Driver { + case constants.DriverPostgres: + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuildExecutable). + Clauses(clause.Returning{}). + Where("build_id = ?", id). + Delete(b). + Error + + if err != nil { + return nil, err + } + + case constants.DriverSqlite: + // send query to the database and store result in variable + err := e.client. + Table(constants.TableBuildExecutable). + Where("id = ?", id). + Take(b). + Error + if err != nil { + return nil, err + } + + // send query to the database to delete result just got + err = e.client. + Table(constants.TableBuildExecutable). + Delete(b). + Error + if err != nil { + return nil, err + } + } + + // decrypt the fields for the build executable + // + // https://pkg.go.dev/github.com/go-vela/types/database#Repo.Decrypt + err := b.Decrypt(e.config.EncryptionKey) + if err != nil { + return nil, err + } + + // decompress data for the build executable + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutable.Decompress + err = b.Decompress() + if err != nil { + return nil, err + } + + // return the decompressed build executable + // + // https://pkg.go.dev/github.com/go-vela/types/database#BuildExecutable.ToLibrary + return b.ToLibrary(), nil +} diff --git a/database/executable/pop_test.go b/database/executable/pop_test.go new file mode 100644 index 000000000..b89dcec9e --- /dev/null +++ b/database/executable/pop_test.go @@ -0,0 +1,84 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "reflect" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/types/library" +) + +func TestExecutable_Engine_PopBuildExecutable(t *testing.T) { + // setup types + _bExecutable := testBuildExecutable() + _bExecutable.SetID(1) + _bExecutable.SetBuildID(1) + _bExecutable.SetData([]byte("foo")) + + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + // create expected result in mock + _rows := sqlmock.NewRows( + []string{"id", "build_id", "data"}). + AddRow(1, 1, "+//18dbf7mF+v7ZPK3Wo5h2TD6v4Zg95sCMUJYO2tpwY37DEgTxW5xdyt3Tey9w=") + + // ensure the mock expects the query + _mock.ExpectQuery(`DELETE FROM "build_executables" WHERE build_id = $1 RETURNING *`).WithArgs(1).WillReturnRows(_rows) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + err := _sqlite.CreateBuildExecutable(_bExecutable) + if err != nil { + t.Errorf("unable to create test build executable for sqlite: %v", err) + } + + // setup tests + tests := []struct { + failure bool + name string + database *engine + want *library.BuildExecutable + }{ + { + failure: false, + name: "postgres", + database: _postgres, + want: _bExecutable, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + want: _bExecutable, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.database.PopBuildExecutable(1) + + if test.failure { + if err == nil { + t.Errorf("PopBuildExecutable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("PopBuildExecutable for %s returned err: %v", test.name, err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("PopBuildExecutable for %s is %v, want %v", test.name, got, test.want) + } + }) + } +} diff --git a/database/executable/table.go b/database/executable/table.go new file mode 100644 index 000000000..c2b3323b2 --- /dev/null +++ b/database/executable/table.go @@ -0,0 +1,50 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import "github.com/go-vela/types/constants" + +const ( + // CreatePostgresTable represents a query to create the Postgres build_executables table. + CreatePostgresTable = ` +CREATE TABLE +IF NOT EXISTS +build_executables ( + id SERIAL PRIMARY KEY, + build_id INTEGER, + data BYTEA, + UNIQUE(build_id) +); +` + + // CreateSqliteTable represents a query to create the Sqlite build_executables table. + CreateSqliteTable = ` +CREATE TABLE +IF NOT EXISTS +build_executables ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + build_id INTEGER, + data BLOB, + UNIQUE(build_id) +); +` +) + +// CreateBuildExecutableTable creates the build executables table in the database. +func (e *engine) CreateBuildExecutableTable(driver string) error { + e.logger.Tracef("creating build_executables table in the database") + + // handle the driver provided to create the table + switch driver { + case constants.DriverPostgres: + // create the build_executables table for Postgres + return e.client.Exec(CreatePostgresTable).Error + case constants.DriverSqlite: + fallthrough + default: + // create the build_executables table for Sqlite + return e.client.Exec(CreateSqliteTable).Error + } +} diff --git a/database/executable/table_test.go b/database/executable/table_test.go new file mode 100644 index 000000000..ed203b113 --- /dev/null +++ b/database/executable/table_test.go @@ -0,0 +1,59 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package executable + +import ( + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func TestExecutable_Engine_CreateBuildExecutableTable(t *testing.T) { + // setup types + _postgres, _mock := testPostgres(t) + defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() + + _mock.ExpectExec(CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) + + _sqlite := testSqlite(t) + defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() + + // setup tests + tests := []struct { + failure bool + name string + database *engine + }{ + { + failure: false, + name: "postgres", + database: _postgres, + }, + { + failure: false, + name: "sqlite3", + database: _sqlite, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.database.CreateBuildExecutableTable(test.name) + + if test.failure { + if err == nil { + t.Errorf("CreateBuildExecutableTable for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("CreateBuildExecutableTable for %s returned err: %v", test.name, err) + } + }) + } +} diff --git a/database/integration_test.go b/database/integration_test.go index cd4e3f9a7..c87dec0ae 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/executable" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -32,6 +33,7 @@ import ( type Resources struct { Builds []*library.Build Deployments []*library.Deployment + Executables []*library.BuildExecutable Hooks []*library.Hook Logs []*library.Log Pipelines []*library.Pipeline @@ -117,6 +119,8 @@ func TestDatabase_Integration(t *testing.T) { t.Run("test_builds", func(t *testing.T) { testBuilds(t, db, resources) }) + t.Run("test_executables", func(t *testing.T) { testExecutables(t, db, resources) }) + t.Run("test_hooks", func(t *testing.T) { testHooks(t, db, resources) }) t.Run("test_logs", func(t *testing.T) { testLogs(t, db, resources) }) @@ -381,6 +385,53 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { } } +func testExecutables(t *testing.T, db Interface, resources *Resources) { + // create a variable to track the number of methods called for pipelines + methods := make(map[string]bool) + // capture the element type of the pipeline interface + element := reflect.TypeOf(new(executable.BuildExecutableInterface)).Elem() + // iterate through all methods found in the pipeline interface + for i := 0; i < element.NumMethod(); i++ { + // skip tracking the methods to create indexes and tables for pipelines + // since those are already called when the database engine starts + if strings.Contains(element.Method(i).Name, "Index") || + strings.Contains(element.Method(i).Name, "Table") { + continue + } + + // add the method name to the list of functions + methods[element.Method(i).Name] = false + } + + // create the pipelines + for _, executable := range resources.Executables { + err := db.CreateBuildExecutable(executable) + if err != nil { + t.Errorf("unable to create executable %d: %v", executable.GetID(), err) + } + } + methods["CreateBuildExecutable"] = true + + // pop executables for builds + for _, executable := range resources.Executables { + got, err := db.PopBuildExecutable(executable.GetBuildID()) + if err != nil { + t.Errorf("unable to get executable %d for build %d: %v", executable.GetID(), executable.GetBuildID(), err) + } + if !reflect.DeepEqual(got, executable) { + t.Errorf("PopBuildExecutable() is %v, want %v", got, executable) + } + } + methods["PopBuildExecutable"] = true + + // ensure we called all the methods we expected to + for method, called := range methods { + if !called { + t.Errorf("method %s was not called for pipelines", method) + } + } +} + func testHooks(t *testing.T, db Interface, resources *Resources) { // create a variable to track the number of methods called for hooks methods := make(map[string]bool) @@ -1862,6 +1913,16 @@ func newResources() *Resources { buildTwo.SetRuntime("docker") buildTwo.SetDistribution("linux") + executableOne := new(library.BuildExecutable) + executableOne.SetID(1) + executableOne.SetBuildID(1) + executableOne.SetData([]byte("foo")) + + executableTwo := new(library.BuildExecutable) + executableTwo.SetID(2) + executableTwo.SetBuildID(2) + executableTwo.SetData([]byte("foo")) + deploymentOne := new(library.Deployment) deploymentOne.SetID(1) deploymentOne.SetRepoID(1) @@ -2229,6 +2290,7 @@ func newResources() *Resources { return &Resources{ Builds: []*library.Build{buildOne, buildTwo}, Deployments: []*library.Deployment{deploymentOne, deploymentTwo}, + Executables: []*library.BuildExecutable{executableOne, executableTwo}, Hooks: []*library.Hook{hookOne, hookTwo}, Logs: []*library.Log{logServiceOne, logServiceTwo, logStepOne, logStepTwo}, Pipelines: []*library.Pipeline{pipelineOne, pipelineTwo}, diff --git a/database/interface.go b/database/interface.go index 3ed775707..cc7428378 100644 --- a/database/interface.go +++ b/database/interface.go @@ -6,6 +6,7 @@ package database import ( "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/executable" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -36,6 +37,9 @@ type Interface interface { // BuildInterface defines the interface for builds stored in the database. build.BuildInterface + // BuildExecutableInterface defines the interface for build executables stored in the database. + executable.BuildExecutableInterface + // HookInterface defines the interface for hooks stored in the database. hook.HookInterface diff --git a/database/resource.go b/database/resource.go index e6784b2e1..482834ecf 100644 --- a/database/resource.go +++ b/database/resource.go @@ -8,6 +8,7 @@ import ( "context" "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/executable" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -35,6 +36,18 @@ func (e *engine) NewResources(ctx context.Context) error { return err } + // create the database agnostic engine for build_executables + e.BuildExecutableInterface, err = executable.New( + executable.WithClient(e.client), + executable.WithLogger(e.logger), + executable.WithSkipCreation(e.config.SkipCreation), + executable.WithEncryptionKey(e.config.EncryptionKey), + executable.WithDriver(e.config.Driver), + ) + if err != nil { + return err + } + // create the database agnostic engine for hooks e.HookInterface, err = hook.New( hook.WithClient(e.client), diff --git a/database/resource_test.go b/database/resource_test.go index 233dbb800..328f04f58 100644 --- a/database/resource_test.go +++ b/database/resource_test.go @@ -10,6 +10,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/go-vela/server/database/build" + "github.com/go-vela/server/database/executable" "github.com/go-vela/server/database/hook" "github.com/go-vela/server/database/log" "github.com/go-vela/server/database/pipeline" @@ -32,6 +33,8 @@ func TestDatabase_Engine_NewResources(t *testing.T) { _mock.ExpectExec(build.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(build.CreateSourceIndex).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(build.CreateStatusIndex).WillReturnResult(sqlmock.NewResult(1, 1)) + // ensure the mock expects the build executable queries + _mock.ExpectExec(executable.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) // ensure the mock expects the hook queries _mock.ExpectExec(hook.CreatePostgresTable).WillReturnResult(sqlmock.NewResult(1, 1)) _mock.ExpectExec(hook.CreateRepoIDIndex).WillReturnResult(sqlmock.NewResult(1, 1)) diff --git a/go.mod b/go.mod index f36b309d4..2f200eccf 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.20.1 + github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index a8eaa2a36..45416d2f1 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.20.1 h1:hHAX0Iij2J7UZ9f3SlXbwNy481CjKzU9CBfkiLuysVE= -github.com/go-vela/types v0.20.1/go.mod h1:AXO4oQSygOBQ02fPapsKjQHkx2aQO3zTu7clpvVbXBY= +github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe h1:5lw7hJmwLiymoSI0H8gr9Aiixifv2wOXvtH4NJJZB2k= +github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe/go.mod h1:AXO4oQSygOBQ02fPapsKjQHkx2aQO3zTu7clpvVbXBY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= diff --git a/mock/server/build.go b/mock/server/build.go index 6d989d8af..cc24af60c 100644 --- a/mock/server/build.go +++ b/mock/server/build.go @@ -150,6 +150,14 @@ const ( "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJidWlsZF9pZCI6MSwicmVwbyI6ImZvby9iYXIiLCJzdWIiOiJPY3RvY2F0IiwiaWF0IjoxNTE2MjM5MDIyfQ.hD7gXpaf9acnLBdOBa4GOEa5KZxdzd0ZvK6fGwaN4bc" }` + // BuildExecutableResp represents a JSON return for requesting a build executable. + BuildExecutableResp = `{ + "id": 1 + "build_id": 1, + "data": "eyAKICAgICJpZCI6ICJzdGVwX25hbWUiLAogICAgInZlcnNpb24iOiAiMSIsCiAgICAibWV0YWRhdGEiOnsKICAgICAgICAiY2xvbmUiOnRydWUsCiAgICAgICAgImVudmlyb25tZW50IjpbInN0ZXBzIiwic2VydmljZXMiLCJzZWNyZXRzIl19LAogICAgIndvcmtlciI6e30sCiAgICAic3RlcHMiOlsKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6InN0ZXBfZ2l0aHViX29jdG9jYXRfMV9pbml0IiwKICAgICAgICAgICAgImRpcmVjdG9yeSI6Ii92ZWxhL3NyYy9naXRodWIuY29tL2dpdGh1Yi9vY3RvY2F0IiwKICAgICAgICAgICAgImVudmlyb25tZW50IjogeyJCVUlMRF9BVVRIT1IiOiJPY3RvY2F0In0KICAgICAgICB9CiAgICBdCn0KCg==" + }` + + // CleanResourcesResp represents a string return for cleaning resources as an admin. CleanResourcesResp = "42 builds cleaned. 42 services cleaned. 42 steps cleaned." ) @@ -330,6 +338,8 @@ func buildToken(c *gin.Context) { if strings.EqualFold(b, "2") { c.AbortWithStatusJSON(http.StatusBadRequest, "") + + return } data := []byte(BuildTokenResp) @@ -340,6 +350,28 @@ func buildToken(c *gin.Context) { c.JSON(http.StatusOK, body) } +// buildExecutable has a param :build returns mock JSON for a http GET. +// +// Pass "0" to :build to test receiving a http 500 response. +func buildExecutable(c *gin.Context) { + b := c.Param("build") + + if strings.EqualFold(b, "0") { + msg := fmt.Sprintf("unable to get build executable for build %s", b) + + c.AbortWithStatusJSON(http.StatusInternalServerError, types.Error{Message: &msg}) + + return + } + + data := []byte(BuildExecutableResp) + + var body library.BuildExecutable + _ = json.Unmarshal(data, &body) + + c.JSON(http.StatusOK, body) +} + // cleanResources has a query param :before returns mock JSON for a http PUT // // Pass "1" to :before to test receiving a http 500 response. Pass "2" to :before diff --git a/mock/server/server.go b/mock/server/server.go index d2f6ccbab..7bc668719 100644 --- a/mock/server/server.go +++ b/mock/server/server.go @@ -42,6 +42,7 @@ func FakeHandler() http.Handler { e.PUT("/api/v1/repos/:org/:repo/builds/:build", updateBuild) e.DELETE("/api/v1/repos/:org/:repo/builds/:build", removeBuild) e.GET("/api/v1/repos/:org/:repo/builds/:build/token", buildToken) + e.GET("/api/v1/repos/:org/:repo/builds/:build/executable", buildExecutable) // mock endpoints for deployment calls e.GET("/api/v1/deployments/:org/:repo", getDeployments) diff --git a/queue/redis/length_test.go b/queue/redis/length_test.go index 95cb21423..c97a5b3f8 100644 --- a/queue/redis/length_test.go +++ b/queue/redis/length_test.go @@ -17,10 +17,9 @@ func TestRedis_Length(t *testing.T) { // setup types // use global variables in redis_test.go _item := &types.Item{ - Build: _build, - Pipeline: _steps, - Repo: _repo, - User: _user, + Build: _build, + Repo: _repo, + User: _user, } // setup queue item diff --git a/queue/redis/pop_test.go b/queue/redis/pop_test.go index 8ae6094b7..cb8209e1d 100644 --- a/queue/redis/pop_test.go +++ b/queue/redis/pop_test.go @@ -18,10 +18,9 @@ func TestRedis_Pop(t *testing.T) { // setup types // use global variables in redis_test.go _item := &types.Item{ - Build: _build, - Pipeline: _steps, - Repo: _repo, - User: _user, + Build: _build, + Repo: _repo, + User: _user, } // setup queue item diff --git a/queue/redis/push_test.go b/queue/redis/push_test.go index 69af784e3..74e815926 100644 --- a/queue/redis/push_test.go +++ b/queue/redis/push_test.go @@ -16,10 +16,9 @@ func TestRedis_Push(t *testing.T) { // setup types // use global variables in redis_test.go _item := &types.Item{ - Build: _build, - Pipeline: _steps, - Repo: _repo, - User: _user, + Build: _build, + Repo: _repo, + User: _user, } // setup queue item diff --git a/router/build.go b/router/build.go index 22cd37aa4..c8cc0d688 100644 --- a/router/build.go +++ b/router/build.go @@ -26,6 +26,7 @@ import ( // DELETE /api/v1/repos/:org/:repo/builds/:build/cancel // GET /api/v1/repos/:org/:repo/builds/:build/logs // GET /api/v1/repos/:org/:repo/builds/:build/token +// GET /api/v1/repos/:org/:repo/builds/:build/executable // POST /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services // GET /api/v1/repos/:org/:repo/builds/:build/services/:service @@ -61,6 +62,7 @@ func BuildHandlers(base *gin.RouterGroup) { b.DELETE("/cancel", executors.Establish(), perm.MustWrite(), build.CancelBuild) b.GET("/logs", perm.MustRead(), log.ListLogsForBuild) b.GET("/token", perm.MustWorkerAuthToken(), build.GetBuildToken) + b.GET("/executable", perm.MustBuildAccess(), build.GetBuildExecutable) // Service endpoints // * Log endpoints From a980c86090ae9ed591ded61144e541a6b0ca6681 Mon Sep 17 00:00:00 2001 From: claire1618 <55173466+claire1618@users.noreply.github.com> Date: Wed, 23 Aug 2023 13:27:05 -0500 Subject: [PATCH 293/298] enhance: adding a branch field to scheduled builds (#934) * enhance: adding a branch field to scheduled builds * enhance: adding a branch field to scheduled builds * enhance: adding a branch field to scheduled builds * enhance: fixing merge conflicts for branch in scheduled builds * enhance: fixing merge conflicts for branch in scheduled builds --------- Co-authored-by: Claire.Nicholas Co-authored-by: Kelly Merrick Co-authored-by: Claire.Nicholas --- api/schedule/create.go | 6 ++++++ api/schedule/update.go | 3 +++ cmd/vela-server/schedule.go | 4 ++-- database/integration_test.go | 2 ++ database/schedule/count_active_test.go | 2 ++ database/schedule/count_repo_test.go | 2 ++ database/schedule/count_test.go | 2 ++ database/schedule/create_test.go | 7 ++++--- database/schedule/delete_test.go | 1 + database/schedule/get_repo_test.go | 5 +++-- database/schedule/get_test.go | 5 +++-- database/schedule/list_active_test.go | 6 ++++-- database/schedule/list_repo_test.go | 6 ++++-- database/schedule/list_test.go | 8 +++++--- database/schedule/schedule_test.go | 1 + database/schedule/table.go | 3 +++ database/schedule/update_test.go | 8 +++++--- go.mod | 2 +- go.sum | 4 ++-- scm/github/repo.go | 6 +++--- scm/github/repo_test.go | 2 +- scm/service.go | 2 +- 22 files changed, 60 insertions(+), 27 deletions(-) diff --git a/api/schedule/create.go b/api/schedule/create.go index c50f11744..667eb3ca9 100644 --- a/api/schedule/create.go +++ b/api/schedule/create.go @@ -137,6 +137,12 @@ func CreateSchedule(c *gin.Context) { s.SetUpdatedAt(time.Now().UTC().Unix()) s.SetUpdatedBy(u.GetName()) + if input.GetBranch() == "" { + s.SetBranch(r.GetBranch()) + } else { + s.SetBranch(input.GetBranch()) + } + // set the active field based off the input provided if input.Active == nil { // default active field to true diff --git a/api/schedule/update.go b/api/schedule/update.go index 578639c8b..6c2a8b9b6 100644 --- a/api/schedule/update.go +++ b/api/schedule/update.go @@ -127,6 +127,9 @@ func UpdateSchedule(c *gin.Context) { // set the updated by field using claims s.SetUpdatedBy(u.GetName()) + if input.GetBranch() != "" { + s.SetBranch(input.GetBranch()) + } // update the schedule within the database s, err = database.FromContext(c).UpdateSchedule(ctx, s, true) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index a8d927a1b..b65723177 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -184,7 +184,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler } // send API call to capture the commit sha for the branch - _, commit, err := scm.GetBranch(u, r) + _, commit, err := scm.GetBranch(u, r, s.GetBranch()) if err != nil { return fmt.Errorf("failed to get commit for repo %s on %s branch: %w", r.GetFullName(), r.GetBranch(), err) } @@ -193,7 +193,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler b := new(library.Build) b.SetAuthor(s.GetCreatedBy()) - b.SetBranch(r.GetBranch()) + b.SetBranch(s.GetBranch()) b.SetClone(r.GetClone()) b.SetCommit(commit) b.SetDeploy(s.GetName()) diff --git a/database/integration_test.go b/database/integration_test.go index c87dec0ae..3e1ea546d 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -2108,6 +2108,7 @@ func newResources() *Resources { scheduleOne.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) scheduleOne.SetUpdatedBy("octokitty") scheduleOne.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + scheduleOne.SetBranch("main") scheduleTwo := new(library.Schedule) scheduleTwo.SetID(2) @@ -2120,6 +2121,7 @@ func newResources() *Resources { scheduleTwo.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) scheduleTwo.SetUpdatedBy("octokitty") scheduleTwo.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + scheduleTwo.SetBranch("main") secretOrg := new(library.Secret) secretOrg.SetID(1) diff --git a/database/schedule/count_active_test.go b/database/schedule/count_active_test.go index 5d555ea8c..dcf9d2cb0 100644 --- a/database/schedule/count_active_test.go +++ b/database/schedule/count_active_test.go @@ -23,6 +23,7 @@ func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -34,6 +35,7 @@ func TestSchedule_Engine_CountActiveSchedules(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/schedule/count_repo_test.go b/database/schedule/count_repo_test.go index d2429c595..35c530d7c 100644 --- a/database/schedule/count_repo_test.go +++ b/database/schedule/count_repo_test.go @@ -28,6 +28,7 @@ func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -38,6 +39,7 @@ func TestSchedule_Engine_CountSchedulesForRepo(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/schedule/count_test.go b/database/schedule/count_test.go index 91537d919..c98ba7224 100644 --- a/database/schedule/count_test.go +++ b/database/schedule/count_test.go @@ -22,6 +22,7 @@ func TestSchedule_Engine_CountSchedules(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -32,6 +33,7 @@ func TestSchedule_Engine_CountSchedules(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/schedule/create_test.go b/database/schedule/create_test.go index 4a987b577..272e91a41 100644 --- a/database/schedule/create_test.go +++ b/database/schedule/create_test.go @@ -22,6 +22,7 @@ func TestSchedule_Engine_CreateSchedule(t *testing.T) { _schedule.SetCreatedBy("user1") _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -31,9 +32,9 @@ func TestSchedule_Engine_CreateSchedule(t *testing.T) { // ensure the mock expects the query _mock.ExpectQuery(`INSERT INTO "schedules" -("repo_id","active","name","entry","created_at","created_by","updated_at","updated_by","scheduled_at","id") -VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id"`). - WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, 1). +("repo_id","active","name","entry","created_at","created_by","updated_at","updated_by","scheduled_at","branch","id") +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) RETURNING "id"`). + WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main", 1). WillReturnRows(_rows) _sqlite := testSqlite(t) diff --git a/database/schedule/delete_test.go b/database/schedule/delete_test.go index e302da6b9..8dff8ad78 100644 --- a/database/schedule/delete_test.go +++ b/database/schedule/delete_test.go @@ -21,6 +21,7 @@ func TestSchedule_Engine_DeleteSchedule(t *testing.T) { _schedule.SetCreatedBy("user1") _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/schedule/get_repo_test.go b/database/schedule/get_repo_test.go index b29072ec7..998b58fc3 100644 --- a/database/schedule/get_repo_test.go +++ b/database/schedule/get_repo_test.go @@ -29,14 +29,15 @@ func TestSchedule_Engine_GetScheduleForRepo(t *testing.T) { _schedule.SetCreatedBy("user1") _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}, - ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at", "branch"}, + ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE repo_id = $1 AND name = $2 LIMIT 1`).WithArgs(1, "nightly").WillReturnRows(_rows) diff --git a/database/schedule/get_test.go b/database/schedule/get_test.go index b5175d8b0..bc4a61f75 100644 --- a/database/schedule/get_test.go +++ b/database/schedule/get_test.go @@ -23,14 +23,15 @@ func TestSchedule_Engine_GetSchedule(t *testing.T) { _schedule.SetCreatedBy("user1") _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // create expected result in mock _rows := sqlmock.NewRows( - []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}, - ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at", "branch"}, + ).AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE id = $1 LIMIT 1`).WithArgs(1).WillReturnRows(_rows) diff --git a/database/schedule/list_active_test.go b/database/schedule/list_active_test.go index 90ae96cfe..2bce7ed06 100644 --- a/database/schedule/list_active_test.go +++ b/database/schedule/list_active_test.go @@ -24,6 +24,7 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -35,6 +36,7 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -47,8 +49,8 @@ func TestSchedule_Engine_ListActiveSchedules(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). - AddRow(1, 1, true, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at", "branch"}). + AddRow(1, 1, true, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE active = $1`).WithArgs(true).WillReturnRows(_rows) diff --git a/database/schedule/list_repo_test.go b/database/schedule/list_repo_test.go index 2536f73be..2d573448d 100644 --- a/database/schedule/list_repo_test.go +++ b/database/schedule/list_repo_test.go @@ -29,6 +29,7 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -39,6 +40,7 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -51,8 +53,8 @@ func TestSchedule_Engine_ListSchedulesForRepo(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). - AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil) + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at", "branch"}). + AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "schedules" WHERE repo_id = $1 ORDER BY id DESC LIMIT 10`).WithArgs(1).WillReturnRows(_rows) diff --git a/database/schedule/list_test.go b/database/schedule/list_test.go index 6dd64af6c..5b4095724 100644 --- a/database/schedule/list_test.go +++ b/database/schedule/list_test.go @@ -23,6 +23,7 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { _scheduleOne.SetCreatedBy("user1") _scheduleOne.SetUpdatedAt(1) _scheduleOne.SetUpdatedBy("user2") + _scheduleOne.SetBranch("main") _scheduleTwo := testSchedule() _scheduleTwo.SetID(2) @@ -33,6 +34,7 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { _scheduleTwo.SetCreatedBy("user1") _scheduleTwo.SetUpdatedAt(1) _scheduleTwo.SetUpdatedBy("user2") + _scheduleTwo.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -45,9 +47,9 @@ func TestSchedule_Engine_ListSchedules(t *testing.T) { // create expected result in mock _rows = sqlmock.NewRows( - []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at"}). - AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil). - AddRow(2, 2, false, "hourly", "0 * * * *", 1, "user1", 1, "user2", nil) + []string{"id", "repo_id", "active", "name", "entry", "created_at", "created_by", "updated_at", "updated_by", "scheduled_at", "branch"}). + AddRow(1, 1, false, "nightly", "0 0 * * *", 1, "user1", 1, "user2", nil, "main"). + AddRow(2, 2, false, "hourly", "0 * * * *", 1, "user1", 1, "user2", nil, "main") // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "schedules"`).WillReturnRows(_rows) diff --git a/database/schedule/schedule_test.go b/database/schedule/schedule_test.go index aae0403a5..b5916b3e3 100644 --- a/database/schedule/schedule_test.go +++ b/database/schedule/schedule_test.go @@ -187,6 +187,7 @@ func testSchedule() *library.Schedule { UpdatedAt: new(int64), UpdatedBy: new(string), ScheduledAt: new(int64), + Branch: new(string), } } diff --git a/database/schedule/table.go b/database/schedule/table.go index 7ea6eb873..9ebccf864 100644 --- a/database/schedule/table.go +++ b/database/schedule/table.go @@ -6,6 +6,7 @@ package schedule import ( "context" + "github.com/go-vela/types/constants" ) @@ -25,6 +26,7 @@ schedules ( updated_at INTEGER, updated_by VARCHAR(250), scheduled_at INTEGER, + branch VARCHAR(250), UNIQUE(repo_id, name) ); ` @@ -44,6 +46,7 @@ schedules ( updated_at INTEGER, updated_by TEXT, scheduled_at INTEGER, + branch TEXT, UNIQUE(repo_id, name) ); ` diff --git a/database/schedule/update_test.go b/database/schedule/update_test.go index c13e44ae8..235ccfc43 100644 --- a/database/schedule/update_test.go +++ b/database/schedule/update_test.go @@ -28,15 +28,16 @@ func TestSchedule_Engine_UpdateSchedule_Config(t *testing.T) { _schedule.SetCreatedBy("user1") _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() // ensure the mock expects the query _mock.ExpectExec(`UPDATE "schedules" -SET "repo_id"=$1,"active"=$2,"name"=$3,"entry"=$4,"created_at"=$5,"created_by"=$6,"updated_at"=$7,"updated_by"=$8,"scheduled_at"=$9 -WHERE "id" = $10`). - WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", NowTimestamp{}, "user2", nil, 1). +SET "repo_id"=$1,"active"=$2,"name"=$3,"entry"=$4,"created_at"=$5,"created_by"=$6,"updated_at"=$7,"updated_by"=$8,"scheduled_at"=$9,"branch"=$10 +WHERE "id" = $11`). + WithArgs(1, false, "nightly", "0 0 * * *", 1, "user1", NowTimestamp{}, "user2", nil, "main", 1). WillReturnResult(sqlmock.NewResult(1, 1)) _sqlite := testSqlite(t) @@ -107,6 +108,7 @@ func TestSchedule_Engine_UpdateSchedule_NotConfig(t *testing.T) { _schedule.SetUpdatedAt(1) _schedule.SetUpdatedBy("user2") _schedule.SetScheduledAt(1) + _schedule.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/go.mod b/go.mod index 2f200eccf..addeed1ab 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/drone/envsubst v1.0.3 github.com/gin-gonic/gin v1.9.1 github.com/go-playground/assert/v2 v2.2.0 - github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe + github.com/go-vela/types v0.20.2-0.20230822144153-14b37585731d github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-cmp v0.5.9 github.com/google/go-github/v53 v53.2.0 diff --git a/go.sum b/go.sum index 45416d2f1..f109e9873 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= -github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe h1:5lw7hJmwLiymoSI0H8gr9Aiixifv2wOXvtH4NJJZB2k= -github.com/go-vela/types v0.20.2-0.20230821135955-6b577f36fdfe/go.mod h1:AXO4oQSygOBQ02fPapsKjQHkx2aQO3zTu7clpvVbXBY= +github.com/go-vela/types v0.20.2-0.20230822144153-14b37585731d h1:ag6trc3Ev+7hzifeWy0M9rHHjrO9nFCYgW8dlKdZ4j4= +github.com/go-vela/types v0.20.2-0.20230822144153-14b37585731d/go.mod h1:AXO4oQSygOBQ02fPapsKjQHkx2aQO3zTu7clpvVbXBY= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= diff --git a/scm/github/repo.go b/scm/github/repo.go index 5cd3b0999..e69c7220c 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -548,17 +548,17 @@ func (c *client) GetHTMLURL(u *library.User, org, repo, name, ref string) (strin } // GetBranch defines a function that retrieves a branch for a repo. -func (c *client) GetBranch(u *library.User, r *library.Repo) (string, string, error) { +func (c *client) GetBranch(u *library.User, r *library.Repo, branch string) (string, string, error) { c.Logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), "user": u.GetName(), - }).Tracef("retrieving branch %s for repo %s", r.GetBranch(), r.GetFullName()) + }).Tracef("retrieving branch %s for repo %s", branch, r.GetFullName()) // create GitHub OAuth client with user's token client := c.newClientToken(u.GetToken()) - data, _, err := client.Repositories.GetBranch(ctx, r.GetOrg(), r.GetName(), r.GetBranch(), true) + data, _, err := client.Repositories.GetBranch(ctx, r.GetOrg(), r.GetName(), branch, true) if err != nil { return "", "", err } diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index 1fcd3bf0c..858d60f18 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -1339,7 +1339,7 @@ func TestGithub_GetBranch(t *testing.T) { client, _ := NewTest(s.URL) // run test - gotBranch, gotCommit, err := client.GetBranch(u, r) + gotBranch, gotCommit, err := client.GetBranch(u, r, "main") if err != nil { t.Errorf("Status returned err: %v", err) diff --git a/scm/service.go b/scm/service.go index c92cbedbf..4de42362f 100644 --- a/scm/service.go +++ b/scm/service.go @@ -110,7 +110,7 @@ type Service interface { ListUserRepos(*library.User) ([]*library.Repo, error) // GetBranch defines a function that retrieves // a branch for a repo. - GetBranch(*library.User, *library.Repo) (string, string, error) + GetBranch(*library.User, *library.Repo, string) (string, string, error) // GetPullRequest defines a function that retrieves // a pull request for a repo. GetPullRequest(*library.User, *library.Repo, int) (string, string, string, string, error) From 5f6be5c458d810a110172d32f9f2ab800d8324d5 Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:30:45 -0400 Subject: [PATCH 294/298] refactor(db): return step on created and updated (#933) --- api/admin/step.go | 4 ++-- api/build/cancel.go | 2 +- api/build/clean.go | 2 +- api/step/create.go | 5 +---- api/step/plan.go | 8 +------- api/step/update.go | 5 +---- database/integration_test.go | 9 ++------- database/step/clean_test.go | 8 ++++---- database/step/count_build_test.go | 4 ++-- database/step/count_test.go | 4 ++-- database/step/create.go | 11 +++++------ database/step/create_test.go | 7 ++++++- database/step/delete_test.go | 2 +- database/step/get_build_test.go | 2 +- database/step/get_test.go | 2 +- database/step/interface.go | 4 ++-- database/step/list_build_test.go | 4 ++-- database/step/list_image_test.go | 4 ++-- database/step/list_status_test.go | 4 ++-- database/step/list_test.go | 4 ++-- database/step/update.go | 11 +++++------ database/step/update_test.go | 9 +++++++-- router/middleware/step/step_test.go | 2 +- 23 files changed, 54 insertions(+), 63 deletions(-) diff --git a/api/admin/step.go b/api/admin/step.go index 5f03aff6b..2da12ece1 100644 --- a/api/admin/step.go +++ b/api/admin/step.go @@ -66,7 +66,7 @@ func UpdateStep(c *gin.Context) { } // send API call to update the step - err = database.FromContext(c).UpdateStep(input) + s, err := database.FromContext(c).UpdateStep(input) if err != nil { retErr := fmt.Errorf("unable to update step %d: %w", input.GetID(), err) @@ -75,5 +75,5 @@ func UpdateStep(c *gin.Context) { return } - c.JSON(http.StatusOK, input) + c.JSON(http.StatusOK, s) } diff --git a/api/build/cancel.go b/api/build/cancel.go index d8d4e6c06..55dc7cecf 100644 --- a/api/build/cancel.go +++ b/api/build/cancel.go @@ -231,7 +231,7 @@ func CancelBuild(c *gin.Context) { if step.GetStatus() == constants.StatusRunning || step.GetStatus() == constants.StatusPending { step.SetStatus(constants.StatusCanceled) - err = database.FromContext(c).UpdateStep(step) + _, err = database.FromContext(c).UpdateStep(step) if err != nil { retErr := fmt.Errorf("unable to update step %s for build %s: %w", step.GetName(), entry, err) util.HandleError(c, http.StatusNotFound, retErr) diff --git a/api/build/clean.go b/api/build/clean.go index a93a9355c..0dd9ea81e 100644 --- a/api/build/clean.go +++ b/api/build/clean.go @@ -49,7 +49,7 @@ func CleanBuild(ctx context.Context, database database.Interface, b *library.Bui s.SetFinished(time.Now().UTC().Unix()) // send API call to update the step - err := database.UpdateStep(s) + _, err := database.UpdateStep(s) if err != nil { logrus.Errorf("unable to kill step %s for build %d: %v", s.GetName(), b.GetNumber(), err) } diff --git a/api/step/create.go b/api/step/create.go index d87bfaae0..58e71a99e 100644 --- a/api/step/create.go +++ b/api/step/create.go @@ -112,7 +112,7 @@ func CreateStep(c *gin.Context) { } // send API call to create the step - err = database.FromContext(c).CreateStep(input) + s, err := database.FromContext(c).CreateStep(input) if err != nil { retErr := fmt.Errorf("unable to create step for build %s: %w", entry, err) @@ -121,8 +121,5 @@ func CreateStep(c *gin.Context) { return } - // send API call to capture the created step - s, _ := database.FromContext(c).GetStepForBuild(b, input.GetNumber()) - c.JSON(http.StatusCreated, s) } diff --git a/api/step/plan.go b/api/step/plan.go index b072cf4f7..daf795284 100644 --- a/api/step/plan.go +++ b/api/step/plan.go @@ -61,17 +61,11 @@ func planStep(database database.Interface, b *library.Build, c *pipeline.Contain s.SetCreated(time.Now().UTC().Unix()) // send API call to create the step - err := database.CreateStep(s) + s, err := database.CreateStep(s) if err != nil { return nil, fmt.Errorf("unable to create step %s: %w", s.GetName(), err) } - // send API call to capture the created step - s, err = database.GetStepForBuild(b, s.GetNumber()) - if err != nil { - return nil, fmt.Errorf("unable to get step %s: %w", s.GetName(), err) - } - // populate environment variables from step library // // https://pkg.go.dev/github.com/go-vela/types/library#step.Environment diff --git a/api/step/update.go b/api/step/update.go index 8a64fbb12..d0563d98d 100644 --- a/api/step/update.go +++ b/api/step/update.go @@ -147,7 +147,7 @@ func UpdateStep(c *gin.Context) { } // send API call to update the step - err = database.FromContext(c).UpdateStep(s) + s, err = database.FromContext(c).UpdateStep(s) if err != nil { retErr := fmt.Errorf("unable to update step %s: %w", entry, err) @@ -156,8 +156,5 @@ func UpdateStep(c *gin.Context) { return } - // send API call to capture the updated step - s, _ = database.FromContext(c).GetStepForBuild(b, s.GetNumber()) - c.JSON(http.StatusOK, s) } diff --git a/database/integration_test.go b/database/integration_test.go index 3e1ea546d..669fa3907 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -1480,7 +1480,7 @@ func testSteps(t *testing.T, db Interface, resources *Resources) { // create the steps for _, step := range resources.Steps { - err := db.CreateStep(step) + _, err := db.CreateStep(step) if err != nil { t.Errorf("unable to create step %d: %v", step.GetID(), err) } @@ -1585,16 +1585,11 @@ func testSteps(t *testing.T, db Interface, resources *Resources) { // update the steps for _, step := range resources.Steps { step.SetStatus("success") - err = db.UpdateStep(step) + got, err := db.UpdateStep(step) if err != nil { t.Errorf("unable to update step %d: %v", step.GetID(), err) } - // lookup the step by ID - got, err := db.GetStep(step.GetID()) - if err != nil { - t.Errorf("unable to get step %d by ID: %v", step.GetID(), err) - } if !reflect.DeepEqual(got, step) { t.Errorf("GetStep() is %v, want %v", got, step) } diff --git a/database/step/clean_test.go b/database/step/clean_test.go index 4d0c68e07..e772751ac 100644 --- a/database/step/clean_test.go +++ b/database/step/clean_test.go @@ -64,22 +64,22 @@ func TestStep_Engine_CleanStep(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepThree) + _, err = _sqlite.CreateStep(_stepThree) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepFour) + _, err = _sqlite.CreateStep(_stepFour) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/count_build_test.go b/database/step/count_build_test.go index 401e1d6b3..df5a830f4 100644 --- a/database/step/count_build_test.go +++ b/database/step/count_build_test.go @@ -46,12 +46,12 @@ func TestStep_Engine_CountStepsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/count_test.go b/database/step/count_test.go index eff1fec8c..dc473bd96 100644 --- a/database/step/count_test.go +++ b/database/step/count_test.go @@ -41,12 +41,12 @@ func TestStep_Engine_CountSteps(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/create.go b/database/step/create.go index 03ec3a953..2d18bc9ce 100644 --- a/database/step/create.go +++ b/database/step/create.go @@ -12,7 +12,7 @@ import ( ) // CreateStep creates a new step in the database. -func (e *engine) CreateStep(s *library.Step) error { +func (e *engine) CreateStep(s *library.Step) (*library.Step, error) { e.logger.WithFields(logrus.Fields{ "step": s.GetNumber(), }).Tracef("creating step %s in the database", s.GetName()) @@ -27,12 +27,11 @@ func (e *engine) CreateStep(s *library.Step) error { // https://pkg.go.dev/github.com/go-vela/types/database#Step.Validate err := step.Validate() if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TableStep). - Create(step). - Error + result := e.client.Table(constants.TableStep).Create(step) + + return step.ToLibrary(), result.Error } diff --git a/database/step/create_test.go b/database/step/create_test.go index 1f7b3e1b8..0bf3ffca6 100644 --- a/database/step/create_test.go +++ b/database/step/create_test.go @@ -5,6 +5,7 @@ package step import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -57,7 +58,7 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`) // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateStep(_step) + got, err := test.database.CreateStep(_step) if test.failure { if err == nil { @@ -70,6 +71,10 @@ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING "id"`) if err != nil { t.Errorf("CreateStep for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _step) { + t.Errorf("CreateStep for %s returned %s, want %s", test.name, got, _step) + } }) } } diff --git a/database/step/delete_test.go b/database/step/delete_test.go index c3b35ee8a..d77f81a25 100644 --- a/database/step/delete_test.go +++ b/database/step/delete_test.go @@ -31,7 +31,7 @@ func TestStep_Engine_DeleteStep(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_step) + _, err := _sqlite.CreateStep(_step) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/get_build_test.go b/database/step/get_build_test.go index ce4bfff37..8428598f5 100644 --- a/database/step/get_build_test.go +++ b/database/step/get_build_test.go @@ -41,7 +41,7 @@ func TestStep_Engine_GetStepForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_step) + _, err := _sqlite.CreateStep(_step) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/get_test.go b/database/step/get_test.go index 382fa0b7c..b30ced1b0 100644 --- a/database/step/get_test.go +++ b/database/step/get_test.go @@ -36,7 +36,7 @@ func TestStep_Engine_GetStep(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_step) + _, err := _sqlite.CreateStep(_step) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/interface.go b/database/step/interface.go index 68423c8c9..e7a377d26 100644 --- a/database/step/interface.go +++ b/database/step/interface.go @@ -31,7 +31,7 @@ type StepInterface interface { // CountStepsForBuild defines a function that gets the count of steps by build ID. CountStepsForBuild(*library.Build, map[string]interface{}) (int64, error) // CreateStep defines a function that creates a new step. - CreateStep(*library.Step) error + CreateStep(*library.Step) (*library.Step, error) // DeleteStep defines a function that deletes an existing step. DeleteStep(*library.Step) error // GetStep defines a function that gets a step by ID. @@ -47,5 +47,5 @@ type StepInterface interface { // ListStepStatusCount defines a function that gets a list of all step statuses and the count of their occurrence. ListStepStatusCount() (map[string]float64, error) // UpdateStep defines a function that updates an existing step. - UpdateStep(*library.Step) error + UpdateStep(*library.Step) (*library.Step, error) } diff --git a/database/step/list_build_test.go b/database/step/list_build_test.go index c79100eae..4ebe4c0be 100644 --- a/database/step/list_build_test.go +++ b/database/step/list_build_test.go @@ -56,12 +56,12 @@ func TestStep_Engine_ListStepsForBuild(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/list_image_test.go b/database/step/list_image_test.go index 574545493..b7170634f 100644 --- a/database/step/list_image_test.go +++ b/database/step/list_image_test.go @@ -41,12 +41,12 @@ func TestStep_Engine_ListStepImageCount(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/list_status_test.go b/database/step/list_status_test.go index 57f500650..7716b02e9 100644 --- a/database/step/list_status_test.go +++ b/database/step/list_status_test.go @@ -46,12 +46,12 @@ func TestStep_Engine_ListStepStatusCount(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/list_test.go b/database/step/list_test.go index cb1c05cb2..c98852b1b 100644 --- a/database/step/list_test.go +++ b/database/step/list_test.go @@ -51,12 +51,12 @@ func TestStep_Engine_ListSteps(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_stepOne) + _, err := _sqlite.CreateStep(_stepOne) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } - err = _sqlite.CreateStep(_stepTwo) + _, err = _sqlite.CreateStep(_stepTwo) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } diff --git a/database/step/update.go b/database/step/update.go index 87f8d2aa9..c9e5f73d0 100644 --- a/database/step/update.go +++ b/database/step/update.go @@ -12,7 +12,7 @@ import ( ) // UpdateStep updates an existing step in the database. -func (e *engine) UpdateStep(s *library.Step) error { +func (e *engine) UpdateStep(s *library.Step) (*library.Step, error) { e.logger.WithFields(logrus.Fields{ "step": s.GetNumber(), }).Tracef("updating step %s in the database", s.GetName()) @@ -27,12 +27,11 @@ func (e *engine) UpdateStep(s *library.Step) error { // https://pkg.go.dev/github.com/go-vela/types/database#Step.Validate err := step.Validate() if err != nil { - return err + return nil, err } // send query to the database - return e.client. - Table(constants.TableStep). - Save(step). - Error + result := e.client.Table(constants.TableStep).Save(step) + + return step.ToLibrary(), result.Error } diff --git a/database/step/update_test.go b/database/step/update_test.go index c2a10a113..38d8c1bdb 100644 --- a/database/step/update_test.go +++ b/database/step/update_test.go @@ -5,6 +5,7 @@ package step import ( + "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -33,7 +34,7 @@ WHERE "id" = $16`). _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateStep(_step) + _, err := _sqlite.CreateStep(_step) if err != nil { t.Errorf("unable to create test step for sqlite: %v", err) } @@ -59,7 +60,7 @@ WHERE "id" = $16`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err = test.database.UpdateStep(_step) + got, err := test.database.UpdateStep(_step) if test.failure { if err == nil { @@ -72,6 +73,10 @@ WHERE "id" = $16`). if err != nil { t.Errorf("UpdateStep for %s returned err: %v", test.name, err) } + + if !reflect.DeepEqual(got, _step) { + t.Errorf("UpdateStep for %s returned %s, want %s", test.name, got, _step) + } }) } } diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index 6c9aede32..9ca2c8faf 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -89,7 +89,7 @@ func TestStep_Establish(t *testing.T) { _, _ = db.CreateRepo(context.TODO(), r) _, _ = db.CreateBuild(context.TODO(), b) - _ = db.CreateStep(want) + _, _ = db.CreateStep(want) // setup context gin.SetMode(gin.TestMode) From 172a998c8e3161af5524b38737382446ebdf3cb5 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:10:33 -0500 Subject: [PATCH 295/298] feat(queue)!: add priv/pub key signing (#843) --- cmd/vela-server/queue.go | 11 +-- cmd/vela-server/server.go | 1 + docker-compose.yml | 2 + go.mod | 2 +- queue/flags.go | 12 +++ queue/redis/length_test.go | 2 +- queue/redis/opts.go | 74 +++++++++++++++++ queue/redis/opts_test.go | 137 ++++++++++++++++++++++++++++++++ queue/redis/pop.go | 23 +++++- queue/redis/pop_test.go | 18 +++-- queue/redis/push.go | 20 ++++- queue/redis/push_test.go | 4 +- queue/redis/redis.go | 8 +- queue/redis/redis_test.go | 4 +- queue/redis/route_test.go | 2 +- queue/setup.go | 6 ++ router/middleware/queue_test.go | 3 +- router/middleware/signing.go | 18 +++++ 18 files changed, 326 insertions(+), 21 deletions(-) create mode 100644 router/middleware/signing.go diff --git a/cmd/vela-server/queue.go b/cmd/vela-server/queue.go index 677137e18..edd703e69 100644 --- a/cmd/vela-server/queue.go +++ b/cmd/vela-server/queue.go @@ -18,11 +18,12 @@ func setupQueue(c *cli.Context) (queue.Service, error) { // queue configuration _setup := &queue.Setup{ - Driver: c.String("queue.driver"), - Address: c.String("queue.addr"), - Cluster: c.Bool("queue.cluster"), - Routes: c.StringSlice("queue.routes"), - Timeout: c.Duration("queue.pop.timeout"), + Driver: c.String("queue.driver"), + Address: c.String("queue.addr"), + Cluster: c.Bool("queue.cluster"), + Routes: c.StringSlice("queue.routes"), + Timeout: c.Duration("queue.pop.timeout"), + PrivateKey: c.String("queue.private-key"), } // setup the queue diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index d18a74278..cb9f0edd1 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -98,6 +98,7 @@ func server(c *cli.Context) error { middleware.Secret(c.String("vela-secret")), middleware.Secrets(secrets), middleware.Scm(scm), + middleware.QueueSigningPrivateKey(c.String("queue.private-key")), middleware.Allowlist(c.StringSlice("vela-repo-allowlist")), middleware.DefaultBuildLimit(c.Int64("default-build-limit")), middleware.DefaultTimeout(c.Int64("default-build-timeout")), diff --git a/docker-compose.yml b/docker-compose.yml index 09e729ee8..824b461a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,6 +42,7 @@ services: VELA_USER_ACCESS_TOKEN_DURATION: 60m VELA_DISABLE_WEBHOOK_VALIDATION: 'true' VELA_ENABLE_SECURE_COOKIE: 'false' + VELA_QUEUE_SIGNING_PRIVATE_KEY: 'tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==' VELA_REPO_ALLOWLIST: '*' VELA_SCHEDULE_ALLOWLIST: '*' env_file: @@ -78,6 +79,7 @@ services: VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' WORKER_ADDR: 'http://worker:8080' WORKER_CHECK_IN: 5m + VELA_QUEUE_SIGNING_PUBLIC_KEY: 'DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=' restart: always ports: - '8081:8080' diff --git a/go.mod b/go.mod index addeed1ab..788f5cdb0 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/spf13/afero v1.9.5 github.com/urfave/cli/v2 v2.25.7 go.starlark.net v0.0.0-20230725161458-0d7263928a74 + golang.org/x/crypto v0.11.0 golang.org/x/oauth2 v0.9.0 golang.org/x/sync v0.3.0 gopkg.in/square/go-jose.v2 v2.6.0 @@ -116,7 +117,6 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.11.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect diff --git a/queue/flags.go b/queue/flags.go index 0fd1e23a6..9f2c508ee 100644 --- a/queue/flags.go +++ b/queue/flags.go @@ -50,4 +50,16 @@ var Flags = []cli.Flag{ Usage: "timeout for requests that pop items off the queue", Value: 60 * time.Second, }, + &cli.StringFlag{ + EnvVars: []string{"VELA_QUEUE_SIGNING_PRIVATE_KEY"}, + FilePath: "/vela/signing.key", + Name: "queue.private-key", + Usage: "set value of base64 encoded queue signing private key", + }, + &cli.StringFlag{ + EnvVars: []string{"VELA_QUEUE_SIGNING_PUBLIC_KEY"}, + FilePath: "/vela/signing.pub", + Name: "queue.public-key", + Usage: "set value of base64 encoded queue signing public key", + }, } diff --git a/queue/redis/length_test.go b/queue/redis/length_test.go index c97a5b3f8..d9622594c 100644 --- a/queue/redis/length_test.go +++ b/queue/redis/length_test.go @@ -29,7 +29,7 @@ func TestRedis_Length(t *testing.T) { } // setup redis mock - _redis, err := NewTest("vela", "vela:second", "vela:third") + _redis, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela", "vela:second", "vela:third") if err != nil { t.Errorf("unable to create queue service: %v", err) } diff --git a/queue/redis/opts.go b/queue/redis/opts.go index aabcfea05..5589eeb92 100644 --- a/queue/redis/opts.go +++ b/queue/redis/opts.go @@ -5,6 +5,8 @@ package redis import ( + "encoding/base64" + "errors" "fmt" "time" ) @@ -69,3 +71,75 @@ func WithTimeout(timeout time.Duration) ClientOpt { return nil } } + +// WithPrivateKey sets the private key in the queue client for Redis. +// +//nolint:dupl // ignore similar code +func WithPrivateKey(key string) ClientOpt { + return func(c *client) error { + c.Logger.Trace("configuring private key in redis queue client") + + if len(key) == 0 { + c.Logger.Warn("unable to base64 decode private key, provided key is empty. queue service will be unable to sign items") + return nil + } + + decoded, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return err + } + + if len(decoded) == 0 { + return errors.New("unable to base64 decode private key, decoded key is empty") + } + + c.config.PrivateKey = new([64]byte) + copy(c.config.PrivateKey[:], decoded) + + if c.config.PrivateKey == nil { + return errors.New("unable to copy decoded queue signing private key, copied key is nil") + } + + if len(c.config.PrivateKey) == 0 { + return errors.New("unable to copy decoded queue signing private key, copied key is empty") + } + + return nil + } +} + +// WithPublicKey sets the public key in the queue client for Redis. +// +//nolint:dupl // ignore similar code +func WithPublicKey(key string) ClientOpt { + return func(c *client) error { + c.Logger.Tracef("configuring public key in redis queue client") + + if len(key) == 0 { + c.Logger.Warn("unable to base64 decode public key, provided key is empty. queue service will be unable to open items") + return nil + } + + decoded, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return err + } + + if len(decoded) == 0 { + return errors.New("unable to base64 decode public key, decoded key is empty") + } + + c.config.PublicKey = new([32]byte) + copy(c.config.PublicKey[:], decoded) + + if c.config.PublicKey == nil { + return errors.New("unable to copy decoded queue signing public key, copied key is nil") + } + + if len(c.config.PublicKey) == 0 { + return errors.New("unable to copy decoded queue signing public key, copied key is empty") + } + + return nil + } +} diff --git a/queue/redis/opts_test.go b/queue/redis/opts_test.go index b44e79418..3f99e3857 100644 --- a/queue/redis/opts_test.go +++ b/queue/redis/opts_test.go @@ -5,6 +5,7 @@ package redis import ( + "encoding/base64" "fmt" "reflect" "testing" @@ -180,3 +181,139 @@ func TestRedis_ClientOpt_WithCluster(t *testing.T) { } } } + +func TestRedis_ClientOpt_WithSigningPrivateKey(t *testing.T) { + // setup tests + // create a local fake redis instance + // + // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run + _redis, err := miniredis.Run() + if err != nil { + t.Errorf("unable to create miniredis instance: %v", err) + } + defer _redis.Close() + + tests := []struct { + failure bool + privKey string + want string + }{ + { //valid key input + failure: false, + privKey: "tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==", + want: "tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==", + }, + { //empty key input + failure: false, + privKey: "", + want: "", + }, + { //invalid base64 encoded input + failure: true, + privKey: "abc123", + want: "", + }, + } + + // run tests + for _, test := range tests { + _service, err := New( + WithAddress(fmt.Sprintf("redis://%s", _redis.Addr())), + WithPrivateKey(test.privKey), + ) + + if test.failure { + if err == nil { + t.Errorf("WithPrivateKey should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("WithPrivateKey returned err: %v", err) + } + + got := "" + if _service.config.PrivateKey != nil { + got = fmt.Sprintf("%s", *_service.config.PrivateKey) + } else { + got = "" + } + + w, _ := base64.StdEncoding.DecodeString(test.want) + + want := string(w) + if !reflect.DeepEqual(got, want) { + t.Errorf("WithPrivateKey is %v, want %v", got, want) + } + } +} + +func TestRedis_ClientOpt_WithSigningPublicKey(t *testing.T) { + // setup tests + // create a local fake redis instance + // + // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run + _redis, err := miniredis.Run() + if err != nil { + t.Errorf("unable to create miniredis instance: %v", err) + } + defer _redis.Close() + + tests := []struct { + failure bool + pubKey string + want string + }{ + { //valid key input + failure: false, + pubKey: "DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=", + want: "DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=", + }, + { //empty key input + failure: false, + pubKey: "", + want: "", + }, + { //invalid base64 encoded input + failure: true, + pubKey: "abc123", + want: "", + }, + } + + // run tests + for _, test := range tests { + _service, err := New( + WithAddress(fmt.Sprintf("redis://%s", _redis.Addr())), + WithPublicKey(test.pubKey), + ) + + if test.failure { + if err == nil { + t.Errorf("WithPublicKey should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("WithPublicKey returned err: %v", err) + } + + got := "" + if _service.config.PublicKey != nil { + got = fmt.Sprintf("%s", *_service.config.PublicKey) + } else { + got = "" + } + + w, _ := base64.StdEncoding.DecodeString(test.want) + + want := string(w) + if !reflect.DeepEqual(got, want) { + t.Errorf("SigningPublicKey is %v, want %v", got, want) + } + } +} diff --git a/queue/redis/pop.go b/queue/redis/pop.go index 88151649b..732092c32 100644 --- a/queue/redis/pop.go +++ b/queue/redis/pop.go @@ -11,6 +11,7 @@ import ( "github.com/go-vela/types" "github.com/redis/go-redis/v9" + "golang.org/x/crypto/nacl/sign" ) // Pop grabs an item from the specified channel off the queue. @@ -35,10 +36,28 @@ func (c *client) Pop(ctx context.Context) (*types.Item, error) { return nil, err } - item := new(types.Item) + // this should already be validated on startup + if c.config.PublicKey == nil || len(*c.config.PublicKey) != 32 { + return nil, errors.New("no valid signing public key provided") + } + + // extract signed item from pop results + signed := []byte(result[1]) + + var opened, out []byte + + // open the item using the public key generated using sign + // + // https://pkg.go.dev/golang.org/x/crypto@v0.1.0/nacl/sign + opened, ok := sign.Open(out, signed, c.config.PublicKey) + if !ok { + return nil, errors.New("unable to open signed item") + } // unmarshal result into queue item - err = json.Unmarshal([]byte(result[1]), item) + item := new(types.Item) + + err = json.Unmarshal(opened, item) if err != nil { return nil, err } diff --git a/queue/redis/pop_test.go b/queue/redis/pop_test.go index cb8209e1d..1f19bf2c3 100644 --- a/queue/redis/pop_test.go +++ b/queue/redis/pop_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/go-vela/types" + "golang.org/x/crypto/nacl/sign" "gopkg.in/square/go-jose.v2/json" ) @@ -23,6 +24,9 @@ func TestRedis_Pop(t *testing.T) { User: _user, } + var signed []byte + var out []byte + // setup queue item bytes, err := json.Marshal(_item) if err != nil { @@ -30,19 +34,21 @@ func TestRedis_Pop(t *testing.T) { } // setup redis mock - _redis, err := NewTest("vela") + _redis, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela") if err != nil { t.Errorf("unable to create queue service: %v", err) } + signed = sign.Sign(out, bytes, _redis.config.PrivateKey) + // push item to queue - err = _redis.Redis.RPush(context.Background(), "vela", bytes).Err() + err = _redis.Redis.RPush(context.Background(), "vela", signed).Err() if err != nil { t.Errorf("unable to push item to queue: %v", err) } // setup timeout redis mock - timeout, err := NewTest("vela") + timeout, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela") if err != nil { t.Errorf("unable to create queue service: %v", err) } @@ -50,15 +56,17 @@ func TestRedis_Pop(t *testing.T) { timeout.config.Timeout = 1 * time.Second // setup badChannel redis mock - badChannel, err := NewTest("vela") + badChannel, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela") if err != nil { t.Errorf("unable to create queue service: %v", err) } // overwrite channel to be invalid badChannel.config.Channels = nil + signed = sign.Sign(out, bytes, badChannel.config.PrivateKey) + // push something to badChannel queue - err = badChannel.Redis.RPush(context.Background(), "vela", bytes).Err() + err = badChannel.Redis.RPush(context.Background(), "vela", signed).Err() if err != nil { t.Errorf("unable to push item to queue: %v", err) } diff --git a/queue/redis/push.go b/queue/redis/push.go index 7ba97654f..66c8a386a 100644 --- a/queue/redis/push.go +++ b/queue/redis/push.go @@ -7,6 +7,8 @@ package redis import ( "context" "errors" + + "golang.org/x/crypto/nacl/sign" ) // Push inserts an item to the specified channel in the queue. @@ -21,10 +23,26 @@ func (c *client) Push(ctx context.Context, channel string, item []byte) error { return errors.New("item is nil") } + var signed []byte + + var out []byte + + // this should already be validated on startup + if c.config.PrivateKey == nil || len(*c.config.PrivateKey) != 64 { + return errors.New("no valid signing private key provided") + } + + c.Logger.Tracef("signing item for queue %s", channel) + + // sign the item using the private key generated using sign + // + // https://pkg.go.dev/golang.org/x/crypto@v0.1.0/nacl/sign + signed = sign.Sign(out, item, c.config.PrivateKey) + // build a redis queue command to push an item to queue // // https://pkg.go.dev/github.com/go-redis/redis?tab=doc#Client.RPush - pushCmd := c.Redis.RPush(ctx, channel, item) + pushCmd := c.Redis.RPush(ctx, channel, signed) // blocking call to push an item to queue and return err // diff --git a/queue/redis/push_test.go b/queue/redis/push_test.go index 74e815926..e61792ea9 100644 --- a/queue/redis/push_test.go +++ b/queue/redis/push_test.go @@ -28,13 +28,13 @@ func TestRedis_Push(t *testing.T) { } // setup redis mock - _redis, err := NewTest("vela") + _redis, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela") if err != nil { t.Errorf("unable to create queue service: %v", err) } // setup redis mock - badItem, err := NewTest("vela") + badItem, err := NewTest(_signingPrivateKey, _signingPublicKey, "vela") if err != nil { t.Errorf("unable to create queue service: %v", err) } diff --git a/queue/redis/redis.go b/queue/redis/redis.go index 6ed111ec8..4e4f68aea 100644 --- a/queue/redis/redis.go +++ b/queue/redis/redis.go @@ -25,6 +25,10 @@ type config struct { Cluster bool // specifies the timeout to use for the Redis client Timeout time.Duration + // key for signing items pushed to the Redis client + PrivateKey *[64]byte + // key for opening items popped from the Redis client + PublicKey *[32]byte } type client struct { @@ -173,7 +177,7 @@ func pingQueue(c *client) error { // This function is intended for running tests only. // //nolint:revive // ignore returning unexported client -func NewTest(channels ...string) (*client, error) { +func NewTest(signingPrivateKey, signingPublicKey string, channels ...string) (*client, error) { // create a local fake redis instance // // https://pkg.go.dev/github.com/alicebob/miniredis/v2#Run @@ -186,5 +190,7 @@ func NewTest(channels ...string) (*client, error) { WithAddress(fmt.Sprintf("redis://%s", _redis.Addr())), WithChannels(channels...), WithCluster(false), + WithPrivateKey(signingPrivateKey), + WithPublicKey(signingPublicKey), ) } diff --git a/queue/redis/redis_test.go b/queue/redis/redis_test.go index aa1bf1a0f..6935a676d 100644 --- a/queue/redis/redis_test.go +++ b/queue/redis/redis_test.go @@ -46,7 +46,9 @@ func Strings(v []string) *[]string { return &v } // setup global variables used for testing. var ( - _build = &library.Build{ + _signingPrivateKey = "tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==" + _signingPublicKey = "DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=" + _build = &library.Build{ ID: Int64(1), Number: Int(1), Parent: Int(1), diff --git a/queue/redis/route_test.go b/queue/redis/route_test.go index de3f99fc9..23328df43 100644 --- a/queue/redis/route_test.go +++ b/queue/redis/route_test.go @@ -14,7 +14,7 @@ import ( func TestRedis_Client_Route(t *testing.T) { // setup - client, _ := NewTest("vela", "16cpu8gb", "16cpu8gb:gcp", "gcp") + client, _ := NewTest(_signingPrivateKey, _signingPublicKey, "vela", "16cpu8gb", "16cpu8gb:gcp", "gcp") tests := []struct { success bool want string diff --git a/queue/setup.go b/queue/setup.go index ae69a1429..ed0f131c8 100644 --- a/queue/setup.go +++ b/queue/setup.go @@ -30,6 +30,10 @@ type Setup struct { Routes []string // specifies the timeout for pop requests for the queue client Timeout time.Duration + // private key in base64 used for signing items pushed to the queue + PrivateKey string + // public key in base64 used for opening items popped from the queue + PublicKey string } // Redis creates and returns a Vela service capable @@ -45,6 +49,8 @@ func (s *Setup) Redis() (Service, error) { redis.WithChannels(s.Routes...), redis.WithCluster(s.Cluster), redis.WithTimeout(s.Timeout), + redis.WithPrivateKey(s.PrivateKey), + redis.WithPublicKey(s.PublicKey), ) } diff --git a/router/middleware/queue_test.go b/router/middleware/queue_test.go index cfbd94010..80c22ce07 100644 --- a/router/middleware/queue_test.go +++ b/router/middleware/queue_test.go @@ -20,7 +20,8 @@ func TestMiddleware_Queue(t *testing.T) { // setup types var got queue.Service - want, _ := redis.NewTest() + // signing keys are irrelevant here + want, _ := redis.NewTest("", "") // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/signing.go b/router/middleware/signing.go new file mode 100644 index 000000000..05c63b8e5 --- /dev/null +++ b/router/middleware/signing.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +// QueueSigningPrivateKey is a middleware function that attaches the private key used +// to sign items that are pushed to the queue. +func QueueSigningPrivateKey(key string) gin.HandlerFunc { + return func(c *gin.Context) { + c.Set("queue.private-key", key) + c.Next() + } +} From 2187e6b6ed99f40af4f36aa8734c5ba83b20e341 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:44:12 -0500 Subject: [PATCH 296/298] chore: simplify queue env variable names (#939) --- docker-compose.yml | 4 ++-- queue/flags.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 824b461a3..6a596e45e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,6 +28,7 @@ services: DATABASE_ENCRYPTION_KEY: 'C639A572E14D5075C526FDDD43E4ECF6' QUEUE_DRIVER: redis QUEUE_ADDR: 'redis://redis:6379' + QUEUE_PRIVATE_KEY: 'tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==' SCM_DRIVER: github SCM_CONTEXT: 'continuous-integration/vela' SECRET_VAULT: 'true' @@ -42,7 +43,6 @@ services: VELA_USER_ACCESS_TOKEN_DURATION: 60m VELA_DISABLE_WEBHOOK_VALIDATION: 'true' VELA_ENABLE_SECURE_COOKIE: 'false' - VELA_QUEUE_SIGNING_PRIVATE_KEY: 'tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==' VELA_REPO_ALLOWLIST: '*' VELA_SCHEDULE_ALLOWLIST: '*' env_file: @@ -70,6 +70,7 @@ services: EXECUTOR_DRIVER: linux QUEUE_DRIVER: redis QUEUE_ADDR: 'redis://redis:6379' + QUEUE_PUBLIC_KEY: 'DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=' VELA_BUILD_LIMIT: 1 VELA_BUILD_TIMEOUT: 30m VELA_LOG_LEVEL: trace @@ -79,7 +80,6 @@ services: VELA_SERVER_SECRET: 'zB7mrKDTZqNeNTD8z47yG4DHywspAh' WORKER_ADDR: 'http://worker:8080' WORKER_CHECK_IN: 5m - VELA_QUEUE_SIGNING_PUBLIC_KEY: 'DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=' restart: always ports: - '8081:8080' diff --git a/queue/flags.go b/queue/flags.go index 9f2c508ee..b5ede4733 100644 --- a/queue/flags.go +++ b/queue/flags.go @@ -51,13 +51,13 @@ var Flags = []cli.Flag{ Value: 60 * time.Second, }, &cli.StringFlag{ - EnvVars: []string{"VELA_QUEUE_SIGNING_PRIVATE_KEY"}, + EnvVars: []string{"QUEUE_PRIVATE_KEY"}, FilePath: "/vela/signing.key", Name: "queue.private-key", Usage: "set value of base64 encoded queue signing private key", }, &cli.StringFlag{ - EnvVars: []string{"VELA_QUEUE_SIGNING_PUBLIC_KEY"}, + EnvVars: []string{"QUEUE_PUBLIC_KEY"}, FilePath: "/vela/signing.pub", Name: "queue.public-key", Usage: "set value of base64 encoded queue signing public key", From 6a15df6816dd6b358da51d4bbe16d9ed50522f94 Mon Sep 17 00:00:00 2001 From: dave vader <48764154+plyr4@users.noreply.github.com> Date: Mon, 28 Aug 2023 09:27:05 -0500 Subject: [PATCH 297/298] enhance: add context to Executables (#937) Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- api/build/executable.go | 3 +- api/build/publish.go | 2 +- database/executable/create.go | 3 +- database/executable/create_test.go | 3 +- database/executable/executable.go | 5 ++- database/executable/interface.go | 12 ++++--- database/executable/opts.go | 11 +++++++ database/executable/opts_test.go | 50 ++++++++++++++++++++++++++++++ database/executable/pop.go | 4 ++- database/executable/pop_test.go | 5 +-- database/executable/table.go | 8 +++-- database/executable/table_test.go | 3 +- database/integration_test.go | 4 +-- database/resource.go | 1 + 14 files changed, 97 insertions(+), 17 deletions(-) diff --git a/api/build/executable.go b/api/build/executable.go index 832e5abeb..9df63467d 100644 --- a/api/build/executable.go +++ b/api/build/executable.go @@ -70,6 +70,7 @@ func GetBuildExecutable(c *gin.Context) { o := org.Retrieve(c) r := repo.Retrieve(c) cl := claims.Retrieve(c) + ctx := c.Request.Context() // update engine logger with API metadata // @@ -81,7 +82,7 @@ func GetBuildExecutable(c *gin.Context) { "subject": cl.Subject, }).Infof("reading build executable %s/%d", r.GetFullName(), b.GetNumber()) - bExecutable, err := database.FromContext(c).PopBuildExecutable(b.GetID()) + bExecutable, err := database.FromContext(c).PopBuildExecutable(ctx, b.GetID()) if err != nil { retErr := fmt.Errorf("unable to pop build executable: %w", err) util.HandleError(c, http.StatusInternalServerError, retErr) diff --git a/api/build/publish.go b/api/build/publish.go index f5e144232..51f94cff2 100644 --- a/api/build/publish.go +++ b/api/build/publish.go @@ -34,7 +34,7 @@ func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interf bExecutable.SetBuildID(b.GetID()) bExecutable.SetData(byteExecutable) - err = db.CreateBuildExecutable(bExecutable) + err = db.CreateBuildExecutable(ctx, bExecutable) if err != nil { logrus.Errorf("Failed to publish build executable to database %d for %s: %v", b.GetNumber(), r.GetFullName(), err) diff --git a/database/executable/create.go b/database/executable/create.go index 002ac03bc..ac29ec768 100644 --- a/database/executable/create.go +++ b/database/executable/create.go @@ -5,6 +5,7 @@ package executable import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -14,7 +15,7 @@ import ( ) // CreateBuildExecutable creates a new build executable in the database. -func (e *engine) CreateBuildExecutable(b *library.BuildExecutable) error { +func (e *engine) CreateBuildExecutable(ctx context.Context, b *library.BuildExecutable) error { e.logger.WithFields(logrus.Fields{ "build": b.GetBuildID(), }).Tracef("creating build executable for build %d in the database", b.GetBuildID()) diff --git a/database/executable/create_test.go b/database/executable/create_test.go index abf047f79..e3f664314 100644 --- a/database/executable/create_test.go +++ b/database/executable/create_test.go @@ -5,6 +5,7 @@ package executable import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -53,7 +54,7 @@ VALUES ($1,$2,$3) RETURNING "id"`). // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateBuildExecutable(_bExecutable) + err := test.database.CreateBuildExecutable(context.TODO(), _bExecutable) if test.failure { if err == nil { diff --git a/database/executable/executable.go b/database/executable/executable.go index c53759192..556d86754 100644 --- a/database/executable/executable.go +++ b/database/executable/executable.go @@ -5,6 +5,7 @@ package executable import ( + "context" "fmt" "github.com/go-vela/types/constants" @@ -31,6 +32,8 @@ type ( // engine configuration settings used in build executable functions config *config + ctx context.Context + // gorm.io/gorm database client used in build executable functions // // https://pkg.go.dev/gorm.io/gorm#DB @@ -71,7 +74,7 @@ func New(opts ...EngineOpt) (*engine, error) { } // create the build executables table - err := e.CreateBuildExecutableTable(e.client.Config.Dialector.Name()) + err := e.CreateBuildExecutableTable(e.ctx, e.client.Config.Dialector.Name()) if err != nil { return nil, fmt.Errorf("unable to create %s table: %w", constants.TableBuildExecutable, err) } diff --git a/database/executable/interface.go b/database/executable/interface.go index 852d77872..9e3bd50b3 100644 --- a/database/executable/interface.go +++ b/database/executable/interface.go @@ -4,7 +4,11 @@ package executable -import "github.com/go-vela/types/library" +import ( + "context" + + "github.com/go-vela/types/library" +) // BuildExecutableInterface represents the Vela interface for build executable // functions with the supported Database backends. @@ -12,14 +16,14 @@ type BuildExecutableInterface interface { // BuildExecutable Data Definition Language Functions // // https://en.wikipedia.org/wiki/Data_definition_language - CreateBuildExecutableTable(string) error + CreateBuildExecutableTable(context.Context, string) error // BuildExecutable Data Manipulation Language Functions // // https://en.wikipedia.org/wiki/Data_manipulation_language // CreateBuildExecutable defines a function that creates a build executable. - CreateBuildExecutable(*library.BuildExecutable) error + CreateBuildExecutable(context.Context, *library.BuildExecutable) error // PopBuildExecutable defines a function that gets and deletes a build executable. - PopBuildExecutable(int64) (*library.BuildExecutable, error) + PopBuildExecutable(context.Context, int64) (*library.BuildExecutable, error) } diff --git a/database/executable/opts.go b/database/executable/opts.go index 1d91a4a54..fa601a03d 100644 --- a/database/executable/opts.go +++ b/database/executable/opts.go @@ -5,6 +5,8 @@ package executable import ( + "context" + "github.com/sirupsen/logrus" "gorm.io/gorm" @@ -72,3 +74,12 @@ func WithSkipCreation(skipCreation bool) EngineOpt { return nil } } + +// WithContext sets the context in the database engine for build executables. +func WithContext(ctx context.Context) EngineOpt { + return func(e *engine) error { + e.ctx = ctx + + return nil + } +} diff --git a/database/executable/opts_test.go b/database/executable/opts_test.go index 6bb89d0ae..61876dd32 100644 --- a/database/executable/opts_test.go +++ b/database/executable/opts_test.go @@ -5,6 +5,7 @@ package executable import ( + "context" "reflect" "testing" @@ -263,3 +264,52 @@ func TestExecutable_EngineOpt_WithSkipCreation(t *testing.T) { }) } } + +func TestExecutable_EngineOpt_WithContext(t *testing.T) { + // setup types + e := &engine{config: new(config)} + + // setup tests + tests := []struct { + failure bool + name string + ctx context.Context + want context.Context + }{ + { + failure: false, + name: "context set to TODO", + ctx: context.TODO(), + want: context.TODO(), + }, + { + failure: false, + name: "context set to nil", + ctx: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := WithContext(test.ctx)(e) + + if test.failure { + if err == nil { + t.Errorf("WithContext for %s should have returned err", test.name) + } + + return + } + + if err != nil { + t.Errorf("WithContext returned err: %v", err) + } + + if !reflect.DeepEqual(e.ctx, test.want) { + t.Errorf("WithContext is %v, want %v", e.ctx, test.want) + } + }) + } +} diff --git a/database/executable/pop.go b/database/executable/pop.go index c38d472bc..64a2fbcf5 100644 --- a/database/executable/pop.go +++ b/database/executable/pop.go @@ -5,6 +5,8 @@ package executable import ( + "context" + "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" @@ -12,7 +14,7 @@ import ( ) // PopBuildExecutable pops a build executable by build_id from the database. -func (e *engine) PopBuildExecutable(id int64) (*library.BuildExecutable, error) { +func (e *engine) PopBuildExecutable(ctx context.Context, id int64) (*library.BuildExecutable, error) { e.logger.Tracef("popping build executable for build %d from the database", id) // variable to store query results diff --git a/database/executable/pop_test.go b/database/executable/pop_test.go index b89dcec9e..cf282d013 100644 --- a/database/executable/pop_test.go +++ b/database/executable/pop_test.go @@ -5,6 +5,7 @@ package executable import ( + "context" "reflect" "testing" @@ -33,7 +34,7 @@ func TestExecutable_Engine_PopBuildExecutable(t *testing.T) { _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() - err := _sqlite.CreateBuildExecutable(_bExecutable) + err := _sqlite.CreateBuildExecutable(context.TODO(), _bExecutable) if err != nil { t.Errorf("unable to create test build executable for sqlite: %v", err) } @@ -62,7 +63,7 @@ func TestExecutable_Engine_PopBuildExecutable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.PopBuildExecutable(1) + got, err := test.database.PopBuildExecutable(context.TODO(), 1) if test.failure { if err == nil { diff --git a/database/executable/table.go b/database/executable/table.go index c2b3323b2..c36834fe6 100644 --- a/database/executable/table.go +++ b/database/executable/table.go @@ -4,7 +4,11 @@ package executable -import "github.com/go-vela/types/constants" +import ( + "context" + + "github.com/go-vela/types/constants" +) const ( // CreatePostgresTable represents a query to create the Postgres build_executables table. @@ -33,7 +37,7 @@ build_executables ( ) // CreateBuildExecutableTable creates the build executables table in the database. -func (e *engine) CreateBuildExecutableTable(driver string) error { +func (e *engine) CreateBuildExecutableTable(ctx context.Context, driver string) error { e.logger.Tracef("creating build_executables table in the database") // handle the driver provided to create the table diff --git a/database/executable/table_test.go b/database/executable/table_test.go index ed203b113..b4f3cd057 100644 --- a/database/executable/table_test.go +++ b/database/executable/table_test.go @@ -5,6 +5,7 @@ package executable import ( + "context" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -41,7 +42,7 @@ func TestExecutable_Engine_CreateBuildExecutableTable(t *testing.T) { // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - err := test.database.CreateBuildExecutableTable(test.name) + err := test.database.CreateBuildExecutableTable(context.TODO(), test.name) if test.failure { if err == nil { diff --git a/database/integration_test.go b/database/integration_test.go index 669fa3907..30d6ff696 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -405,7 +405,7 @@ func testExecutables(t *testing.T, db Interface, resources *Resources) { // create the pipelines for _, executable := range resources.Executables { - err := db.CreateBuildExecutable(executable) + err := db.CreateBuildExecutable(context.TODO(), executable) if err != nil { t.Errorf("unable to create executable %d: %v", executable.GetID(), err) } @@ -414,7 +414,7 @@ func testExecutables(t *testing.T, db Interface, resources *Resources) { // pop executables for builds for _, executable := range resources.Executables { - got, err := db.PopBuildExecutable(executable.GetBuildID()) + got, err := db.PopBuildExecutable(context.TODO(), executable.GetBuildID()) if err != nil { t.Errorf("unable to get executable %d for build %d: %v", executable.GetID(), executable.GetBuildID(), err) } diff --git a/database/resource.go b/database/resource.go index 482834ecf..74a4b8fe5 100644 --- a/database/resource.go +++ b/database/resource.go @@ -38,6 +38,7 @@ func (e *engine) NewResources(ctx context.Context) error { // create the database agnostic engine for build_executables e.BuildExecutableInterface, err = executable.New( + executable.WithContext(e.ctx), executable.WithClient(e.client), executable.WithLogger(e.logger), executable.WithSkipCreation(e.config.SkipCreation), From 1b95cf6ffa26197e174c348a493cdef9c1feb689 Mon Sep 17 00:00:00 2001 From: Colin Dean Date: Mon, 28 Aug 2023 16:20:11 -0400 Subject: [PATCH 298/298] Increase Starlark execution limit, abstract limit resolver 5,000 was too few to enable the example added to the testdata to work, so was 6,000. I chose 7,500 arbitrarily after a test at 10,000 and both worked. In the long term, this should probably be configurable so as not to require recompilation. For now, this kicks the can down the road while allowing this build matrix use case to exist. --- compiler/template/starlark/render.go | 17 +- compiler/template/starlark/render_test.go | 6 +- .../starlark/testdata/build/large/build.star | 202 ++++++++++++++++++ 3 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 compiler/template/starlark/testdata/build/large/build.star diff --git a/compiler/template/starlark/render.go b/compiler/template/starlark/render.go index 0be1063f5..96b2f1b3d 100644 --- a/compiler/template/starlark/render.go +++ b/compiler/template/starlark/render.go @@ -38,7 +38,7 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM // arbitrarily limiting the steps of the thread to 5000 to help prevent infinite loops // may need to further investigate spawning a separate POSIX process if user input is problematic // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details - thread.SetMaxExecutionSteps(5000) + thread.SetMaxExecutionSteps(GetStarlarkExecutionStepLimit()) predeclared := starlark.StringDict{"struct": starlark.NewBuiltin("struct", starlarkstruct.Make)} @@ -136,6 +136,15 @@ func Render(tmpl string, name string, tName string, environment raw.StringSliceM return &types.Build{Steps: config.Steps, Secrets: config.Secrets, Services: config.Services, Environment: config.Environment}, nil } +// GetStarlarkExecutionStepLimit may eventually look up config or calculate it +func GetStarlarkExecutionStepLimit() uint64 { + // arbitrarily limiting the steps of the thread to help prevent infinite loops + // may need to further investigate spawning a separate POSIX process if user input is problematic + // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details + // This value was previously 5000 and that inhibited a four-dimensional build matrix from working. + return 7500 +} + // RenderBuild renders the templated build. // //nolint:lll // ignore function length due to input args @@ -143,10 +152,8 @@ func RenderBuild(tmpl string, b string, envs map[string]string, variables map[st config := new(types.Build) thread := &starlark.Thread{Name: "templated-base"} - // arbitrarily limiting the steps of the thread to 5000 to help prevent infinite loops - // may need to further investigate spawning a separate POSIX process if user input is problematic - // see https://github.com/google/starlark-go/issues/160#issuecomment-466794230 for further details - thread.SetMaxExecutionSteps(5000) + + thread.SetMaxExecutionSteps(GetStarlarkExecutionStepLimit()) predeclared := starlark.StringDict{"struct": starlark.NewBuiltin("struct", starlarkstruct.Make)} diff --git a/compiler/template/starlark/render_test.go b/compiler/template/starlark/render_test.go index 8cc089e47..c602bac38 100644 --- a/compiler/template/starlark/render_test.go +++ b/compiler/template/starlark/render_test.go @@ -92,6 +92,8 @@ func TestStarlark_Render(t *testing.T) { } func TestNative_RenderBuild(t *testing.T) { + noWantFile := "none" + type args struct { velaFile string } @@ -106,6 +108,7 @@ func TestNative_RenderBuild(t *testing.T) { {"stages", args{velaFile: "testdata/build/basic_stages/build.star"}, "testdata/build/basic_stages/want.yml", false}, {"conditional match", args{velaFile: "testdata/build/conditional/build.star"}, "testdata/build/conditional/want.yml", false}, {"steps, with structs", args{velaFile: "testdata/build/with_struct/build.star"}, "testdata/build/with_struct/want.yml", false}, + {"large build to stress execution steps", args{velaFile: "testdata/build/large/build.star"}, noWantFile, false}, } for _, tt := range tests { @@ -118,13 +121,14 @@ func TestNative_RenderBuild(t *testing.T) { got, err := RenderBuild("build", string(sFile), map[string]string{ "VELA_REPO_FULL_NAME": "octocat/hello-world", "VELA_BUILD_BRANCH": "master", + "VELA_REPO_ORG": "octocat", }, map[string]interface{}{}) if (err != nil) != tt.wantErr { t.Errorf("RenderBuild() error = %v, wantErr %v", err, tt.wantErr) return } - if tt.wantErr != true { + if tt.wantErr != true && tt.wantFile != noWantFile { wFile, err := os.ReadFile(tt.wantFile) if err != nil { t.Error(err) diff --git a/compiler/template/starlark/testdata/build/large/build.star b/compiler/template/starlark/testdata/build/large/build.star new file mode 100644 index 000000000..5ffbc482a --- /dev/null +++ b/compiler/template/starlark/testdata/build/large/build.star @@ -0,0 +1,202 @@ +###### +## Setup the build matrix with the base versions a human will maintain. +###### + +DISTRO_WITH_VERSIONS = { + # n.b. these reduce to DockerHub tags + # https://hub.docker.com/_/python/tags?name=alpine + # https://endoflife.date/alpine + 'alpine': [ + '3.17', # EOL 22 Nov 2024 + '3.18' # EOL 09 May 2025 + ], + # https://hub.docker.com/_/python/tags?name=slim + # https://endoflife.date/debian + 'debian': [ + 'slim-bullseye', # EOL 30 Jun 2026 + 'slim-bookworm' # EOL 10 Jun 2028 + ] +} +PYTHON_VERSIONS = [ + '3.8', + '3.9', + '3.10', + '3.11' +] +POETRY_VERSIONS = [ + '1.6.1' +] + +KANIKO_IMAGE = 'target/vela-kaniko:latest' +HADOLINT_IMAGE = 'hadolint/hadolint:v2.12.0-alpine' + + +## The base Docker container build step's config for push builds +def base(): + return { + 'image': KANIKO_IMAGE, + 'ruleset': { + 'event': 'push', + 'branch': 'main' + }, + 'pull': 'not_present', + 'secrets': [ + { + 'source': 'artifactory_password', + 'target': 'docker_password' + } + ] + } + + +## The base Docker container plugin params for push builds +## +## These are parameters passed to Kaniko. +def base_params(): + return { + 'username': 'ibuildallthings', + 'registry': 'docker.example.com', + 'repo': 'docker.example.com/app/multibuild' + } + + +## The step config for pull request builds +def pull_request(): + pr = base() + pr['ruleset']['event'] = 'pull_request' + pr['ruleset'].pop('branch') + return pr + + +## The Kaniko params for pull request builds +def pull_request_params(): + prp = base_params() + prp['dry_run'] = True + return prp + + +## Define a linting stage that uses Hadolint inside of a Make task +## +## This keeps our Dockerfiles tidy and compliant with conventions +def stage_linting(): + return { + 'linting': { + 'steps': [{ + 'name': 'check-docker', + 'image': HADOLINT_IMAGE, + 'pull': 'not_present', + 'commands': [ + 'time apk add --no-cache make', + 'time make check-docker' + ] + }] + } + } + + +## Build stages comprised of a step for push and pull_request builds +def stage_build_tuple(distro, distro_version, python_version, poetry_version): + pr = build_template("build", distro, distro_version, python_version, poetry_version, pull_request(), pull_request_params()) + base_step = build_template("publish", distro, distro_version, python_version, poetry_version, base(), base_params()) + combined = base_step | pr + return combined + + +## Build a single stage for a build tuple, with its base step config and plugin parameters +def build_template(step_name, distro, distro_version, python_version, poetry_version, step_def_base, step_def_params): + return { + ('python_%s_%s_%s %s' % (python_version, distro, distro_version, step_def_base['ruleset']['event'])): { + 'steps': [step_def_base | { + 'name': ('%s python-%s %s %s' % (step_name, python_version, distro, distro_version)), + 'parameters': step_def_params | { + 'dockerfile': ('python-%s.Dockerfile' % distro), + 'build_args': [ + 'PYTHON_VERSION=%s' % python_version, + '%s_VERSION=%s' % (distro.upper(), distro_version), + 'POETRY_VERSION=%s' % poetry_version + ], + 'tags': [ + '%s-%s-%s-%s' % (python_version, distro, distro_version, poetry_version), + '%s-%s-%s' % (python_version, distro, distro_version), + '%s-%s' % (python_version, distro) + ] + } + }] + } + } + + +## Define a stage that uses the Slack template +def stage_slack_notify(needs): + return { + 'slack': { + 'needs': needs, + 'steps': [{ + 'name': 'slack', + 'template': { + 'name': 'slack' + } + }] + } + } + + +## Builds the build matrix in the form of list of tuples from the constants defined at the top of the file +def build_matrix(): + BUILD_MATRIX = [] + for poetry_version in POETRY_VERSIONS: + for python_version in PYTHON_VERSIONS: + for distro in DISTRO_WITH_VERSIONS: + for distro_version in DISTRO_WITH_VERSIONS[distro]: + BUILD_MATRIX.append((distro, + distro_version, + python_version, + poetry_version)) + return BUILD_MATRIX + + +## Construct a secret +def secret(name, key, secret_type, engine='native'): + return {'name': name, 'key': key, 'engine': engine, 'type': secret_type} + + +## Construct a template +def template(name, source, version=None, template_type='github'): + real_source = '%s@%s' % (source, version) if version else source + return { + 'name': name, + 'source': real_source, + 'type': template_type + } + +## The main method, the real deal. +## +## Vela actually calls this function, its return is what Vela uses. +def main(ctx): + # Retrieve the org dynamically since we're using some org secrets + vela_repo_org = ctx['vela']['repo']['org'] if 'vela' in ctx else "UNKNOWN-ORG" + + # Build the stages from the build matrix + build_stages = {} + for (distro, distro_version, python_version, poetry_version) in build_matrix(): + build_stages = build_stages | (stage_build_tuple(distro, distro_version, python_version, poetry_version)) + + # assemble the stage list with the bookends of linting and notifications in place + stages = stage_linting() | build_stages | stage_slack_notify(build_stages.keys()) + + # Build the final output + final = { + 'version': '1', + 'templates': [ + template(name='slack', + source='git.example.com/vela/vela-templates/slack/slack.yml') + ], + 'stages': stages, + 'secrets': [ + secret('artifactory_password','platform/vela-secrets/artifactory_password_for_ibuildallthings', 'shared'), + secret('slack_webhook', vela_repo_org + '/slack_webhook', 'org') + ] + } + + return final +