diff --git a/go/.gitignore b/go/.gitignore new file mode 100644 index 00000000..554c8b8b --- /dev/null +++ b/go/.gitignore @@ -0,0 +1,8 @@ +.env +coverage.html +coverage.out +coverage.xml +target +!docs/ +docs/* +!docs/swagger.yaml diff --git a/go/Dockerfile b/go/Dockerfile new file mode 100644 index 00000000..71302f8d --- /dev/null +++ b/go/Dockerfile @@ -0,0 +1,45 @@ +# Specifies a parent image +FROM golang:1.19.2-bullseye as build + +# Creates an app directory to hold your app’s source code +WORKDIR /app + +# Copies everything from your root directory into /app +COPY go.* ./ + +ENV GOCACHE=/.cache/go-build +ENV GOMODCACHE=/go/mod/pkg + +# Installs Go dependencies +RUN go mod download + +COPY . ./ + +ENV CGO_ENABLED=0 + +# We will mark this image with a configurable tag +ARG BUILD_TAG=unknown +LABEL BUILD_TAG=$BUILD_TAG + +# Builds your app with optional configuration +RUN go install github.com/swaggo/swag/cmd/swag@v1.16.1 +RUN swag init +RUN go build -a -o target/bin/gilded-rose ./main.go + + + +FROM scratch as runtime + +WORKDIR /app + +# We will mark this image with a configurable tag +ARG BUILD_TAG=unknown +LABEL BUILD_TAG=$BUILD_TAG + +COPY --from=build /app/target/bin/gilded-rose /app/target/bin/gilded-rose + +# Tells Docker which network port your container listens on +EXPOSE 8080 + +ENTRYPOINT [ "/app/target/bin/gilded-rose" ] +CMD [ "app:serve" ] diff --git a/go/Makefile b/go/Makefile new file mode 100644 index 00000000..93339a98 --- /dev/null +++ b/go/Makefile @@ -0,0 +1,88 @@ +# Makefile for gilded-rose +# vim: set ft=make ts=8 noet +# Copyright Cabify.com +# Licence MIT + +# Variables +# UNAME := $(shell uname -s) + +.EXPORT_ALL_VARIABLES: + +# this is godly +# https://news.ycombinator.com/item?id=11939200 +.PHONY: help +help: ### this screen. Keep it first target to be default +ifeq ($(UNAME), Linux) + @grep -P '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' +else + @# this is not tested, but prepared in advance for you, Mac drivers + @awk -F ':.*###' '$$0 ~ FS {printf "%15s%s\n", $$1 ":", $$2}' \ + $(MAKEFILE_LIST) | grep -v '@awk' | sort +endif + +# Targets +# +.PHONY: debug +debug: ### Debug Makefile itself + @echo $(UNAME) + +.PHONY: build-base +build-base: + docker run \ + --env CGO_ENABLED=0 \ + --env GOCACHE=/.cache/go-build \ + --env GOMODCACHE=/go/mod/pkg \ + -v "$$PWD:/app:rw" -v "$$HOME/.cache/go-build:/.cache/go-build:rw" -v "$$HOME/.cache/go-mod-pkg:/go/mod/pkg:rw" \ + -w /app \ + -u "$$(id -u):$$(id -g)" \ + --entrypoint "/bin/sh" \ + --rm -it \ + golang:1.19.2-bullseye -c "$$GO_BUILD_CMD" + +.PHONY: build +build: + GO_BUILD_CMD="go install github.com/swaggo/swag/cmd/swag@v1.16.1 && swag init" make build-base + GO_BUILD_CMD="go build -a -o target/bin/gilded-rose ./main.go" make build-base + +.PHONY: build-dev +build-dev: + GO_BUILD_CMD="go install github.com/swaggo/swag/cmd/swag@v1.16.1 && swag init" make build-base + GO_BUILD_CMD="go build -v -o target/bin/gilded-rose ./main.go" make build-base + +.PHONY: unit-test +unit-test: + GO_BUILD_CMD="go install github.com/swaggo/swag/cmd/swag@v1.16.1 && swag init" make build-base + GO_BUILD_CMD="go test ./... -cover -coverprofile=coverage.out" make build-base + GO_BUILD_CMD="go tool cover -html=coverage.out -o coverage.html" make build-base + +.PHONY: mod-tidy +mod-tidy: + GO_BUILD_CMD="go mod tidy" make build-base + +.PHONY: run +run: build-dev + target/bin/gilded-rose app:serve + +.PHONY: test +test: build-dev + target/bin/gilded-rose test + +.PHONY: texttest +texttest: build-dev + docker run \ + --env XDG_CACHE_HOME=/.cache/pip \ + --env PIP_CACHE_DIR=/.cache/pip \ + --env TEXTTEST_ROOT=/app/texttests \ + --env TEXTTEST_PATH=/app \ + --env TEXTTEST_HOME=/app \ + -v "$$PWD:/app:rw" -v "$$HOME/.cache/pip:/.cache/pip:rw" \ + -w /app \ + -u "$$(id -u):$$(id -g)" \ + --entrypoint "/bin/sh" \ + --rm -it \ + python:3.9.17-slim-bookworm -c "pip install texttest && texttest -con" + +.PHONY: docker +docker: + docker build -t gilded-rose:latest . diff --git a/go/api/controllers/controllers.go b/go/api/controllers/controllers.go new file mode 100644 index 00000000..ac5868f9 --- /dev/null +++ b/go/api/controllers/controllers.go @@ -0,0 +1,8 @@ +package controllers + +import "go.uber.org/fx" + +var Module = fx.Options( + fx.Provide(NewItemController), + fx.Provide(NewSwaggerController), +) diff --git a/go/api/controllers/item_controller.go b/go/api/controllers/item_controller.go new file mode 100644 index 00000000..5ceb9611 --- /dev/null +++ b/go/api/controllers/item_controller.go @@ -0,0 +1,98 @@ +package controllers + +import ( + "net/http" + + "github.com/emilybache/gildedrose-refactoring-kata/domains" + "github.com/emilybache/gildedrose-refactoring-kata/models" + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/emilybache/gildedrose-refactoring-kata/api/middlewares" + "github.com/gin-gonic/gin" +) + +type ItemController struct { + logger lib.Logger + contentTypeFilterMiddleware middlewares.ContentTypeFilterMiddleware + itemUpdateServiceProvider domains.ItemUpdateServiceProvider +} + +type UpdateQualityRequest struct { + Days int `json:"days" binding:"gte=0"` + Items []*models.ItemModel `json:"items" binding:"required"` +} + +func NewItemController( + logger lib.Logger, + contentTypeFilterMiddleware middlewares.ContentTypeFilterMiddleware, + itemUpdateServiceProvider domains.ItemUpdateServiceProvider, +) ItemController { + return ItemController{ + logger: logger, + contentTypeFilterMiddleware: contentTypeFilterMiddleware, + itemUpdateServiceProvider: itemUpdateServiceProvider, + } +} + +func (this *ItemController) Setup(engine *gin.Engine) { + engine.GET("/status", this.getStatus) + engine.POST("/update_quality", this.contentTypeFilterMiddleware.Handler("application/json"), this.postUpdateQuality) + engine.NoRoute(this.invalidPath) +} + +func (this *ItemController) invalidPath(ctx *gin.Context) { + ctx.AbortWithStatus(http.StatusNotFound) +} + +// getStatus godoc +// @Summary Health check (get status) +// @Schemes +// @Description Return a simple OK response +// @Tags health +// @Accept json +// @Produce json +// @Success 200 "Service is up and running" +// @Router /status [get] +func (this *ItemController) getStatus(ctx *gin.Context) { + ctx.JSON(http.StatusOK, gin.H{ + "status": "ok", + }) +} + +// postUpdateQuality godoc +// @Summary Execute Update Quality for all given items and passed days +// @Schemes +// @Description Load a full list of items that will be handled by the service and process them, returning the item list with the updated values for the given days +// @Tags items +// @Accept json +// @Param message body UpdateQualityRequest true "Items info" +// @Success 200 "Result of items with updated quality" +// @Failure 400 "Invalid data in the request" +// @Router /update_quality [post] +func (this *ItemController) postUpdateQuality(ctx *gin.Context) { + + var request UpdateQualityRequest + + if err := ctx.BindJSON(&request); err != nil { + ctx.AbortWithStatus(http.StatusBadRequest) + return + } + + var items = make([]*models.Item, len(request.Items)) + for i, item := range request.Items { + items[i] = models.NewItem(item) + } + + for day := 0; day < request.Days; day++ { + for _, item := range items { + itemUpdateService := this.itemUpdateServiceProvider.GetUpdateService(item) + itemUpdateService.UpdateQuality(item) + } + } + + var itemEntities = make([]*models.ItemModel, len(items)) + for i, item := range items { + itemEntities[i] = item.Model + } + + ctx.JSON(http.StatusOK, itemEntities) +} diff --git a/go/api/controllers/item_controller_test.go b/go/api/controllers/item_controller_test.go new file mode 100644 index 00000000..207e7906 --- /dev/null +++ b/go/api/controllers/item_controller_test.go @@ -0,0 +1,57 @@ +package controllers + +import ( + "net/http" + "net/http/httptest" + //"strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.uber.org/fx" + "go.uber.org/fx/fxtest" + + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/emilybache/gildedrose-refactoring-kata/services" + "github.com/emilybache/gildedrose-refactoring-kata/api/middlewares" +) + +var TestCommonModules = fx.Options( + Module, + lib.Module, + services.Module, + middlewares.Module, +) + +type TestCaseRunner interface{} + +func setupTestCase(handler lib.RequestHandler, logger lib.Logger, itemController ItemController) { + logger.Info("Setup test case") + itemController.Setup(handler.Gin) +} + +func runTestCase(t *testing.T, runner TestCaseRunner) { + app := fxtest.New(t, TestCommonModules, fx.Invoke(setupTestCase), fx.Invoke(runner)) + + defer app.RequireStart().RequireStop() + require.NoError(t, app.Err()) +} + +func executeRequest(handler lib.RequestHandler, req *http.Request) *httptest.ResponseRecorder { + result := httptest.NewRecorder() + handler.Gin.ServeHTTP(result, req) + return result +} + +func TestStatus(t *testing.T) { + runTestCase(t, func( + handler lib.RequestHandler, + ) { + req, _ := http.NewRequest("GET", "/status", nil) + + w := executeRequest(handler, req) + assert.Equal(t, 200, w.Code) + assert.Equal(t, `{"status":"ok"}`, w.Body.String()) + }) +} diff --git a/go/api/controllers/swagger_controller.go b/go/api/controllers/swagger_controller.go new file mode 100644 index 00000000..126c899a --- /dev/null +++ b/go/api/controllers/swagger_controller.go @@ -0,0 +1,30 @@ +package controllers + +import ( + docs "github.com/emilybache/gildedrose-refactoring-kata/docs" + swaggerfiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" + + "github.com/emilybache/gildedrose-refactoring-kata/lib" + + "github.com/gin-gonic/gin" +) + +type SwaggerController struct { + logger lib.Logger +} + +func NewSwaggerController(logger lib.Logger) SwaggerController { + return SwaggerController{ + logger: logger, + } +} + +func (this *SwaggerController) Setup(engine *gin.Engine) { + docs.SwaggerInfo.Title = "Gilded Rose Service" + docs.SwaggerInfo.Description = "This service implements the Gilded Rose item update service." + docs.SwaggerInfo.Version = "1.0" + docs.SwaggerInfo.BasePath = "/" + + engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) +} diff --git a/go/api/middlewares/content_type_filter.go b/go/api/middlewares/content_type_filter.go new file mode 100644 index 00000000..4e28b08e --- /dev/null +++ b/go/api/middlewares/content_type_filter.go @@ -0,0 +1,31 @@ +package middlewares + +import ( + "net/http" + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/gin-gonic/gin" +) + +type ContentTypeFilterMiddleware struct { + logger lib.Logger +} + +func NewContentTypeFilterMiddleware(logger lib.Logger) ContentTypeFilterMiddleware { + return ContentTypeFilterMiddleware{ + logger: logger, + } +} + +func (this ContentTypeFilterMiddleware) Setup() { + this.logger.Info("Setting up content type filter middleware") +} + +func (this ContentTypeFilterMiddleware) Handler(allowedType string) gin.HandlerFunc { + return func(ctx *gin.Context) { + if ctx.ContentType() != allowedType { + ctx.AbortWithStatus(http.StatusUnsupportedMediaType) + return + } + ctx.Next() + } +} diff --git a/go/api/middlewares/cors.go b/go/api/middlewares/cors.go new file mode 100644 index 00000000..6b43dd8f --- /dev/null +++ b/go/api/middlewares/cors.go @@ -0,0 +1,33 @@ +package middlewares + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/lib" + cors "github.com/rs/cors/wrapper/gin" +) + +type CorsMiddleware struct { + handler lib.RequestHandler + logger lib.Logger + env lib.Env +} + +func NewCorsMiddleware(handler lib.RequestHandler, logger lib.Logger, env lib.Env) CorsMiddleware { + return CorsMiddleware{ + handler: handler, + logger: logger, + env: env, + } +} + +func (this CorsMiddleware) Setup() { + this.logger.Info("Setting up cors middleware") + + debug := this.env.Environment == "development" + this.handler.Gin.Use(cors.New(cors.Options{ + AllowCredentials: true, + AllowOriginFunc: func(origin string) bool { return true }, + AllowedHeaders: []string{"*"}, + AllowedMethods: []string{"GET", "POST", "PUT", "HEAD", "OPTIONS"}, + Debug: debug, + })) +} diff --git a/go/api/middlewares/middlewares.go b/go/api/middlewares/middlewares.go new file mode 100644 index 00000000..c82807f3 --- /dev/null +++ b/go/api/middlewares/middlewares.go @@ -0,0 +1,31 @@ +package middlewares + +import "go.uber.org/fx" + +var Module = fx.Options( + fx.Provide(NewCorsMiddleware), + fx.Provide(NewMiddlewares), + fx.Provide(NewContentTypeFilterMiddleware), +) + +type IMiddleware interface { + Setup() +} + +type Middlewares []IMiddleware + +func NewMiddlewares( + corsMiddleware CorsMiddleware, + contentTypeFilterMiddleware ContentTypeFilterMiddleware, +) Middlewares { + return Middlewares{ + corsMiddleware, + contentTypeFilterMiddleware, + } +} + +func (m Middlewares) Setup() { + for _, middleware := range m { + middleware.Setup() + } +} diff --git a/go/api/routes/item.go b/go/api/routes/item.go new file mode 100644 index 00000000..366ce1c6 --- /dev/null +++ b/go/api/routes/item.go @@ -0,0 +1,29 @@ +package routes + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/api/controllers" + "github.com/emilybache/gildedrose-refactoring-kata/lib" +) + +type ItemControllerRoutes struct { + logger lib.Logger + handler lib.RequestHandler + itemController controllers.ItemController +} + +func (this ItemControllerRoutes) Setup() { + this.logger.Info("Setting up item controller routes") + this.itemController.Setup(this.handler.Gin) +} + +func NewItemControllerRoutes( + logger lib.Logger, + handler lib.RequestHandler, + itemController controllers.ItemController, +) ItemControllerRoutes { + return ItemControllerRoutes{ + logger: logger, + handler: handler, + itemController: itemController, + } +} diff --git a/go/api/routes/routes.go b/go/api/routes/routes.go new file mode 100644 index 00000000..9339a549 --- /dev/null +++ b/go/api/routes/routes.go @@ -0,0 +1,31 @@ +package routes + +import "go.uber.org/fx" + +var Module = fx.Options( + fx.Provide(NewItemControllerRoutes), + fx.Provide(NewSwaggerRoutes), + fx.Provide(NewRoutes), +) + +type Routes []Route + +type Route interface { + Setup() +} + +func NewRoutes( + itemControllerRoutes ItemControllerRoutes, + swaggerRoutes SwaggerRoutes, +) Routes { + return Routes{ + itemControllerRoutes, + swaggerRoutes, + } +} + +func (r Routes) Setup() { + for _, route := range r { + route.Setup() + } +} diff --git a/go/api/routes/swagger.go b/go/api/routes/swagger.go new file mode 100644 index 00000000..48a7947c --- /dev/null +++ b/go/api/routes/swagger.go @@ -0,0 +1,29 @@ +package routes + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/api/controllers" + "github.com/emilybache/gildedrose-refactoring-kata/lib" +) + +type SwaggerRoutes struct { + logger lib.Logger + handler lib.RequestHandler + swaggerController controllers.SwaggerController +} + +func (this SwaggerRoutes) Setup() { + this.logger.Info("Setting up swagger routes") + this.swaggerController.Setup(this.handler.Gin) +} + +func NewSwaggerRoutes( + logger lib.Logger, + handler lib.RequestHandler, + swaggerController controllers.SwaggerController, +) SwaggerRoutes { + return SwaggerRoutes{ + logger: logger, + handler: handler, + swaggerController: swaggerController, + } +} diff --git a/go/bootstrap/app.go b/go/bootstrap/app.go new file mode 100644 index 00000000..486a5b1b --- /dev/null +++ b/go/bootstrap/app.go @@ -0,0 +1,30 @@ +package bootstrap + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/cmd" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "gilded-rose", + Short: "Clean architecture using gin framework", + Long: ` +This is a command runner or cli for api architecture in golang. +Using this we can use underlying dependency injection container for running scripts. +Main advantage is that, we can use same services, repositories, infrastructure present in the application itself`, + TraverseChildren: true, +} + +type App struct { + *cobra.Command +} + +func NewApp() App { + command := App{ + Command: rootCmd, + } + command.AddCommand(cmd.GetSubCommands(CommonModules)...) + return command +} + +var RootApp = NewApp() diff --git a/go/bootstrap/modules.go b/go/bootstrap/modules.go new file mode 100644 index 00000000..bedf3990 --- /dev/null +++ b/go/bootstrap/modules.go @@ -0,0 +1,18 @@ +package bootstrap + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/api/controllers" + "github.com/emilybache/gildedrose-refactoring-kata/api/middlewares" + "github.com/emilybache/gildedrose-refactoring-kata/api/routes" + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/emilybache/gildedrose-refactoring-kata/services" + "go.uber.org/fx" +) + +var CommonModules = fx.Options( + controllers.Module, + middlewares.Module, + routes.Module, + lib.Module, + services.Module, +) diff --git a/go/cmd/cmd.go b/go/cmd/cmd.go new file mode 100644 index 00000000..21dba96e --- /dev/null +++ b/go/cmd/cmd.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "context" + + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/spf13/cobra" + "go.uber.org/fx" + "go.uber.org/fx/fxevent" +) + +var cmds = map[string]lib.Command{ + "app:serve": NewServeCommand(), + "test": NewTextTestFixtureCommand(), +} + +func GetSubCommands(opt fx.Option) []*cobra.Command { + var subCommands []*cobra.Command + for name, command := range cmds { + subCommands = append(subCommands, WrapSubCommand(name, command, opt)) + } + return subCommands +} + +func WrapSubCommand(name string, command lib.Command, opt fx.Option) *cobra.Command { + wrappedCmd := &cobra.Command{ + Use: name, + Short: command.Short(), + Run: func(c *cobra.Command, args []string) { + logger := lib.GetLogger() + opts := fx.Options( + fx.WithLogger(func() fxevent.Logger { + return logger.GetFxLogger() + }), + fx.Invoke(command.Run()), + ) + ctx := context.Background() + app := fx.New(opt, opts) + err := app.Start(ctx) + defer app.Stop(ctx) + if err != nil { + logger.Fatal(err) + } + }, + } + command.Setup(wrappedCmd) + return wrappedCmd +} diff --git a/go/cmd/serve.go b/go/cmd/serve.go new file mode 100644 index 00000000..f194e4ec --- /dev/null +++ b/go/cmd/serve.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/emilybache/gildedrose-refactoring-kata/api/middlewares" + "github.com/emilybache/gildedrose-refactoring-kata/api/routes" + "github.com/spf13/cobra" +) + +type ServeCommand struct{} + +func (this *ServeCommand) Short() string { + return "serve application" +} + +func (this *ServeCommand) Setup(command *cobra.Command) {} + +func (this *ServeCommand) Run() lib.CommandRunner { + return func( + middleware middlewares.Middlewares, + env lib.Env, + requestHandler lib.RequestHandler, + route routes.Routes, + logger lib.Logger, + ) { + logger.Info("Init") + middleware.Setup() + route.Setup() + logger.Info("Running server") + if env.ServerPort == "" { + _ = requestHandler.Gin.Run() + } else { + _ = requestHandler.Gin.Run(":" + env.ServerPort) + } + } +} + +func NewServeCommand() *ServeCommand { + return &ServeCommand{} +} diff --git a/go/texttest_fixture.go b/go/cmd/texttest_fixture.go similarity index 100% rename from go/texttest_fixture.go rename to go/cmd/texttest_fixture.go diff --git a/go/docker-compose.yml b/go/docker-compose.yml new file mode 100644 index 00000000..3b6c135c --- /dev/null +++ b/go/docker-compose.yml @@ -0,0 +1,7 @@ +version: "3" + +services: + gilded-rose: + image: gilded-rose:latest + ports: + - 8080:8080 diff --git a/go/domains/item_update_service.go b/go/domains/item_update_service.go new file mode 100644 index 00000000..00659789 --- /dev/null +++ b/go/domains/item_update_service.go @@ -0,0 +1,9 @@ +package domains + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/models" +) + +type ItemUpdateService interface { + UpdateQuality(item *models.Item) error +} diff --git a/go/domains/item_update_service_provider.go b/go/domains/item_update_service_provider.go new file mode 100644 index 00000000..47bcdd6e --- /dev/null +++ b/go/domains/item_update_service_provider.go @@ -0,0 +1,9 @@ +package domains + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/models" +) + +type ItemUpdateServiceProvider interface { + GetUpdateService(item *models.Item) ItemUpdateService +} diff --git a/go/gildedrose/gildedrose_test.go b/go/gildedrose/gildedrose_test.go deleted file mode 100644 index ec1bf49b..00000000 --- a/go/gildedrose/gildedrose_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package gildedrose_test - -import ( - "testing" - - "github.com/emilybache/gildedrose-refactoring-kata/gildedrose" -) - -func Test_Foo(t *testing.T) { - var items = []*gildedrose.Item{ - {"foo", 0, 0}, - } - - gildedrose.UpdateQuality(items) - - if items[0].Name != "fixme" { - t.Errorf("Name: Expected %s but got %s ", "fixme", items[0].Name) - } -} diff --git a/go/go.mod b/go/go.mod index 00f9da4e..726cf611 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,3 +1,74 @@ module github.com/emilybache/gildedrose-refactoring-kata -go 1.18 +go 1.19 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/joho/godotenv v1.4.0 + github.com/rs/cors/wrapper/gin v0.0.0-20230526135330-e90f16747950 + github.com/spf13/cobra v1.4.0 + github.com/spf13/viper v1.10.1 + github.com/stretchr/testify v1.8.3 + go.uber.org/fx v1.17.1 + go.uber.org/zap v1.21.0 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.2.0 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/bytedance/sonic v1.9.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.4 // 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.1 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.4.3 // 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 v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/cors v1.8.2 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect + github.com/swaggo/swag v1.16.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/dig v1.14.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.10.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect + golang.org/x/tools v0.10.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go/go.sum b/go/go.sum new file mode 100644 index 00000000..a582e0a7 --- /dev/null +++ b/go/go.sum @@ -0,0 +1,291 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig= +github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= +github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +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/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +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.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/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.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/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.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A= +github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= +github.com/go-playground/validator/v10 v10.14.1/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/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/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/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +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/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors/wrapper/gin v0.0.0-20230526135330-e90f16747950 h1:AqLt1PEuscqbMJkmkfOw1xLlDH0VIQzrDEuOGggv0a4= +github.com/rs/cors/wrapper/gin v0.0.0-20230526135330-e90f16747950/go.mod h1:gmu40DuK3SLdKUzGOUofS3UDZwyeOUy6ZjPPuaALatw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= +github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= +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 v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= +github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= +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= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/dig v1.14.0 h1:VmGvIH45/aapXPQkaOrK5u4B5B7jxZB98HM/utx0eME= +go.uber.org/dig v1.14.0/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o= +go.uber.org/fx v1.17.1 h1:S42dZ6Pok8hQ3jxKwo6ZMYcCgHQA/wAS/gnpRa1Pksg= +go.uber.org/fx v1.17.1/go.mod h1:yO7KN5rhlARljyo4LR047AjaV6J+KFzd/Z7rnTbEn0A= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/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/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/go/lib/command.go b/go/lib/command.go new file mode 100644 index 00000000..326a4e8b --- /dev/null +++ b/go/lib/command.go @@ -0,0 +1,32 @@ +package lib + +import "github.com/spf13/cobra" + +type CommandRunner interface{} + +// Command interface is used to implement sub-commands in the system. +type Command interface { + // Short returns string about short description of the command + // the string is shown in help screen of cobra command + Short() string + + // Setup is used to setup flags or pre-run steps for the command. + // + // For example, + // cmd.Flags().IntVarP(&r.num, "num", "n", 5, "description") + // + Setup(cmd *cobra.Command) + + // Run runs the command runner + // run returns command runner which is a function with dependency + // injected arguments. + // + // For example, + // Command{ + // Run: func(l lib.Logger) { + // l.Info("i am working") + // }, + // } + // + Run() CommandRunner +} diff --git a/go/lib/env.go b/go/lib/env.go new file mode 100644 index 00000000..ef22d3a7 --- /dev/null +++ b/go/lib/env.go @@ -0,0 +1,34 @@ +package lib + +import ( + "log" + "github.com/spf13/viper" +) + +// Env has environment stored +type Env struct { + ServerPort string `mapstructure:"SERVER_PORT"` + Environment string `mapstructure:"ENV"` + LogOutput string `mapstructure:"LOG_OUTPUT"` + LogLevel string `mapstructure:"LOG_LEVEL"` +} + +// NewEnv creates a new environment +func NewEnv() Env { + + env := Env{} + + viper.SetDefault("SERVER_PORT", "8080") + viper.SetDefault("ENV", "production") + viper.SetDefault("LOG_OUTPUT", "") + viper.SetDefault("LOG_LEVEL", "warn") + + viper.AutomaticEnv() + + err := viper.Unmarshal(&env) + if err != nil { + log.Fatal("☠️ environment can't be loaded: ", err) + } + + return env +} diff --git a/go/lib/lib.go b/go/lib/lib.go new file mode 100644 index 00000000..93584aa1 --- /dev/null +++ b/go/lib/lib.go @@ -0,0 +1,10 @@ +package lib + +import "go.uber.org/fx" + +// Module exports dependency +var Module = fx.Options( + fx.Provide(NewRequestHandler), + fx.Provide(NewEnv), + fx.Provide(GetLogger), +) diff --git a/go/lib/logger.go b/go/lib/logger.go new file mode 100644 index 00000000..17cfaea7 --- /dev/null +++ b/go/lib/logger.go @@ -0,0 +1,181 @@ +package lib + +import ( + "fmt" + + "go.uber.org/fx/fxevent" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// Logger structure +type Logger struct { + *zap.SugaredLogger +} + +type GinLogger struct { + *Logger +} + +type FxLogger struct { + *Logger +} + + +var ( + globalLogger *Logger + zapLogger *zap.Logger +) + +// GetLogger get the logger +func GetLogger() Logger { + if globalLogger == nil { + logger := newLogger(NewEnv()) + globalLogger = &logger + } + return *globalLogger +} + +// GetGinLogger get the gin logger +func (this Logger) GetGinLogger() GinLogger { + logger := zapLogger.WithOptions( + zap.WithCaller(false), + ) + return GinLogger{ + Logger: newSugaredLogger(logger), + } +} + +// GetFxLogger gets logger for go-fx +func (this *Logger) GetFxLogger() fxevent.Logger { + logger := zapLogger.WithOptions( + zap.WithCaller(false), + ) + return &FxLogger{Logger: newSugaredLogger(logger)} +} + +// LogEvent log event for fx logger +func (this *FxLogger) LogEvent(event fxevent.Event) { + switch e := event.(type) { + case *fxevent.OnStartExecuting: + this.Logger.Debug("OnStart hook executing: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + ) + case *fxevent.OnStartExecuted: + if e.Err != nil { + this.Logger.Debug("OnStart hook failed: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + zap.Error(e.Err), + ) + } else { + this.Logger.Debug("OnStart hook executed: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + zap.String("runtime", e.Runtime.String()), + ) + } + case *fxevent.OnStopExecuting: + this.Logger.Debug("OnStop hook executing: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + ) + case *fxevent.OnStopExecuted: + if e.Err != nil { + this.Logger.Debug("OnStop hook failed: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + zap.Error(e.Err), + ) + } else { + this.Logger.Debug("OnStop hook executed: ", + zap.String("callee", e.FunctionName), + zap.String("caller", e.CallerName), + zap.String("runtime", e.Runtime.String()), + ) + } + case *fxevent.Supplied: + this.Logger.Debug("supplied: ", zap.String("type", e.TypeName), zap.Error(e.Err)) + case *fxevent.Provided: + for _, rtype := range e.OutputTypeNames { + this.Logger.Debug("provided: ", e.ConstructorName, " => ", rtype) + } + case *fxevent.Decorated: + for _, rtype := range e.OutputTypeNames { + this.Logger.Debug("decorated: ", + zap.String("decorator", e.DecoratorName), + zap.String("type", rtype), + ) + } + case *fxevent.Invoking: + this.Logger.Debug("invoking: ", e.FunctionName) + case *fxevent.Started: + if e.Err == nil { + this.Logger.Debug("started") + } + case *fxevent.LoggerInitialized: + if e.Err == nil { + this.Logger.Debug("initialized: custom fxevent.Logger -> ", e.ConstructorName) + } + } +} + +func newSugaredLogger(logger *zap.Logger) *Logger { + return &Logger{ + SugaredLogger: logger.Sugar(), + } +} + +// newLogger sets up logger +func newLogger(env Env) Logger { + + config := zap.NewDevelopmentConfig() + logOutput := env.LogOutput + + if env.Environment == "development" { + fmt.Println("encode level") + config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + } + + if env.Environment == "production" && logOutput != "" { + config.OutputPaths = []string{logOutput} + } + + logLevel := env.LogLevel + level := zap.PanicLevel + switch logLevel { + case "debug": + level = zapcore.DebugLevel + case "info": + level = zapcore.InfoLevel + case "warn": + level = zapcore.WarnLevel + case "error": + level = zapcore.ErrorLevel + case "fatal": + level = zapcore.FatalLevel + default: + level = zap.PanicLevel + } + config.Level.SetLevel(level) + + zapLogger, _ = config.Build() + logger := newSugaredLogger(zapLogger) + + return *logger +} + +// Write interface implementation for gin-framework +func (this GinLogger) Write(p []byte) (n int, err error) { + this.Info(string(p)) + return len(p), nil +} + +// Printf prits go-fx logs +func (this FxLogger) Printf(str string, args ...interface{}) { + if len(args) > 0 { + this.Debugf(str, args) + } + this.Debug(str) +} diff --git a/go/lib/request_handler.go b/go/lib/request_handler.go new file mode 100644 index 00000000..234fd2a1 --- /dev/null +++ b/go/lib/request_handler.go @@ -0,0 +1,20 @@ +package lib + +import ( + "github.com/gin-gonic/gin" +) + +// RequestHandler function +type RequestHandler struct { + Gin *gin.Engine +} + +// NewRequestHandler creates a new request handler +func NewRequestHandler(logger Logger, env Env) RequestHandler { + gin.DefaultWriter = logger.GetGinLogger() + if env.Environment != "development" { + gin.SetMode(gin.ReleaseMode) + } + engine := gin.New() + return RequestHandler{Gin: engine} +} diff --git a/go/main.go b/go/main.go new file mode 100644 index 00000000..d947a5d3 --- /dev/null +++ b/go/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/bootstrap" + "github.com/joho/godotenv" +) + +// Application main entry point +func main() { + _ = godotenv.Load() + bootstrap.RootApp.Execute() +} diff --git a/go/models/item.go b/go/models/item.go new file mode 100644 index 00000000..967adbb9 --- /dev/null +++ b/go/models/item.go @@ -0,0 +1,32 @@ +package models + +import ( + "fmt" + "sync" +) + +type ItemModel struct { + Name string `json:"name" binding:"required"` + SellIn int `json:"sellIn" binding:"required"` + Quality int `json:"quality" binding:"required,gte=0"` +} + +type Item struct { + Model *ItemModel + Mutex *sync.RWMutex +} + +func NewItem(model *ItemModel) *Item { + return &Item{ + Model: model, + Mutex: &sync.RWMutex{}, + } +} + +func (this Item) String() string { + return this.Model.String() +} + +func (this ItemModel) String() string { + return fmt.Sprintf("%s, %d, %d", this.Name, this.SellIn, this.Quality) +} diff --git a/go/gildedrose/gildedrose.go b/go/services/item_update_service.go similarity index 100% rename from go/gildedrose/gildedrose.go rename to go/services/item_update_service.go diff --git a/go/services/item_update_service_provider.go b/go/services/item_update_service_provider.go new file mode 100644 index 00000000..49d30d11 --- /dev/null +++ b/go/services/item_update_service_provider.go @@ -0,0 +1,27 @@ +package services + +import ( + "github.com/emilybache/gildedrose-refactoring-kata/domains" + "github.com/emilybache/gildedrose-refactoring-kata/lib" + "github.com/emilybache/gildedrose-refactoring-kata/models" +) + +type ItemUpdateServiceProvider struct { + logger lib.Logger + itemUpdateService ItemUpdateService +} + +func NewItemUpdateServiceProvider( + logger lib.Logger, + itemUpdateService ItemUpdateService, +) domains.ItemUpdateServiceProvider { + + return ItemUpdateServiceProvider{ + logger: logger, + itemUpdateService: itemUpdateService, + } +} + +func (this ItemUpdateServiceProvider) GetUpdateService(item *models.Item) domains.ItemUpdateService { + return this.itemUpdateService +} diff --git a/go/services/services.go b/go/services/services.go new file mode 100644 index 00000000..17ab9df4 --- /dev/null +++ b/go/services/services.go @@ -0,0 +1,8 @@ +package services + +import "go.uber.org/fx" + +var Module = fx.Options( + fx.Provide(NewItemUpdateService), + fx.Provide(NewItemUpdateServiceProvider), +) diff --git a/texttests/README.md b/go/texttests/README.md similarity index 100% rename from texttests/README.md rename to go/texttests/README.md diff --git a/texttests/ThirtyDays/._options.gr b/go/texttests/ThirtyDays/._options.gr similarity index 100% rename from texttests/ThirtyDays/._options.gr rename to go/texttests/ThirtyDays/._options.gr diff --git a/texttests/ThirtyDays/options.gr b/go/texttests/ThirtyDays/options.gr similarity index 100% rename from texttests/ThirtyDays/options.gr rename to go/texttests/ThirtyDays/options.gr diff --git a/texttests/ThirtyDays/stderr.gr b/go/texttests/ThirtyDays/stderr.gr similarity index 100% rename from texttests/ThirtyDays/stderr.gr rename to go/texttests/ThirtyDays/stderr.gr diff --git a/texttests/ThirtyDays/stdout.gr b/go/texttests/ThirtyDays/stdout.gr similarity index 100% rename from texttests/ThirtyDays/stdout.gr rename to go/texttests/ThirtyDays/stdout.gr diff --git a/texttests/config.gr b/go/texttests/config.gr similarity index 89% rename from texttests/config.gr rename to go/texttests/config.gr index 877deb22..e5cb17ab 100755 --- a/texttests/config.gr +++ b/go/texttests/config.gr @@ -1,8 +1,11 @@ full_name:Gilded Rose Refactoring Kata # set your preferred editor and diff tool. -view_program:subl -diff_program:meld +view_program:vim +diff_program:diff + +executable:${TEXTTEST_HOME}/target/bin/gilded-rose +interpreter:${TEXTTEST_ROOT}/texttest_fixture.sh # Settings for the Python version #executable:${TEXTTEST_HOME}/python/texttest_fixture.py diff --git a/texttests/environment.gr b/go/texttests/environment.gr similarity index 100% rename from texttests/environment.gr rename to go/texttests/environment.gr diff --git a/texttests/testsuite.gr b/go/texttests/testsuite.gr similarity index 100% rename from texttests/testsuite.gr rename to go/texttests/testsuite.gr diff --git a/go/texttests/texttest_fixture.sh b/go/texttests/texttest_fixture.sh new file mode 100755 index 00000000..1451b1ba --- /dev/null +++ b/go/texttests/texttest_fixture.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec "$1" test "${@:2}"