First refactor commit

This commit is contained in:
Daniel F 2023-07-11 20:36:37 +01:00
parent d0d6fdb93c
commit 48bf57695b
43 changed files with 1405 additions and 22 deletions

8
go/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.env
coverage.html
coverage.out
coverage.xml
target
!docs/
docs/*
!docs/swagger.yaml

45
go/Dockerfile Normal file
View File

@ -0,0 +1,45 @@
# Specifies a parent image
FROM golang:1.19.2-bullseye as build
# Creates an app directory to hold your apps 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" ]

88
go/Makefile Normal file
View File

@ -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 .

View File

@ -0,0 +1,8 @@
package controllers
import "go.uber.org/fx"
var Module = fx.Options(
fx.Provide(NewItemController),
fx.Provide(NewSwaggerController),
)

View File

@ -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)
}

View File

@ -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())
})
}

View File

@ -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))
}

View File

@ -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()
}
}

View File

@ -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,
}))
}

View File

@ -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()
}
}

29
go/api/routes/item.go Normal file
View File

@ -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,
}
}

31
go/api/routes/routes.go Normal file
View File

@ -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()
}
}

29
go/api/routes/swagger.go Normal file
View File

@ -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,
}
}

30
go/bootstrap/app.go Normal file
View File

@ -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()

18
go/bootstrap/modules.go Normal file
View File

@ -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,
)

48
go/cmd/cmd.go Normal file
View File

@ -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
}

40
go/cmd/serve.go Normal file
View File

@ -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{}
}

7
go/docker-compose.yml Normal file
View File

@ -0,0 +1,7 @@
version: "3"
services:
gilded-rose:
image: gilded-rose:latest
ports:
- 8080:8080

View File

@ -0,0 +1,9 @@
package domains
import (
"github.com/emilybache/gildedrose-refactoring-kata/models"
)
type ItemUpdateService interface {
UpdateQuality(item *models.Item) error
}

View File

@ -0,0 +1,9 @@
package domains
import (
"github.com/emilybache/gildedrose-refactoring-kata/models"
)
type ItemUpdateServiceProvider interface {
GetUpdateService(item *models.Item) ItemUpdateService
}

View File

@ -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)
}
}

View File

@ -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
)

291
go/go.sum Normal file
View File

@ -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=

32
go/lib/command.go Normal file
View File

@ -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
}

34
go/lib/env.go Normal file
View File

@ -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
}

10
go/lib/lib.go Normal file
View File

@ -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),
)

181
go/lib/logger.go Normal file
View File

@ -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)
}

20
go/lib/request_handler.go Normal file
View File

@ -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}
}

12
go/main.go Normal file
View File

@ -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()
}

32
go/models/item.go Normal file
View File

@ -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)
}

View File

@ -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
}

8
go/services/services.go Normal file
View File

@ -0,0 +1,8 @@
package services
import "go.uber.org/fx"
var Module = fx.Options(
fx.Provide(NewItemUpdateService),
fx.Provide(NewItemUpdateServiceProvider),
)

View File

@ -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

View File

@ -0,0 +1,2 @@
#!/bin/bash
exec "$1" test "${@:2}"