From b78f65ab6c069ff3245b829a9479bac95865a1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20Gustav=20Str=C3=A5b=C3=B8?= Date: Mon, 11 Mar 2024 14:16:09 +0100 Subject: [PATCH 1/2] use zerolog and gin --- .vscode/launch.json | 2 +- go.mod | 45 ++++++++--- go.sum | 136 +++++++++++++++++++++----------- handler/webhook_handler.go | 29 +++---- handler/webhook_handler_test.go | 90 ++++++++++----------- internal/jwt_token_source.go | 7 +- main.go | 46 ++++++++--- radix/api_server.go | 12 ++- radix/api_server_mock.go | 25 +++--- radix/api_server_stub.go | 32 ++++---- router/router.go | 24 +++--- 11 files changed, 269 insertions(+), 179 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index c035592..1111a59 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,7 +15,7 @@ "API_SERVER_ENDPOINT_PREFIX": "https://server-radix-api-qa", "RADIX_CLUSTERNAME": "weekly-34", "RADIX_DNS_ZONE": "dev.radix.equinor.com", - "BEARER_TOKEN": "", + "BEARER_TOKEN": "fdgdfdg", } } ] diff --git a/go.mod b/go.mod index 847c7c2..888738c 100644 --- a/go.mod +++ b/go.mod @@ -5,35 +5,54 @@ go 1.21 toolchain go1.21.0 require ( + github.com/equinor/radix-common v1.9.0 + github.com/gin-gonic/gin v1.9.1 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/mock v1.6.0 - github.com/google/go-github/v53 v53.2.0 - github.com/gorilla/mux v1.8.1 - github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.18.0 - github.com/sirupsen/logrus v1.9.3 + github.com/google/go-github/v60 v60.0.0 + github.com/prometheus/client_golang v1.19.0 + github.com/rs/zerolog v1.32.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.4 - golang.org/x/oauth2 v0.15.0 + github.com/stretchr/testify v1.9.0 + golang.org/x/oauth2 v0.18.0 ) require ( - github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // 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.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.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/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // 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.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/sys v0.15.0 // indirect + github.com/rs/xid v1.5.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index d0cdff5..5fb30d6 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,37 @@ -github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= -github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= 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/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 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/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= +github.com/equinor/radix-common v1.9.0 h1:tE2y3DdI3wqv9087mnQVXsuBd1BoCfAdvlSSyAIie/A= +github.com/equinor/radix-common v1.9.0/go.mod h1:ekn86U68NT4ccSdt3GT+ukpiclzfuhr96a7zBJKv/jw= +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/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.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +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.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.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 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/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= @@ -22,68 +42,95 @@ 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/google/go-cmp v0.5.2/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v60 v60.0.0 h1:oLG98PsLauFvvu4D/YPxq374jhSxFYdzQGNCyONLfn8= +github.com/google/go-github/v60 v60.0.0/go.mod h1:ByhX2dP9XT9o/ll2yXAu2VD8l5eNVg8hD4Cr0S/LmQk= 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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +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/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/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/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/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 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.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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -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/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -91,31 +138,25 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -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/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= @@ -132,3 +173,4 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV 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= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/handler/webhook_handler.go b/handler/webhook_handler.go index feb6ea3..cc0bf40 100644 --- a/handler/webhook_handler.go +++ b/handler/webhook_handler.go @@ -3,6 +3,7 @@ package handler import ( "bytes" "encoding/json" + "errors" "fmt" "io" "mime" @@ -12,9 +13,8 @@ import ( "github.com/equinor/radix-github-webhook/metrics" "github.com/equinor/radix-github-webhook/models" "github.com/equinor/radix-github-webhook/radix" - "github.com/google/go-github/v53/github" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" + "github.com/google/go-github/v60/github" + "github.com/rs/zerolog" ) const ( @@ -67,12 +67,7 @@ func NewWebHookHandler(apiServer radix.APIServer) *WebHookHandler { } } -// HandleWebhookEvents Main handler of events -func (wh *WebHookHandler) HandleWebhookEvents() http.Handler { - return http.HandlerFunc(wh.handleEvent) -} - -func (wh *WebHookHandler) handleEvent(w http.ResponseWriter, req *http.Request) { +func (wh *WebHookHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Increase metrics counter metrics.IncreaseAllCounter() @@ -83,7 +78,7 @@ func (wh *WebHookHandler) handleEvent(w http.ResponseWriter, req *http.Request) } _succeedWithMessage := func(statusCode int, message string) { - log.Infof("Success: %s", message) + zerolog.Ctx(req.Context()).Info().Msgf("Success: %s", message) succeedWithMessage(w, event, statusCode, message) } @@ -130,7 +125,7 @@ func (wh *WebHookHandler) handleEvent(w http.ResponseWriter, req *http.Request) } metrics.IncreasePushGithubEventTypeTriggerPipelineCounter(sshURL, branch, commitID, applicationSummary.Name) - jobSummary, err := wh.apiServer.TriggerPipeline(applicationSummary.Name, branch, commitID, triggeredBy) + jobSummary, err := wh.apiServer.TriggerPipeline(req.Context(), applicationSummary.Name, branch, commitID, triggeredBy) if err != nil { if e, ok := err.(*radix.ApiError); ok && e.Code == 400 { _succeedWithMessage(http.StatusAccepted, createPipelineJobErrorMessage(applicationSummary.Name, err)) @@ -181,7 +176,7 @@ func (wh *WebHookHandler) getApplication(req *http.Request, body []byte, sshURL return nil, err } - application, err := wh.apiServer.GetApplication(applicationSummary.Name) + application, err := wh.apiServer.GetApplication(req.Context(), applicationSummary.Name) if err != nil { return nil, err } @@ -194,7 +189,7 @@ func (wh *WebHookHandler) getApplication(req *http.Request, body []byte, sshURL } func (wh *WebHookHandler) getApplicationSummary(req *http.Request, sshURL string) (*models.ApplicationSummary, error) { - applicationSummaries, err := wh.apiServer.ShowApplications(sshURL) + applicationSummaries, err := wh.apiServer.ShowApplications(req.Context(), sshURL) if err != nil { return nil, err } @@ -286,7 +281,7 @@ func succeedWithMessage(w http.ResponseWriter, event string, statusCode int, mes } func fail(w http.ResponseWriter, event string, statusCode int, err error) { - log.Printf("%s\n", err) + // log.Printf("%s\n", err) w.WriteHeader(statusCode) render(w, WebhookResponse{ Ok: false, @@ -302,7 +297,7 @@ func render(w http.ResponseWriter, v interface{}) { return } _, err = w.Write(data) - if err != nil { - log.Errorf("Failed to write respones: %v", err) - } + // if err != nil { + // log.Errorf("Failed to write respones: %v", err) + // } } diff --git a/handler/webhook_handler_test.go b/handler/webhook_handler_test.go index 92ad649..8f4d3a4 100644 --- a/handler/webhook_handler_test.go +++ b/handler/webhook_handler_test.go @@ -15,7 +15,7 @@ import ( "github.com/equinor/radix-github-webhook/radix" "github.com/equinor/radix-github-webhook/router" "github.com/golang/mock/gomock" - "github.com/google/go-github/v53/github" + "github.com/google/go-github/v60/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -46,7 +46,7 @@ func (s *handlerTestSuite) SetupTest() { } func (s *handlerTestSuite) Test_MissingEventTypeHeader() { - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", nil) router.New(sut).ServeHTTP(s.w, req) @@ -62,7 +62,7 @@ func (s *handlerTestSuite) Test_UnhandledEventType() { withURL("git@github.com:equinor/repo-1.git"). BuildPullRequestEventPayload() - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "pull_request") @@ -79,9 +79,9 @@ func (s *handlerTestSuite) Test_PingEventShowApplicationsReturnError() { withURL("git@github.com:equinor/repo-4.git"). BuildPingEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return(nil, errors.New("any error")).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return(nil, errors.New("any error")).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -99,9 +99,9 @@ func (s *handlerTestSuite) Test_PingEventUnmatchedRepo() { withURL("git@github.com:equinor/repo-4.git"). BuildPingEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return(nil, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return(nil, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -119,9 +119,9 @@ func (s *handlerTestSuite) Test_PingEventMultipleRepos() { withURL("git@github.com:equinor/repo-4.git"). BuildPingEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{{}, {}}, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{{}, {}}, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -144,10 +144,10 @@ func (s *handlerTestSuite) Test_PingEventGetApplicationReturnsError() { BuildPingEventPayload() appSummary := models.ApplicationSummary{Name: appName} - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(nil, errors.New("any error")).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(nil, errors.New("any error")).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -167,10 +167,10 @@ func (s *handlerTestSuite) Test_PingEventIncorrectSecret() { BuildPingEventPayload() appSummary := models.ApplicationSummary{Name: appName} appDetail := models.NewApplicationBuilder().WithName(appName).WithSharedSecret("sharedsecret").Build() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -195,10 +195,10 @@ func (s *handlerTestSuite) Test_PingEventWithCorrectSecret() { appSummary := models.ApplicationSummary{Name: appName} appDetail := models.NewApplicationBuilder().WithName(appName).WithSharedSecret("sharedsecret").Build() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "ping") @@ -218,9 +218,9 @@ func (s *handlerTestSuite) Test_PushEventShowApplicationsReturnsError() { withURL("git@github.com:equinor/repo-4.git"). BuildPushEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return(nil, errors.New("any error")).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return(nil, errors.New("any error")).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -294,19 +294,19 @@ func (s *handlerTestSuite) Test_PushEventUnmatchedRepo() { for _, scenario := range scenarios { s.T().Logf("Test: %s", scenario.name) s.w = httptest.NewRecorder() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return(scenario.apps, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return(scenario.apps, nil).Times(1) for _, expectAppDetail := range scenario.expectAppDetails { appDetail := models.NewApplicationBuilder().WithName(expectAppDetail.appName).WithSharedSecret(sharedSecret).Build() - s.apiServer.EXPECT().GetApplication(expectAppDetail.appName). + s.apiServer.EXPECT().GetApplication(gomock.Any(), expectAppDetail.appName). Return(appDetail, nil). Times(1) jobSummary := models.JobSummary{Name: "jobname", AppName: expectAppDetail.appName, Branch: "master", CommitID: commitID, TriggeredBy: ""} s.apiServer.EXPECT(). - TriggerPipeline(expectAppDetail.appName, "master", commitID, ""). + TriggerPipeline(gomock.Any(), expectAppDetail.appName, "master", commitID, ""). Return(&jobSummary, nil). Times(1) } - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", scenario.url, bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -327,9 +327,9 @@ func (s *handlerTestSuite) Test_PushEventMultipleReposWithoutAppName() { withURL("git@github.com:equinor/repo-4.git"). BuildPushEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{{}, {}}, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{{}, {}}, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -350,10 +350,10 @@ func (s *handlerTestSuite) Test_PushEventIncorrectSecret() { BuildPushEventPayload() appSummary := models.ApplicationSummary{Name: appName} appDetail := models.NewApplicationBuilder().WithName(appName).WithSharedSecret("sharedsecret").Build() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -376,10 +376,10 @@ func (s *handlerTestSuite) Test_PushEventGetApplicationReturnsError() { withURL("git@github.com:equinor/repo-4.git"). BuildPushEventPayload() appSummary := models.ApplicationSummary{Name: appName} - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(nil, errors.New("any error")).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(nil, errors.New("any error")).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -456,11 +456,11 @@ func (s *handlerTestSuite) Test_PushEventTriggerPipelineReturnsError() { withURL("git@github.com:equinor/repo-4.git"). BuildPushEventPayload() - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) - s.apiServer.EXPECT().TriggerPipeline(appName, "master", commitID, "").Return(nil, scenario.apiError).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().TriggerPipeline(gomock.Any(), appName, "master", commitID, "").Return(nil, scenario.apiError).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -489,11 +489,11 @@ func (s *handlerTestSuite) Test_PushEventCorrectSecret() { appSummary := models.ApplicationSummary{Name: appName} appDetail := models.NewApplicationBuilder().WithName(appName).WithSharedSecret("sharedsecret").Build() jobSummary := models.JobSummary{Name: "jobname", AppName: "jobappname", Branch: "jobbranchname", CommitID: "jobcommitID", TriggeredBy: "anyuser"} - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) - s.apiServer.EXPECT().TriggerPipeline(appName, "master", commitID, "").Return(&jobSummary, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-4.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().TriggerPipeline(gomock.Any(), appName, "master", commitID, "").Return(&jobSummary, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -515,7 +515,7 @@ func (s *handlerTestSuite) Test_PushEventWithRefDeleted() { withURL("git@github.com:equinor/repo-4.git"). BuildPushEventPayload() - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") @@ -549,11 +549,11 @@ func (s *handlerTestSuite) Test_PushEventWithAnnotatedTag() { appSummary := models.ApplicationSummary{Name: appName} appDetail := models.NewApplicationBuilder().WithName(appName).WithSharedSecret("sharedsecret").Build() jobSummary := models.JobSummary{Name: "jobname", AppName: "jobappname", Branch: "jobbranchname", CommitID: headCommitID, TriggeredBy: "anyuser"} - s.apiServer.EXPECT().ShowApplications("git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) - s.apiServer.EXPECT().GetApplication(appName).Return(appDetail, nil).Times(1) - s.apiServer.EXPECT().TriggerPipeline(appName, tag, headCommitID, "").Return(&jobSummary, nil).Times(1) + s.apiServer.EXPECT().ShowApplications(gomock.Any(), "git@github.com:equinor/repo-1.git").Return([]*models.ApplicationSummary{&appSummary}, nil).Times(1) + s.apiServer.EXPECT().GetApplication(gomock.Any(), appName).Return(appDetail, nil).Times(1) + s.apiServer.EXPECT().TriggerPipeline(gomock.Any(), appName, tag, headCommitID, "").Return(&jobSummary, nil).Times(1) - sut := NewWebHookHandler(s.apiServer).HandleWebhookEvents() + sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", bytes.NewReader(payload)) req.Header.Add("Content-Type", "application/json") req.Header.Add("X-GitHub-Event", "push") diff --git a/internal/jwt_token_source.go b/internal/jwt_token_source.go index ba5a9c2..05aa051 100644 --- a/internal/jwt_token_source.go +++ b/internal/jwt_token_source.go @@ -2,7 +2,7 @@ package internal import ( "github.com/golang-jwt/jwt/v4" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "golang.org/x/oauth2" ) @@ -17,7 +17,7 @@ type jwtCallbackTokenSource struct { } func (s *jwtCallbackTokenSource) Token() (*oauth2.Token, error) { - log.Debug("Getting new token from callback") + log.Debug().Msg("Getting new token from callback") tokenString, err := s.callback() if err != nil { return nil, err @@ -31,6 +31,7 @@ func (s *jwtCallbackTokenSource) Token() (*oauth2.Token, error) { AccessToken: tokenString, Expiry: c.ExpiresAt.Time, } - log.Debugf("New token expires on %v", token.Expiry) + + log.Debug().Msgf("New token expires on %v", token.Expiry) return &token, nil } diff --git a/main.go b/main.go index 96bcc57..f0e8f44 100644 --- a/main.go +++ b/main.go @@ -4,15 +4,21 @@ import ( "context" "errors" "fmt" + "io" + "net" "net/http" "os" + "strconv" "strings" + "time" "github.com/equinor/radix-github-webhook/handler" "github.com/equinor/radix-github-webhook/internal" "github.com/equinor/radix-github-webhook/radix" "github.com/equinor/radix-github-webhook/router" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/spf13/pflag" "golang.org/x/oauth2" ) @@ -20,12 +26,6 @@ import ( const serviceAccountTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" func main() { - logLevel, err := log.ParseLevel(os.Getenv("LOG_LEVEL")) - if err != nil { - logLevel = log.InfoLevel - } - log.SetLevel(logLevel) - fs := initializeFlagSet() var ( port = fs.StringP("port", "p", defaultPort(), "The port for which we listen to events on") @@ -35,17 +35,41 @@ func main() { tokenSource, err := getTokenSource() if err != nil { - log.Fatal(err) + log.Fatal().Err(err).Msg("Failed to get token source") } + logLevel := os.Getenv("LOG_LEVEL") + logPretty, _ := strconv.ParseBool(os.Getenv("LOG_PRETTY")) + ctx := setupLogger(context.Background(), logLevel, logPretty) + client := oauth2.NewClient(context.Background(), oauth2.ReuseTokenSource(nil, tokenSource)) wh := handler.NewWebHookHandler(radix.NewAPIServerStub(apiServerEndpoint, client)) - router := router.New(wh.HandleWebhookEvents()) - err = http.ListenAndServe(fmt.Sprintf(":%s", *port), router) + router := router.New(wh) + srv := &http.Server{ + Addr: fmt.Sprintf(":%s", *port), + Handler: router, + BaseContext: func(_ net.Listener) context.Context { return ctx }, + } + if err := srv.ListenAndServe(); err != nil { + log.Fatal().Err(err).Msg("Unable to start server") + } +} + +func setupLogger(ctx context.Context, level string, pretty bool) context.Context { + var logWriter io.Writer = os.Stderr + if pretty { + logWriter = &zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.TimeOnly} + } + + logLevel, err := zerolog.ParseLevel(level) if err != nil { - log.Fatalf("Unable to start serving: %v", err) + logLevel = zerolog.InfoLevel } + zerolog.SetGlobalLevel(logLevel) + log.Logger = zerolog.New(logWriter).With().Timestamp().Logger() + + return log.Logger.WithContext(ctx) } func initializeFlagSet() *pflag.FlagSet { diff --git a/radix/api_server.go b/radix/api_server.go index e417b5f..aa6ae67 100644 --- a/radix/api_server.go +++ b/radix/api_server.go @@ -1,10 +1,14 @@ package radix -import "github.com/equinor/radix-github-webhook/models" +import ( + "context" + + "github.com/equinor/radix-github-webhook/models" +) // APIServer Stub methods in order to mock endpoints type APIServer interface { - ShowApplications(sshURL string) ([]*models.ApplicationSummary, error) - GetApplication(appName string) (*models.Application, error) - TriggerPipeline(appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) + ShowApplications(ctx context.Context, sshURL string) ([]*models.ApplicationSummary, error) + GetApplication(ctx context.Context, appName string) (*models.Application, error) + TriggerPipeline(ctx context.Context, appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) } diff --git a/radix/api_server_mock.go b/radix/api_server_mock.go index e0d929f..770f068 100644 --- a/radix/api_server_mock.go +++ b/radix/api_server_mock.go @@ -5,6 +5,7 @@ package radix import ( + context "context" reflect "reflect" models "github.com/equinor/radix-github-webhook/models" @@ -35,46 +36,46 @@ func (m *MockAPIServer) EXPECT() *MockAPIServerMockRecorder { } // GetApplication mocks base method. -func (m *MockAPIServer) GetApplication(appName string) (*models.Application, error) { +func (m *MockAPIServer) GetApplication(ctx context.Context, appName string) (*models.Application, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetApplication", appName) + ret := m.ctrl.Call(m, "GetApplication", ctx, appName) ret0, _ := ret[0].(*models.Application) ret1, _ := ret[1].(error) return ret0, ret1 } // GetApplication indicates an expected call of GetApplication. -func (mr *MockAPIServerMockRecorder) GetApplication(appName interface{}) *gomock.Call { +func (mr *MockAPIServerMockRecorder) GetApplication(ctx, appName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockAPIServer)(nil).GetApplication), appName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplication", reflect.TypeOf((*MockAPIServer)(nil).GetApplication), ctx, appName) } // ShowApplications mocks base method. -func (m *MockAPIServer) ShowApplications(sshURL string) ([]*models.ApplicationSummary, error) { +func (m *MockAPIServer) ShowApplications(ctx context.Context, sshURL string) ([]*models.ApplicationSummary, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ShowApplications", sshURL) + ret := m.ctrl.Call(m, "ShowApplications", ctx, sshURL) ret0, _ := ret[0].([]*models.ApplicationSummary) ret1, _ := ret[1].(error) return ret0, ret1 } // ShowApplications indicates an expected call of ShowApplications. -func (mr *MockAPIServerMockRecorder) ShowApplications(sshURL interface{}) *gomock.Call { +func (mr *MockAPIServerMockRecorder) ShowApplications(ctx, sshURL interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShowApplications", reflect.TypeOf((*MockAPIServer)(nil).ShowApplications), sshURL) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShowApplications", reflect.TypeOf((*MockAPIServer)(nil).ShowApplications), ctx, sshURL) } // TriggerPipeline mocks base method. -func (m *MockAPIServer) TriggerPipeline(appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) { +func (m *MockAPIServer) TriggerPipeline(ctx context.Context, appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TriggerPipeline", appName, branch, commitID, triggeredBy) + ret := m.ctrl.Call(m, "TriggerPipeline", ctx, appName, branch, commitID, triggeredBy) ret0, _ := ret[0].(*models.JobSummary) ret1, _ := ret[1].(error) return ret0, ret1 } // TriggerPipeline indicates an expected call of TriggerPipeline. -func (mr *MockAPIServerMockRecorder) TriggerPipeline(appName, branch, commitID, triggeredBy interface{}) *gomock.Call { +func (mr *MockAPIServerMockRecorder) TriggerPipeline(ctx, appName, branch, commitID, triggeredBy interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TriggerPipeline", reflect.TypeOf((*MockAPIServer)(nil).TriggerPipeline), appName, branch, commitID, triggeredBy) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TriggerPipeline", reflect.TypeOf((*MockAPIServer)(nil).TriggerPipeline), ctx, appName, branch, commitID, triggeredBy) } diff --git a/radix/api_server_stub.go b/radix/api_server_stub.go index ac0787b..080c331 100644 --- a/radix/api_server_stub.go +++ b/radix/api_server_stub.go @@ -2,6 +2,7 @@ package radix import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -9,8 +10,7 @@ import ( "net/url" "github.com/equinor/radix-github-webhook/models" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" ) const buildDeployPipeline = "build-deploy" @@ -33,9 +33,9 @@ func NewAPIServerStub(apiServerEndPoint string, client *http.Client) APIServer { } // ShowApplications Implementation -func (api *APIServerStub) ShowApplications(sshURL string) ([]*models.ApplicationSummary, error) { +func (api *APIServerStub) ShowApplications(ctx context.Context, sshURL string) ([]*models.ApplicationSummary, error) { url := fmt.Sprintf(api.apiServerEndPoint+getApplicationSummariesEndPointPattern, url.QueryEscape(sshURL)) - response, err := api.makeRequest("GET", url) + response, err := api.makeRequest(ctx, "GET", url) if err != nil { return nil, err } @@ -49,9 +49,9 @@ func (api *APIServerStub) ShowApplications(sshURL string) ([]*models.Application } // GetApplication Implementation -func (api *APIServerStub) GetApplication(appName string) (*models.Application, error) { +func (api *APIServerStub) GetApplication(ctx context.Context, appName string) (*models.Application, error) { url := fmt.Sprintf(api.apiServerEndPoint+getApplicationEndPointPattern, appName) - response, err := api.makeRequest("GET", url) + response, err := api.makeRequest(ctx, "GET", url) if err != nil { return nil, err } @@ -65,7 +65,7 @@ func (api *APIServerStub) GetApplication(appName string) (*models.Application, e } // TriggerPipeline Implementation -func (api *APIServerStub) TriggerPipeline(appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) { +func (api *APIServerStub) TriggerPipeline(ctx context.Context, appName, branch, commitID, triggeredBy string) (*models.JobSummary, error) { url := fmt.Sprintf(api.apiServerEndPoint+startPipelineEndPointPattern, appName, buildDeployPipeline) parameters := models.PipelineParameters{Branch: branch, CommitID: commitID, TriggeredBy: triggeredBy} @@ -74,7 +74,7 @@ func (api *APIServerStub) TriggerPipeline(appName, branch, commitID, triggeredBy return nil, err } - response, err := api.makeRequestWithBody("POST", url, body) + response, err := api.makeRequestWithBody(ctx, "POST", url, body) if err != nil { return nil, err } @@ -87,21 +87,21 @@ func (api *APIServerStub) TriggerPipeline(appName, branch, commitID, triggeredBy return jobSummary, nil } -func (api *APIServerStub) makeRequest(method, url string) ([]byte, error) { - return api.makeRequestWithBody(method, url, []byte{}) +func (api *APIServerStub) makeRequest(ctx context.Context, method, url string) ([]byte, error) { + return api.makeRequestWithBody(ctx, method, url, []byte{}) } -func (api *APIServerStub) makeRequestWithBody(method, url string, reqBody []byte) ([]byte, error) { - req, err := http.NewRequest(method, url, bytes.NewReader(reqBody)) +func (api *APIServerStub) makeRequestWithBody(ctx context.Context, method, url string, reqBody []byte) ([]byte, error) { + req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(reqBody)) if err != nil { - return nil, errors.Errorf("Unable create request for starting pipeline: %v", err) + return nil, fmt.Errorf("unable create request for starting pipeline: %w", err) } req.Header.Set("Accept", "application/json") + zerolog.Ctx(ctx).Info().Str("method", method).Str("url", url).Msg("Request to Radix API") - log.Infof("%s: %s", method, url) resp, err := api.client.Do(req) if err != nil { - return nil, errors.Errorf("Request failed: %v", err) + return nil, fmt.Errorf("request failed: %w", err) } if resp.StatusCode >= 400 { @@ -120,7 +120,7 @@ func readBody(resp *http.Response) ([]byte, error) { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - return nil, errors.Errorf("Invalid response: %v", err) + return nil, fmt.Errorf("invalid response: %w", err) } return body, nil diff --git a/router/router.go b/router/router.go index 4a9cf90..91905db 100644 --- a/router/router.go +++ b/router/router.go @@ -3,18 +3,22 @@ package router import ( "net/http" - "github.com/gorilla/mux" + commongin "github.com/equinor/radix-common/pkg/gin" + "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" ) // New creates a mux router for handling Github webhook requests -func New(webHookHandler http.Handler) *mux.Router { - router := mux.NewRouter() - router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - }).Methods("GET") - router.Handle("/metrics", promhttp.Handler()) - router.Handle("/events/github", webHookHandler) - router.Handle("/", webHookHandler) - return router +func New(webHookHandler http.Handler) http.Handler { + engine := gin.New() + engine.RemoveExtraSlash = true + engine.Use(commongin.SetZerologLogger(commongin.ZerologLoggerWithRequestId)) + engine.Use(commongin.ZerologRequestLogger(), gin.Recovery()) + engine.Handle(http.MethodGet, "/health", func(ctx *gin.Context) { + ctx.Writer.WriteHeader(http.StatusOK) + }) + engine.Handle(http.MethodGet, "/metrics", gin.WrapH(promhttp.Handler())) + engine.Handle(http.MethodPost, "/events/github", gin.WrapH(webHookHandler)) + engine.Handle(http.MethodPost, "/", gin.WrapH(webHookHandler)) + return engine } From 4b711fce392c9fc7e539dd07bea66ab01a4c9d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20Gustav=20Str=C3=A5b=C3=B8?= Date: Mon, 11 Mar 2024 15:16:52 +0100 Subject: [PATCH 2/2] refactor webhook handler --- .github/workflows/pr.yaml | 17 +++--- .golangci.yaml | 15 +++++ .vscode/launch.json | 3 +- handler/webhook_handler.go | 104 +++++++++++++------------------- handler/webhook_handler_test.go | 1 - main.go | 2 +- radixconfig.yaml | 1 + router/router.go | 6 +- 8 files changed, 71 insertions(+), 78 deletions(-) create mode 100644 .golangci.yaml diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index c697ecf..fc9a296 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -21,25 +21,22 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 2 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: '1.21' - - name: Install dependencies - run: go mod download - - name: Install GolangCI Lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2 - + go-version-file: 'go.mod' - name: golangci-lint - run: golangci-lint run --timeout=30m --max-same-issues=0 --out-format=github-actions + uses: golangci/golangci-lint-action@v4 + with: + version: v1.55.2 test: name: Unit Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version-file: 'go.mod' - name: Install dependencies run: go mod download - name: Run Tests diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..810cb8c --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,15 @@ +run: + timeout: 30m + +linters: + enable: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - unused + - zerologlint + +issues: + max-same-issues: 0 \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 1111a59..5a36351 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,10 +12,11 @@ "program": "${workspaceFolder}/main.go", "env": { "LOG_LEVEL": "info", + "LOG_PRETTY": "true", "API_SERVER_ENDPOINT_PREFIX": "https://server-radix-api-qa", "RADIX_CLUSTERNAME": "weekly-34", "RADIX_DNS_ZONE": "dev.radix.equinor.com", - "BEARER_TOKEN": "fdgdfdg", + "BEARER_TOKEN": "", } } ] diff --git a/handler/webhook_handler.go b/handler/webhook_handler.go index cc0bf40..91f5a47 100644 --- a/handler/webhook_handler.go +++ b/handler/webhook_handler.go @@ -2,7 +2,6 @@ package handler import ( "bytes" - "encoding/json" "errors" "fmt" "io" @@ -13,6 +12,7 @@ import ( "github.com/equinor/radix-github-webhook/metrics" "github.com/equinor/radix-github-webhook/models" "github.com/equinor/radix-github-webhook/radix" + "github.com/gin-gonic/gin" "github.com/google/go-github/v60/github" "github.com/rs/zerolog" ) @@ -55,51 +55,62 @@ type WebhookResponse struct { Error string `json:"error,omitempty"` } -// WebHookHandler Instance -type WebHookHandler struct { +// webhookHandler Instance +type webhookHandler struct { apiServer radix.APIServer } // NewWebHookHandler Constructor -func NewWebHookHandler(apiServer radix.APIServer) *WebHookHandler { - return &WebHookHandler{ +func NewWebHookHandler(apiServer radix.APIServer) gin.HandlerFunc { + handler := &webhookHandler{ apiServer, } + + return handler.HandleFunc } -func (wh *WebHookHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (wh *webhookHandler) HandleFunc(c *gin.Context) { // Increase metrics counter metrics.IncreaseAllCounter() - event := req.Header.Get("x-github-event") + event := c.GetHeader("x-github-event") - _fail := func(statusCode int, err error) { - fail(w, event, statusCode, err) + writeErrorResponse := func(statusCode int, err error) { + _ = c.Error(err) + c.AbortWithStatusJSON(statusCode, WebhookResponse{ + Ok: false, + Event: event, + Error: err.Error(), + }) } - _succeedWithMessage := func(statusCode int, message string) { - zerolog.Ctx(req.Context()).Info().Msgf("Success: %s", message) - succeedWithMessage(w, event, statusCode, message) + writeSuccessResponse := func(statusCode int, message string) { + zerolog.Ctx(c.Request.Context()).Info().Msg(message) + c.JSON(statusCode, WebhookResponse{ + Ok: true, + Event: event, + Message: message, + }) } if len(strings.TrimSpace(event)) == 0 { metrics.IncreaseNotGithubEventCounter() - _fail(http.StatusBadRequest, errors.New(notAGithubEventMessage)) + writeErrorResponse(http.StatusBadRequest, errors.New(notAGithubEventMessage)) return } // Need to parse webhook before validation because the secret is taken from the matching repo - body, err := io.ReadAll(req.Body) + body, err := io.ReadAll(c.Request.Body) if err != nil { metrics.IncreaseFailedParsingCounter() - _fail(http.StatusBadRequest, fmt.Errorf("could not parse webhook: err=%s ", err)) + writeErrorResponse(http.StatusBadRequest, fmt.Errorf("could not parse webhook: err=%s ", err)) return } - - payload, err := github.ParseWebHook(github.WebHookType(req), body) + webhookEventType := github.WebHookType(c.Request) + payload, err := github.ParseWebHook(webhookEventType, body) if err != nil { metrics.IncreaseFailedParsingCounter() - _fail(http.StatusBadRequest, fmt.Errorf("could not parse webhook: err=%s ", err)) + writeErrorResponse(http.StatusBadRequest, fmt.Errorf("could not parse webhook: err=%s ", err)) return } @@ -113,48 +124,48 @@ func (wh *WebHookHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { metrics.IncreasePushGithubEventTypeCounter(sshURL, branch, commitID) if isPushEventForRefDeletion(e) { - _succeedWithMessage(http.StatusAccepted, refDeletionPushEventUnsupportedMessage(*e.Ref)) + writeSuccessResponse(http.StatusAccepted, refDeletionPushEventUnsupportedMessage(*e.Ref)) return } - applicationSummary, err := wh.getApplication(req, body, sshURL) + applicationSummary, err := wh.getApplication(c.Request, body, sshURL) if err != nil { metrics.IncreaseFailedCloneURLValidationCounter(sshURL) - _fail(http.StatusBadRequest, err) + writeErrorResponse(http.StatusBadRequest, err) return } metrics.IncreasePushGithubEventTypeTriggerPipelineCounter(sshURL, branch, commitID, applicationSummary.Name) - jobSummary, err := wh.apiServer.TriggerPipeline(req.Context(), applicationSummary.Name, branch, commitID, triggeredBy) + jobSummary, err := wh.apiServer.TriggerPipeline(c.Request.Context(), applicationSummary.Name, branch, commitID, triggeredBy) if err != nil { if e, ok := err.(*radix.ApiError); ok && e.Code == 400 { - _succeedWithMessage(http.StatusAccepted, createPipelineJobErrorMessage(applicationSummary.Name, err)) + writeSuccessResponse(http.StatusAccepted, createPipelineJobErrorMessage(applicationSummary.Name, err)) return } metrics.IncreasePushGithubEventTypeFailedTriggerPipelineCounter(sshURL, branch, commitID) - _fail(http.StatusBadRequest, errors.New(createPipelineJobErrorMessage(applicationSummary.Name, err))) + writeErrorResponse(http.StatusBadRequest, errors.New(createPipelineJobErrorMessage(applicationSummary.Name, err))) return } - _succeedWithMessage(http.StatusOK, createPipelineJobSuccessMessage(jobSummary.Name, jobSummary.AppName, jobSummary.Branch, jobSummary.CommitID)) + writeSuccessResponse(http.StatusOK, createPipelineJobSuccessMessage(jobSummary.Name, jobSummary.AppName, jobSummary.Branch, jobSummary.CommitID)) case *github.PingEvent: // sshURL := getSSHUrlFromPingURL(*e.Hook.URL) sshURL := e.Repo.GetSSHURL() metrics.IncreasePingGithubEventTypeCounter(sshURL) - applicationSummary, err := wh.getApplication(req, body, sshURL) + applicationSummary, err := wh.getApplication(c.Request, body, sshURL) if err != nil { metrics.IncreaseFailedCloneURLValidationCounter(sshURL) - _fail(http.StatusBadRequest, err) + writeErrorResponse(http.StatusBadRequest, err) return } - _succeedWithMessage(http.StatusOK, webhookCorrectConfiguration(applicationSummary.Name)) + writeSuccessResponse(http.StatusOK, webhookCorrectConfiguration(applicationSummary.Name)) default: metrics.IncreaseUnsupportedGithubEventTypeCounter() - _fail(http.StatusBadRequest, errors.New(unhandledEventTypeMessage(github.WebHookType(req)))) + writeErrorResponse(http.StatusBadRequest, errors.New(unhandledEventTypeMessage(webhookEventType))) return } } @@ -170,7 +181,7 @@ func getCommitID(e *github.PushEvent) string { return *e.After } -func (wh *WebHookHandler) getApplication(req *http.Request, body []byte, sshURL string) (*models.ApplicationSummary, error) { +func (wh *webhookHandler) getApplication(req *http.Request, body []byte, sshURL string) (*models.ApplicationSummary, error) { applicationSummary, err := wh.getApplicationSummary(req, sshURL) if err != nil { return nil, err @@ -188,7 +199,7 @@ func (wh *WebHookHandler) getApplication(req *http.Request, body []byte, sshURL return applicationSummary, nil } -func (wh *WebHookHandler) getApplicationSummary(req *http.Request, sshURL string) (*models.ApplicationSummary, error) { +func (wh *webhookHandler) getApplicationSummary(req *http.Request, sshURL string) (*models.ApplicationSummary, error) { applicationSummaries, err := wh.apiServer.ShowApplications(req.Context(), sshURL) if err != nil { return nil, err @@ -270,34 +281,3 @@ func validatePayload(header http.Header, payload []byte, sharedSecret []byte) er return nil } - -func succeedWithMessage(w http.ResponseWriter, event string, statusCode int, message string) { - w.WriteHeader(statusCode) - render(w, WebhookResponse{ - Ok: true, - Event: event, - Message: message, - }) -} - -func fail(w http.ResponseWriter, event string, statusCode int, err error) { - // log.Printf("%s\n", err) - w.WriteHeader(statusCode) - render(w, WebhookResponse{ - Ok: false, - Event: event, - Error: err.Error(), - }) -} - -func render(w http.ResponseWriter, v interface{}) { - data, err := json.Marshal(v) - if err != nil { - http.Error(w, err.Error(), 500) - return - } - _, err = w.Write(data) - // if err != nil { - // log.Errorf("Failed to write respones: %v", err) - // } -} diff --git a/handler/webhook_handler_test.go b/handler/webhook_handler_test.go index 8f4d3a4..8ed2837 100644 --- a/handler/webhook_handler_test.go +++ b/handler/webhook_handler_test.go @@ -48,7 +48,6 @@ func (s *handlerTestSuite) SetupTest() { func (s *handlerTestSuite) Test_MissingEventTypeHeader() { sut := NewWebHookHandler(s.apiServer) req, _ := http.NewRequest("POST", "/", nil) - router.New(sut).ServeHTTP(s.w, req) s.Equal(http.StatusBadRequest, s.w.Code) var res response diff --git a/main.go b/main.go index f0e8f44..fe049dd 100644 --- a/main.go +++ b/main.go @@ -50,7 +50,7 @@ func main() { Handler: router, BaseContext: func(_ net.Listener) context.Context { return ctx }, } - + log.Info().Msgf("API is serving on address %s", srv.Addr) if err := srv.ListenAndServe(); err != nil { log.Fatal().Err(err).Msg("Unable to start server") } diff --git a/radixconfig.yaml b/radixconfig.yaml index 861e7e7..77ff73d 100644 --- a/radixconfig.yaml +++ b/radixconfig.yaml @@ -20,6 +20,7 @@ spec: publicPort: http variables: LOG_LEVEL: info + LOG_PRETTY: "false" environmentConfig: - environment: qa variables: diff --git a/router/router.go b/router/router.go index 91905db..22fea47 100644 --- a/router/router.go +++ b/router/router.go @@ -9,7 +9,7 @@ import ( ) // New creates a mux router for handling Github webhook requests -func New(webHookHandler http.Handler) http.Handler { +func New(webHookHandler gin.HandlerFunc) http.Handler { engine := gin.New() engine.RemoveExtraSlash = true engine.Use(commongin.SetZerologLogger(commongin.ZerologLoggerWithRequestId)) @@ -18,7 +18,7 @@ func New(webHookHandler http.Handler) http.Handler { ctx.Writer.WriteHeader(http.StatusOK) }) engine.Handle(http.MethodGet, "/metrics", gin.WrapH(promhttp.Handler())) - engine.Handle(http.MethodPost, "/events/github", gin.WrapH(webHookHandler)) - engine.Handle(http.MethodPost, "/", gin.WrapH(webHookHandler)) + engine.Handle(http.MethodPost, "/events/github", webHookHandler) + engine.Handle(http.MethodPost, "/", webHookHandler) return engine }