From 6d55eac0687b275b48b589c7f0de8452a40f9879 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Thu, 9 Apr 2026 17:51:32 +0530 Subject: [PATCH 01/11] newrelic and airbrake integration --- Dockerfile | 29 +++++-------------- config/config.go | 28 +++++++++++++++++++ db/db.go | 8 +++++- go.mod | 27 +++++++++++++----- go.sum | 72 ++++++++++++++++++++++++++++++++++++------------ main.go | 46 +++++++++++++++++++++++++++---- 6 files changed, 157 insertions(+), 53 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2c73fbd..3e25a1b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,11 @@ -# Build the application from source -FROM golang:1.21 AS build-stage - -WORKDIR /app - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN CGO_ENABLED=0 GOOS=linux go build -o /server main.go - -# Deploy the application binary into a lean image -FROM alpine:3.21.3 AS build-release-stage - +FROM alpine:3.21.3 RUN apk update \ - && apk --no-cache add ca-certificates \ - && apk --no-cache add -U tzdata \ - && rm -rf /var/cache/apk/* - -WORKDIR /usr/app/ + && apk --no-cache add ca-certificates \ + && apk --no-cache add -U tzdata \ + && rm -rf /var/cache/apk/* -COPY --from=build-stage server . +WORKDIR /server +COPY server . EXPOSE 8080 -ENTRYPOINT ["./server"] +CMD ["./server"] diff --git a/config/config.go b/config/config.go index 8432fa6..f696a5a 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,10 @@ type appConfig struct { TokenExpireTime int64 Environment string `json:"environment" validate:"required"` TenantName string `json:"tenant_name" validate:"required"` + // Observability (same JSON keys as go-email-templates service secrets) + AirbrakeProjectID int64 + AirbrakeProjectKey string + NewRelicLicenseKey string } type dbConfig struct { Write dbConfigObj @@ -76,6 +80,20 @@ func GetConfig() *appConfig { } func LoadConfig() *appConfig { + intFormatter := func(v interface{}) (val int64) { + switch ta := v.(type) { + case int: + val = int64(ta) + case int64: + val = ta + case float64: + val = int64(ta) + case string: + val, _ = strconv.ParseInt(ta, 10, 64) + } + return + } + fmt.Println("Fetching config from AWS secret manager...") keys := []string{ "global", // Global secrets @@ -206,6 +224,16 @@ func LoadConfig() *appConfig { if k == "environment" { config.Environment = v.(string) } + + if k == "airbrake_project_id" { + config.AirbrakeProjectID = intFormatter(v) + } + if k == "airbrake_project_key" { + config.AirbrakeProjectKey = v.(string) + } + if k == "newrelic_license_key" { + config.NewRelicLicenseKey = v.(string) + } } } config.DBUser.Write = dbObj diff --git a/db/db.go b/db/db.go index 63b6daa..79a774b 100644 --- a/db/db.go +++ b/db/db.go @@ -5,6 +5,8 @@ import ( "time" "com.lc.go.codepush/server/config" + + _ "github.com/newrelic/go-agent/v3/integrations/nrmysql" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" @@ -20,7 +22,11 @@ func GetUserDB() (odb *gorm.DB, err error) { dbConfig := config.GetConfig().DBUser dsnSource := dbConfig.Write.UserName + ":" + dbConfig.Write.Password + "@tcp(" + dbConfig.Write.Host + ":" + strconv.Itoa(int(dbConfig.Write.Port)) + ")/" + dbConfig.Write.DBname + "?charset=utf8mb4&parseTime=True&loc=Local" - db, err := gorm.Open(mysql.Open(dsnSource), &gorm.Config{ + // Same driver as go-email-templates (sql.Open("nrmysql", ...)); pairs with HTTP txns when using Request context. + db, err := gorm.Open(mysql.New(mysql.Config{ + DriverName: "nrmysql", + DSN: dsnSource, + }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Error), }) if err != nil { diff --git a/go.mod b/go.mod index caa96d3..359f3e4 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,22 @@ module com.lc.go.codepush/server -go 1.21 +go 1.24 require ( github.com/go-playground/validator/v10 v10.19.0 github.com/jlaffaye/ftp v0.2.0 + github.com/newrelic/go-agent/v3/integrations/nrgin v1.2.1 + github.com/newrelic/go-agent/v3/integrations/nrmysql v1.2.2 + github.com/punchh/go-packages v1.2.1 + github.com/sirupsen/logrus v1.9.4 gorm.io/driver/mysql v1.5.6 ) require ( + github.com/airbrake/gobrake/v5 v5.6.2 // indirect github.com/bytedance/sonic v1.11.3 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/caio/go-tdigest/v4 v4.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -19,24 +25,31 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jonboulle/clockwork v0.5.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/newrelic/go-agent/v3 v3.24.0 // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index aeee0a5..5ba206f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/airbrake/gobrake/v5 v5.6.2 h1:/LLjm0B3Jy3gqg17VpeGEnSTRqiIElGDy3RZy9s7+MU= +github.com/airbrake/gobrake/v5 v5.6.2/go.mod h1:7lOWiGlpBnOnmWdz7BJzY/shByCkuAIL4LvHbGBKeZs= github.com/aws/aws-sdk-go v1.51.24 h1:nwL5MaommPkwb7Ixk24eWkdx5HY4of1gD10kFFVAl6A= github.com/aws/aws-sdk-go v1.51.24/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= @@ -8,8 +10,10 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1 github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA= github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -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/caio/go-tdigest/v4 v4.0.1 h1:sx4ZxjmIEcLROUPs2j1BGe2WhOtHD6VSe6NNbBdKYh4= +github.com/caio/go-tdigest/v4 v4.0.1/go.mod h1:Wsa+f0EZnV2gShdj1adgl0tQSoXRxtM0QioTgukFw8U= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.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/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -30,6 +34,8 @@ 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-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.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= @@ -42,8 +48,12 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 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/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -62,12 +72,16 @@ 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/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= 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.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4= +github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -77,12 +91,28 @@ 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/newrelic/go-agent/v3 v3.24.0 h1:DPfbd+p0akRjv6UpWzWJl+pfOMSs+QkAeNRUp0fPLZI= +github.com/newrelic/go-agent/v3 v3.24.0/go.mod h1:7GnP0o5ZwEsnC001iDSoZRJ63jS6AtoAOggpg5XVJh8= +github.com/newrelic/go-agent/v3/integrations/nrgin v1.2.1 h1:re7DEe0rP5oek23/0N1aFfdtH5h2yBk8JhmLZvYAUqo= +github.com/newrelic/go-agent/v3/integrations/nrgin v1.2.1/go.mod h1:nXd6QMW8iuY9U/bQSXpjRLbMdCnDaydncooVLqzxygA= +github.com/newrelic/go-agent/v3/integrations/nrmysql v1.2.2 h1:JtaJdL4y1hj5mH0JA2XIIIZtOsivsCmG0wsp3cGtoNo= +github.com/newrelic/go-agent/v3/integrations/nrmysql v1.2.2/go.mod h1:0JZ1gqlaBi9FUrQsg9LLZR357oDH4fGYYTbQQPhOd8o= +github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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/punchh/go-packages v1.2.1 h1:y7HWLFNVXh23wGNk0I6AXiitNy/UOd01EQqVq6H4sJI= +github.com/punchh/go-packages v1.2.1/go.mod h1:DZ5pM4qI81hZOHx54PPw4k5DM0Y8a52kn9D8dajfMCA= github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= 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= @@ -93,8 +123,9 @@ 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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -102,24 +133,29 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index ba67ab1..b80162f 100644 --- a/main.go +++ b/main.go @@ -2,23 +2,59 @@ package main import ( "fmt" + "os" + "strconv" "com.lc.go.codepush/server/config" - "com.lc.go.codepush/server/middleware" + localmw "com.lc.go.codepush/server/middleware" "com.lc.go.codepush/server/request" "github.com/gin-contrib/gzip" - "github.com/gin-gonic/gin" + "github.com/newrelic/go-agent/v3/integrations/nrgin" + punchhmw "github.com/punchh/go-packages/middleware" + "github.com/sirupsen/logrus" ) func main() { fmt.Println("code-push-server-go V1.0.5") // gin.SetMode(gin.ReleaseMode) + + logger := punchhmw.NewLogger(logrus.StandardLogger()) + configs := config.GetConfig() + + // Airbrake on logrus errors (same hook as go-email-templates / go-packages) + airPID, airKey := configs.AirbrakeProjectID, configs.AirbrakeProjectKey + if airPID == 0 { + if s := os.Getenv("AIRBRAKE_PROJECT_ID"); s != "" { + airPID, _ = strconv.ParseInt(s, 10, 64) + } + } + if airKey == "" { + airKey = os.Getenv("AIRBRAKE_PROJECT_KEY") + } + if airPID > 0 && airKey != "" { + logger.AddHook(punchhmw.NewAirbrake(configs.Environment, airPID, airKey)) + } + + nrKey := configs.NewRelicLicenseKey + if nrKey == "" { + nrKey = os.Getenv("NEW_RELIC_LICENSE_KEY") + } + + nr, err := punchhmw.Newnewrelic(configs.Environment, "code-push-server-go", nrKey) + if err != nil { + logger.Println("newrelic init:", err) + } + + logger.Println("starting HTTP server") + g := gin.Default() + if nr != nil && nr.Application != nil { + g.Use(nrgin.Middleware(nr.Application)) + } g.Use(gzip.Gzip(gzip.DefaultCompression)) - g.Use(middleware.Recover) - configs := config.GetConfig() + g.Use(localmw.Recover) // g.Static("/bundels", "bundels") @@ -36,7 +72,7 @@ func main() { { apiGroup.POST("/login", request.User{}.Login) } - authApi := apiGroup.Use(middleware.CheckToken) + authApi := apiGroup.Use(localmw.CheckToken) { authApi.POST("/createApp", request.App{}.CreateApp) authApi.POST("/createDeployment", request.App{}.CreateDeployment) From 2dc84e43b94ff13a8e8563483166606e7ac50a85 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Wed, 15 Apr 2026 12:48:56 +0530 Subject: [PATCH 02/11] airbrake recovery added --- main.go | 8 ++++++-- middleware/middleware.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index b80162f..8ed0652 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,9 @@ func main() { airKey = os.Getenv("AIRBRAKE_PROJECT_KEY") } if airPID > 0 && airKey != "" { - logger.AddHook(punchhmw.NewAirbrake(configs.Environment, airPID, airKey)) + abHook := punchhmw.NewAirbrake(configs.Environment, airPID, airKey) + logger.AddHook(abHook) + localmw.SetAirbrakeHook(abHook) } nrKey := configs.NewRelicLicenseKey @@ -49,7 +51,9 @@ func main() { logger.Println("starting HTTP server") - g := gin.Default() + g := gin.New() + g.Use(gin.Logger()) + g.Use(localmw.AirbrakeRecovery()) if nr != nil && nr.Application != nil { g.Use(nrgin.Middleware(nr.Application)) } diff --git a/middleware/middleware.go b/middleware/middleware.go index c04e315..4795e88 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -10,8 +10,44 @@ import ( "com.lc.go.codepush/server/model/constants" "com.lc.go.codepush/server/utils" "github.com/gin-gonic/gin" + punchhmw "github.com/punchh/go-packages/middleware" ) +var airbrakeHook *punchhmw.Airbrake + +func SetAirbrakeHook(hook *punchhmw.Airbrake) { + airbrakeHook = hook +} + +func AirbrakeRecovery() gin.HandlerFunc { + return func(c *gin.Context) { + defer func() { + if r := recover(); r != nil { + if airbrakeHook != nil { + airbrakeHook.Notify(r, c.Request) + } + log.Printf("Error:%v", r) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "code": 500, + "msg": "Internal Server Error", + "success": false, + }) + } + }() + c.Next() + if c.Writer.Status() >= http.StatusInternalServerError { + if len(c.Errors) > 0 { + for _, e := range c.Errors { + if airbrakeHook != nil { + airbrakeHook.Notify(e.Err, c.Request) + } + log.Printf("server error: %v", e.Err) + } + } + } + } +} + // 檢查token func CheckToken(ctx *gin.Context) { var token, _ = ctx.Cookie("token") From 0733873e1614fbafa77762f4d91c21eeb15c8718 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Fri, 24 Apr 2026 18:42:35 +0530 Subject: [PATCH 03/11] github workflow changes --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++++ .github/workflows/go.yml | 30 ---------------------------- 2 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..24e7c42 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: Go CI + +on: + pull_request: + push: + branches: + - main + + workflow_dispatch: + inputs: + skip_tests: + description: 'Skip running tests' + required: false + default: false + type: boolean + triggered_user: + description: 'Who triggered the workflow' + required: false + default: "" + type: string + +jobs: + go-ci: + permissions: + id-token: write + contents: write + packages: read + uses: punchh/GHA-central-workflow/.github/workflows/go-ci.yml@main + + with: + repository: ${{ github.repository }} + branch: ${{ github.event_name == 'workflow_dispatch' && github.ref_name || (github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name) }} + go_version: 1.24 + triggered_user: ${{ github.event_name == 'workflow_dispatch' && inputs.triggered_user || '' }} + skip_tests: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_tests || false }} + test_cases: false + snyk_severity_threshold: "critical" + go_build: true + secrets: + SVC_ACCOUNT_GITHUB_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} + SVC_ACCOUNT_SNYK_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_SNYK_ORG_TOKEN }} + CAPTAIN_DEVOPS_SLACK_BOT_TOKEN: ${{ secrets.CAPTAIN_DEVOPS_SLACK_BOT_TOKEN }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 07331c2..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflow will build a golang project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go - -name: Go - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - pull_request_review: - types: [submitted, dismissed] - -jobs: - - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.21.5' - - name: Install dependencies - run: go get . - - name: Build - run: go build -v ./... - - name: Test with the Go CLI - run: go test From e82c8eac503f8dfe4b3f34c049fed1bce2127814 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Fri, 24 Apr 2026 19:14:13 +0530 Subject: [PATCH 04/11] github workflow changes --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24e7c42..353c22a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,6 @@ jobs: skip_tests: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_tests || false }} test_cases: false snyk_severity_threshold: "critical" - go_build: true secrets: SVC_ACCOUNT_GITHUB_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} SVC_ACCOUNT_SNYK_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_SNYK_ORG_TOKEN }} From e3a47261c0c8227dfef2928dc490290a8ed9b8dd Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 07:55:13 +0530 Subject: [PATCH 05/11] github workflow changes --- .github/workflows/ci.yml | 69 ++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 353c22a..82599a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,6 @@ +# Self-contained Go CI (does not call punchh/GHA-central-workflow — that reusable +# workflow must be allowed by org settings; use this file if you see "workflow was not found".) + name: Go CI on: @@ -5,37 +8,41 @@ on: push: branches: - main - workflow_dispatch: - inputs: - skip_tests: - description: 'Skip running tests' - required: false - default: false - type: boolean - triggered_user: - description: 'Who triggered the workflow' - required: false - default: "" - type: string + +permissions: + contents: read jobs: - go-ci: - permissions: - id-token: write - contents: write - packages: read - uses: punchh/GHA-central-workflow/.github/workflows/go-ci.yml@main - - with: - repository: ${{ github.repository }} - branch: ${{ github.event_name == 'workflow_dispatch' && github.ref_name || (github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name) }} - go_version: 1.24 - triggered_user: ${{ github.event_name == 'workflow_dispatch' && inputs.triggered_user || '' }} - skip_tests: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_tests || false }} - test_cases: false - snyk_severity_threshold: "critical" - secrets: - SVC_ACCOUNT_GITHUB_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} - SVC_ACCOUNT_SNYK_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_SNYK_ORG_TOKEN }} - CAPTAIN_DEVOPS_SLACK_BOT_TOKEN: ${{ secrets.CAPTAIN_DEVOPS_SLACK_BOT_TOKEN }} + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.24" + + - name: Configure private Go modules (punchh) + env: + TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} + run: | + if [ -n "$TOKEN" ]; then + git config --global url."https://x-access-token:${TOKEN}@github.com/punchh/".insteadOf "https://github.com/punchh/" + fi + + - name: Go mod download + env: + GOPRIVATE: github.com/punchh + GONOSUMDB: github.com/punchh + run: go mod download + + - name: Build + env: + GOPRIVATE: github.com/punchh + run: go build -v ./... + + - name: Test + env: + GOPRIVATE: github.com/punchh + run: go test -v ./... From 36ee8a384643bf35566060710274935ea2a6281d Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 07:58:18 +0530 Subject: [PATCH 06/11] github workflow changes --- .github/workflows/ci.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82599a0..99b47db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,26 +23,41 @@ jobs: with: go-version: "1.24" - - name: Configure private Go modules (punchh) + # Go uses git for GOPRIVATE modules; netrc + url.insteadOf avoids + # "could not read Username for 'https://github.com': terminal prompts disabled". + - name: Authenticate for private github.com/punchh modules env: TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} run: | - if [ -n "$TOKEN" ]; then - git config --global url."https://x-access-token:${TOKEN}@github.com/punchh/".insteadOf "https://github.com/punchh/" + if [ -z "$TOKEN" ]; then + echo "::error::SVC_ACCOUNT_GITHUB_ORG_TOKEN is empty or not passed to this job." + echo "Add the org/repo secret under Settings → Secrets and variables → Actions." + echo "Fork PRs: GitHub does not give fork workflows access to org secrets—use a branch on this repo for the PR." + exit 1 fi + { + echo "machine github.com" + echo "login x-access-token" + echo "password ${TOKEN}" + } >> "$HOME/.netrc" + chmod 600 "$HOME/.netrc" + git config --global url."https://x-access-token:${TOKEN}@github.com/punchh/".insteadOf "https://github.com/punchh/" - name: Go mod download env: GOPRIVATE: github.com/punchh GONOSUMDB: github.com/punchh + GOPROXY: direct run: go mod download - name: Build env: GOPRIVATE: github.com/punchh + GOPROXY: direct run: go build -v ./... - name: Test env: GOPRIVATE: github.com/punchh + GOPROXY: direct run: go test -v ./... From fc884bcef829b9cee476550dbde5ff92dc60b81b Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 08:01:12 +0530 Subject: [PATCH 07/11] github workflow changes --- .github/workflows/ci.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 99b47db..70c00ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,15 +25,19 @@ jobs: # Go uses git for GOPRIVATE modules; netrc + url.insteadOf avoids # "could not read Username for 'https://github.com': terminal prompts disabled". + # Prefer org PAT (works for fork PRs if you expose a dedicated secret — usually you still + # need a branch on the upstream repo). If unset, fall back to GITHUB_TOKEN (same-repo + # workflows only; org must allow Actions to read private repos — see GitHub docs). - name: Authenticate for private github.com/punchh modules env: - TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} + PAT: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + TOKEN="${PAT}" if [ -z "$TOKEN" ]; then - echo "::error::SVC_ACCOUNT_GITHUB_ORG_TOKEN is empty or not passed to this job." - echo "Add the org/repo secret under Settings → Secrets and variables → Actions." - echo "Fork PRs: GitHub does not give fork workflows access to org secrets—use a branch on this repo for the PR." - exit 1 + TOKEN="${GITHUB_TOKEN}" + echo "SVC_ACCOUNT_GITHUB_ORG_TOKEN not set — using GITHUB_TOKEN for git HTTPS." + echo "If go mod download fails with 403, add SVC_ACCOUNT_GITHUB_ORG_TOKEN or open the PR from a branch on this repo (not a fork)." fi { echo "machine github.com" From b3a1584a4b095af392300e270f5f0815b8d0f6ad Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 08:03:54 +0530 Subject: [PATCH 08/11] github workflow changes --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70c00ef..7e0a8dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,21 +47,21 @@ jobs: chmod 600 "$HOME/.netrc" git config --global url."https://x-access-token:${TOKEN}@github.com/punchh/".insteadOf "https://github.com/punchh/" + # Do not set GOPROXY=direct: it forces every module through git; some public tags + # (e.g. chenzhuoyu/iasm) can fail with "unknown revision" on GitHub while proxy.golang.org still serves them. + # GOPRIVATE already makes only github.com/punchh/* bypass the proxy. - name: Go mod download env: GOPRIVATE: github.com/punchh GONOSUMDB: github.com/punchh - GOPROXY: direct run: go mod download - name: Build env: GOPRIVATE: github.com/punchh - GOPROXY: direct run: go build -v ./... - name: Test env: GOPRIVATE: github.com/punchh - GOPROXY: direct run: go test -v ./... From dda49e23e661de167ff7c7e1f2beeaa62a344052 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 08:06:39 +0530 Subject: [PATCH 09/11] github workflow changes --- .github/workflows/ci.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e0a8dc..2c9d3a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,21 +23,19 @@ jobs: with: go-version: "1.24" - # Go uses git for GOPRIVATE modules; netrc + url.insteadOf avoids - # "could not read Username for 'https://github.com': terminal prompts disabled". - # Prefer org PAT (works for fork PRs if you expose a dedicated secret — usually you still - # need a branch on the upstream repo). If unset, fall back to GITHUB_TOKEN (same-repo - # workflows only; org must allow Actions to read private repos — see GitHub docs). + # Private module github.com/punchh/go-packages must use a PAT: GITHUB_TOKEN only has + # access to *this* repo, so GitHub returns misleading "repository not found" for other private repos. + # Fork PRs: org secrets are not available — push a branch on punchh/code-push-server-go. - name: Authenticate for private github.com/punchh modules env: - PAT: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} run: | - TOKEN="${PAT}" if [ -z "$TOKEN" ]; then - TOKEN="${GITHUB_TOKEN}" - echo "SVC_ACCOUNT_GITHUB_ORG_TOKEN not set — using GITHUB_TOKEN for git HTTPS." - echo "If go mod download fails with 403, add SVC_ACCOUNT_GITHUB_ORG_TOKEN or open the PR from a branch on this repo (not a fork)." + echo "::error::SVC_ACCOUNT_GITHUB_ORG_TOKEN is required to clone github.com/punchh/go-packages." + echo "GITHUB_TOKEN cannot read sibling private repos (GitHub reports that as 'repository not found')." + echo "Add an org or repo Actions secret: classic PAT with repo scope, or fine-grained PAT with read on punchh/go-packages." + echo "Fork PRs do not receive org secrets — open the PR from a branch on this repository." + exit 1 fi { echo "machine github.com" From 1d5f8e142491d7ba8a2735e1c13b3264cc3adf85 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 08:08:13 +0530 Subject: [PATCH 10/11] github workflow changes --- .github/workflows/ci.yml | 89 +++++++++++++++------------------------- 1 file changed, 33 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c9d3a9..b3ad83d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,65 +1,42 @@ -# Self-contained Go CI (does not call punchh/GHA-central-workflow — that reusable -# workflow must be allowed by org settings; use this file if you see "workflow was not found".) - name: Go CI on: pull_request: - push: + push: branches: - main - workflow_dispatch: -permissions: - contents: read + workflow_dispatch: + inputs: + skip_tests: + description: 'Skip running tests' + required: false + default: false + type: boolean + triggered_user: + description: 'Who triggered the workflow' + required: false + default: "" + type: string jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v5 - with: - go-version: "1.24" - - # Private module github.com/punchh/go-packages must use a PAT: GITHUB_TOKEN only has - # access to *this* repo, so GitHub returns misleading "repository not found" for other private repos. - # Fork PRs: org secrets are not available — push a branch on punchh/code-push-server-go. - - name: Authenticate for private github.com/punchh modules - env: - TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} - run: | - if [ -z "$TOKEN" ]; then - echo "::error::SVC_ACCOUNT_GITHUB_ORG_TOKEN is required to clone github.com/punchh/go-packages." - echo "GITHUB_TOKEN cannot read sibling private repos (GitHub reports that as 'repository not found')." - echo "Add an org or repo Actions secret: classic PAT with repo scope, or fine-grained PAT with read on punchh/go-packages." - echo "Fork PRs do not receive org secrets — open the PR from a branch on this repository." - exit 1 - fi - { - echo "machine github.com" - echo "login x-access-token" - echo "password ${TOKEN}" - } >> "$HOME/.netrc" - chmod 600 "$HOME/.netrc" - git config --global url."https://x-access-token:${TOKEN}@github.com/punchh/".insteadOf "https://github.com/punchh/" - - # Do not set GOPROXY=direct: it forces every module through git; some public tags - # (e.g. chenzhuoyu/iasm) can fail with "unknown revision" on GitHub while proxy.golang.org still serves them. - # GOPRIVATE already makes only github.com/punchh/* bypass the proxy. - - name: Go mod download - env: - GOPRIVATE: github.com/punchh - GONOSUMDB: github.com/punchh - run: go mod download - - - name: Build - env: - GOPRIVATE: github.com/punchh - run: go build -v ./... - - - name: Test - env: - GOPRIVATE: github.com/punchh - run: go test -v ./... + go-ci: + permissions: + id-token: write + contents: write + packages: read + uses: punchh/GHA-central-workflow/.github/workflows/go-ci.yml@main + + with: + repository: ${{ github.repository }} + branch: ${{ github.event_name == 'workflow_dispatch' && github.ref_name || (github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name) }} + go_version: 1.24.1 + triggered_user: ${{ github.event_name == 'workflow_dispatch' && inputs.triggered_user || '' }} + skip_tests: ${{ github.event_name == 'workflow_dispatch' && inputs.skip_tests || false }} + test_cases: false + snyk_severity_threshold: "critical" + go_build: true + secrets: + SVC_ACCOUNT_GITHUB_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_GITHUB_ORG_TOKEN }} + SVC_ACCOUNT_SNYK_ORG_TOKEN: ${{ secrets.SVC_ACCOUNT_SNYK_ORG_TOKEN }} + CAPTAIN_DEVOPS_SLACK_BOT_TOKEN: ${{ secrets.CAPTAIN_DEVOPS_SLACK_BOT_TOKEN }} \ No newline at end of file From f4f380899cd8281e0b0e792714ce23ee6cca5461 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sat, 25 Apr 2026 10:15:12 +0530 Subject: [PATCH 11/11] newrelic and airbrake integration changes --- .github/workflows/release.yaml | 4 ++-- README.md | 2 +- config/config.go | 23 +++++++++++++------ db/db.go | 5 +++- main.go | 11 +++++---- middleware/middleware.go | 42 +++++++++++----------------------- 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6abb60e..3e5cd7d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,9 +19,9 @@ jobs: with: fetch-depth: 0 - run: git fetch --force --tags - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: '1.21.5' + go-version: '1.24' cache: true # More assembly might be required: Docker logins, GPG, etc. It all depends # on your needs. diff --git a/README.md b/README.md index ab74d14..c7fa41a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Codepush server go is compatible with [react-native-code-push](https://github.co ## Support version - [mysql](https://dev.mysql.com/downloads/mysql/) >= 8.0 -- [golang](https://go.dev/dl/) >= 1.21.5 +- [golang](https://go.dev/dl/) >= 1.24 - [redis](https://redis.io/downloads/) >= 5.0 ## Support client version diff --git a/config/config.go b/config/config.go index f696a5a..2b3d111 100644 --- a/config/config.go +++ b/config/config.go @@ -80,18 +80,23 @@ func GetConfig() *appConfig { } func LoadConfig() *appConfig { - intFormatter := func(v interface{}) (val int64) { + intFormatter := func(v interface{}) (val int64, ok bool) { switch ta := v.(type) { case int: - val = int64(ta) + return int64(ta), true case int64: - val = ta + return ta, true case float64: - val = int64(ta) + return int64(ta), true case string: - val, _ = strconv.ParseInt(ta, 10, 64) + parsed, err := strconv.ParseInt(ta, 10, 64) + if err != nil { + return 0, false + } + return parsed, true + default: + return 0, false } - return } fmt.Println("Fetching config from AWS secret manager...") @@ -226,7 +231,11 @@ func LoadConfig() *appConfig { } if k == "airbrake_project_id" { - config.AirbrakeProjectID = intFormatter(v) + if parsed, ok := intFormatter(v); ok { + config.AirbrakeProjectID = parsed + } else { + fmt.Printf("config: invalid airbrake_project_id value (%T): %v\n", v, v) + } } if k == "airbrake_project_key" { config.AirbrakeProjectKey = v.(string) diff --git a/db/db.go b/db/db.go index 79a774b..2671a48 100644 --- a/db/db.go +++ b/db/db.go @@ -22,7 +22,10 @@ func GetUserDB() (odb *gorm.DB, err error) { dbConfig := config.GetConfig().DBUser dsnSource := dbConfig.Write.UserName + ":" + dbConfig.Write.Password + "@tcp(" + dbConfig.Write.Host + ":" + strconv.Itoa(int(dbConfig.Write.Port)) + ")/" + dbConfig.Write.DBname + "?charset=utf8mb4&parseTime=True&loc=Local" - // Same driver as go-email-templates (sql.Open("nrmysql", ...)); pairs with HTTP txns when using Request context. + // New Relic datastore instrumentation: + // Using the "nrmysql" driver enables MySQL metrics. To associate DB segments with the + // current HTTP transaction, queries must run with the request context + // (e.g. via `db.WithContext(c.Request.Context())` in handlers). db, err := gorm.Open(mysql.New(mysql.Config{ DriverName: "nrmysql", DSN: dsnSource, diff --git a/main.go b/main.go index 8ed0652..593136a 100644 --- a/main.go +++ b/main.go @@ -44,16 +44,19 @@ func main() { nrKey = os.Getenv("NEW_RELIC_LICENSE_KEY") } - nr, err := punchhmw.Newnewrelic(configs.Environment, "code-push-server-go", nrKey) - if err != nil { - logger.Println("newrelic init:", err) + var nr *punchhmw.NewRelic + if nrKey != "" { + var err error + nr, err = punchhmw.Newnewrelic(configs.Environment, "code-push-server-go", nrKey) + if err != nil { + logger.Println("newrelic init:", err) + } } logger.Println("starting HTTP server") g := gin.New() g.Use(gin.Logger()) - g.Use(localmw.AirbrakeRecovery()) if nr != nil && nr.Application != nil { g.Use(nrgin.Middleware(nr.Application)) } diff --git a/middleware/middleware.go b/middleware/middleware.go index 4795e88..4f0ab28 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -19,35 +19,6 @@ func SetAirbrakeHook(hook *punchhmw.Airbrake) { airbrakeHook = hook } -func AirbrakeRecovery() gin.HandlerFunc { - return func(c *gin.Context) { - defer func() { - if r := recover(); r != nil { - if airbrakeHook != nil { - airbrakeHook.Notify(r, c.Request) - } - log.Printf("Error:%v", r) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ - "code": 500, - "msg": "Internal Server Error", - "success": false, - }) - } - }() - c.Next() - if c.Writer.Status() >= http.StatusInternalServerError { - if len(c.Errors) > 0 { - for _, e := range c.Errors { - if airbrakeHook != nil { - airbrakeHook.Notify(e.Err, c.Request) - } - log.Printf("server error: %v", e.Err) - } - } - } - } -} - // 檢查token func CheckToken(ctx *gin.Context) { var token, _ = ctx.Cookie("token") @@ -90,6 +61,9 @@ func Recover(c *gin.Context) { // 加载defer异常处理 defer func() { if err := recover(); err != nil { + if airbrakeHook != nil { + airbrakeHook.Notify(err, c.Request) + } c.Writer.WriteHeader(http.StatusInternalServerError) log.Printf("Error:%s", err) // 返回统一的Json风格 @@ -115,4 +89,14 @@ func Recover(c *gin.Context) { } //继续操作 c.Next() + + // Report 5xx errors after handler execution (non-panic paths). + if c.Writer.Status() >= http.StatusInternalServerError && len(c.Errors) > 0 { + for _, e := range c.Errors { + if airbrakeHook != nil { + airbrakeHook.Notify(e.Err, c.Request) + } + log.Printf("server error: %v", e.Err) + } + } }