├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── main.go ├── scaffold ├── scaffold.go └── scaffold_test.go ├── static ├── Makefile └── config │ └── config.yml └── template ├── Dockerfile ├── README.md ├── cmd └── main.tmpl ├── config ├── config.tmpl ├── database.tmpl ├── http.tmpl └── release.tmpl ├── docker-compose.yml ├── model └── model.tmpl └── web ├── routes.tmpl ├── server.tmpl └── version.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | 4 | go: 5 | - 1.10.x 6 | - 1.11.x 7 | - tip 8 | 9 | matrix: 10 | fast_finish: true 11 | include: 12 | - go: 1.11.x 13 | env: GO111MODULE=on 14 | 15 | script: 16 | - go test -v ./... -race -coverprofile=coverage.txt 17 | 18 | after_success: 19 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 CATCHPLAY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scaffold 2 | 3 | [![Build Status](https://travis-ci.org/catchplay/scaffold.svg)](https://travis-ci.org/catchplay/scaffold) 4 | [![codecov](https://codecov.io/gh/catchplay/scaffold/branch/master/graph/badge.svg)](https://codecov.io/gh/catchplay/scaffold) 5 | [![Go Report Card](https://goreportcard.com/badge/github.com/catchplay/scaffold)](https://goreportcard.com/report/github.com/catchplay/scaffold) 6 | [![GoDoc](https://godoc.org/github.com/catchplay/scaffold?status.svg)](https://godoc.org/github.com/catchplay/scaffold) 7 | 8 | Scaffold generates starter Go project layout. Let you can focus on buesiness logic implemeted. 9 | 10 | [![asciicast](https://asciinema.org/a/MA0ppdKfZSEl64cskUnqfsSiH.svg)](https://asciinema.org/a/MA0ppdKfZSEl64cskUnqfsSiH?autoplay=1&speed=2) 11 | 12 | The following is Go project layout scaffold generated: 13 | 14 | ``` 15 | ├── Dockerfile 16 | ├── Makefile 17 | ├── README.md 18 | ├── cmd 19 | │ └── main.go 20 | ├── config 21 | │ ├── config.go 22 | │ ├── config.yml 23 | │ ├── database.go 24 | │ ├── http.go 25 | │ └── release.go 26 | ├── docker-compose.yml 27 | ├── model 28 | │ └── model.go 29 | └── web 30 | ├── routes.go 31 | ├── server.go 32 | └── version.go 33 | ``` 34 | 35 | ## Installation 36 | 37 | Download scaffold by using: 38 | ```sh 39 | $ go get -u github.com/catchplay/scaffold 40 | ``` 41 | 42 | ## Create a new project 43 | 44 | 1. Going to your new project folder: 45 | ```sh 46 | # change to project directory 47 | $ cd $GOPATH/src/path/to/project 48 | ``` 49 | 50 | 2. Run `scaffold init` in the new project folder: 51 | 52 | ```sh 53 | $ scaffold init 54 | ``` 55 | 56 | 3. That will generate a whole new starter project files like: 57 | 58 | ``` 59 | Create Dockerfile 60 | Create README.md 61 | Create cmd/main.go 62 | Create config/config.go 63 | Create config/database.go 64 | Create config/http.go 65 | Create config/release.go 66 | Create docker-compose.yml 67 | Create model/model.go 68 | Create web/routes.go 69 | Create web/server.go 70 | Create web/version.go 71 | Create Makefile 72 | Create config/config.yml 73 | Success Created. Please excute `make up` to start service. 74 | 75 | ``` 76 | 77 | 4. And you can run the new project by using: 78 | ```sh 79 | $ make run 80 | ``` -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/catchplay/scaffold 2 | 3 | require ( 4 | github.com/pkg/errors v0.8.1 5 | github.com/urfave/cli v1.20.0 6 | ) 7 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 2 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 3 | github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= 4 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 5 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | 9 | "github.com/catchplay/scaffold/scaffold" 10 | "github.com/urfave/cli" 11 | ) 12 | 13 | func main() { 14 | app := cli.NewApp() 15 | app.Version = "1.0.0-rc" 16 | app.Usage = "Generate scaffold project layout for Go." 17 | app.Commands = []cli.Command{ 18 | { 19 | Name: "init", 20 | Aliases: []string{"i"}, 21 | Usage: " Generate scaffold project layout", 22 | Action: func(c *cli.Context) error { 23 | currDir, err := filepath.Abs(filepath.Dir(os.Args[0])) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | err = scaffold.New(false).Generate(currDir) 29 | //fmt.Printf("error:%+v\n", err) 30 | if err == nil { 31 | fmt.Println("Success Created. Please excute `make up` to start service.") 32 | } 33 | 34 | return err 35 | }, 36 | }, 37 | } 38 | 39 | err := app.Run(os.Args) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scaffold/scaffold.go: -------------------------------------------------------------------------------- 1 | package scaffold 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | pkgErr "github.com/pkg/errors" 12 | ) 13 | 14 | const ( 15 | GoScaffoldPath = "src/github.com/catchplay/scaffold" 16 | ) 17 | 18 | func init() { 19 | Gopath = os.Getenv("GOPATH") 20 | if Gopath == "" { 21 | panic("cannot find $GOPATH environment variable") 22 | } 23 | } 24 | 25 | var Gopath string 26 | 27 | type scaffold struct { 28 | debug bool 29 | } 30 | 31 | func New(debug bool) *scaffold { 32 | return &scaffold{debug: debug} 33 | } 34 | 35 | func (s *scaffold) Generate(path string) error { 36 | genAbsDir, err := filepath.Abs(path) 37 | if err != nil { 38 | return err 39 | } 40 | projectName := filepath.Base(genAbsDir) 41 | //TODO: have to check path MUST be under the $GOPATH/src folder 42 | goProjectPath := strings.TrimPrefix(genAbsDir, filepath.Join(Gopath, "src")+string(os.PathSeparator)) 43 | 44 | d := data{ 45 | AbsGenProjectPath: genAbsDir, 46 | ProjectPath: goProjectPath, 47 | ProjectName: projectName, 48 | Quit: "<-quit", 49 | } 50 | 51 | if err := s.genFromTemplate(getTemplateSets(), d); err != nil { 52 | return err 53 | } 54 | 55 | if err := s.genFormStaticFle(d); err != nil { 56 | return err 57 | } 58 | return nil 59 | } 60 | 61 | type data struct { 62 | AbsGenProjectPath string // The Abs Gen Project Path 63 | ProjectPath string //The Go import project path (eg:github.com/fooOrg/foo) 64 | ProjectName string //The project name which want to generated 65 | Quit string 66 | } 67 | 68 | type templateEngine struct { 69 | Templates []templateSet 70 | currDir string 71 | } 72 | 73 | type templateSet struct { 74 | templateFilePath string 75 | templateFileName string 76 | genFilePath string 77 | } 78 | 79 | func getTemplateSets() []templateSet { 80 | tt := templateEngine{} 81 | templatesFolder := filepath.Join(Gopath, GoScaffoldPath, "template/") 82 | //fmt.Printf("walk:%s\n", templatesFolder) 83 | filepath.Walk(templatesFolder, tt.visit) 84 | return tt.Templates 85 | } 86 | 87 | func (s *scaffold) genFromTemplate(templateSets []templateSet, d data) error { 88 | for _, tmpl := range templateSets { 89 | if err := s.tmplExec(tmpl, d); err != nil { 90 | return err 91 | } 92 | } 93 | return nil 94 | } 95 | 96 | func unescaped(x string) interface{} { return template.HTML(x) } 97 | 98 | func (s *scaffold) tmplExec(tmplSet templateSet, d data) error { 99 | tmpl := template.New(tmplSet.templateFileName) 100 | tmpl = tmpl.Funcs(template.FuncMap{"unescaped": unescaped}) 101 | tmpl, err := tmpl.ParseFiles(tmplSet.templateFilePath) 102 | if err != nil { 103 | return pkgErr.WithStack(err) 104 | } 105 | 106 | relateDir := filepath.Dir(tmplSet.genFilePath) 107 | 108 | distRelFilePath := filepath.Join(relateDir, filepath.Base(tmplSet.genFilePath)) 109 | distAbsFilePath := filepath.Join(d.AbsGenProjectPath, distRelFilePath) 110 | 111 | s.debugPrintf("distRelFilePath:%s\n", distRelFilePath) 112 | s.debugPrintf("distAbsFilePath:%s\n", distAbsFilePath) 113 | 114 | if err := os.MkdirAll(filepath.Dir(distAbsFilePath), os.ModePerm); err != nil { 115 | return pkgErr.WithStack(err) 116 | } 117 | 118 | dist, err := os.Create(distAbsFilePath) 119 | if err != nil { 120 | return pkgErr.WithStack(err) 121 | } 122 | defer dist.Close() 123 | 124 | fmt.Printf("Create %s\n", distRelFilePath) 125 | return tmpl.Execute(dist, d) 126 | } 127 | 128 | func (templEngine *templateEngine) visit(path string, f os.FileInfo, err error) error { 129 | if err != nil { 130 | return err 131 | } 132 | 133 | if ext := filepath.Ext(path); ext == ".tmpl" { 134 | templateFileName := filepath.Base(path) 135 | 136 | genFileBaeName := strings.TrimSuffix(templateFileName, ".tmpl") + ".go" 137 | genFileBasePath, err := filepath.Rel(filepath.Join(Gopath, GoScaffoldPath, "template"), filepath.Join(filepath.Dir(path), genFileBaeName)) 138 | if err != nil { 139 | return pkgErr.WithStack(err) 140 | } 141 | 142 | templ := templateSet{ 143 | templateFilePath: path, 144 | templateFileName: templateFileName, 145 | genFilePath: filepath.Join(templEngine.currDir, genFileBasePath), 146 | } 147 | 148 | templEngine.Templates = append(templEngine.Templates, templ) 149 | 150 | } else if mode := f.Mode(); mode.IsRegular() { 151 | templateFileName := filepath.Base(path) 152 | 153 | basepath := filepath.Join(Gopath, GoScaffoldPath, "template") 154 | targpath := filepath.Join(filepath.Dir(path), templateFileName) 155 | genFileBasePath, err := filepath.Rel(basepath, targpath) 156 | if err != nil { 157 | return pkgErr.WithStack(err) 158 | } 159 | 160 | templ := templateSet{ 161 | templateFilePath: path, 162 | templateFileName: templateFileName, 163 | genFilePath: filepath.Join(templEngine.currDir, genFileBasePath), 164 | } 165 | 166 | templEngine.Templates = append(templEngine.Templates, templ) 167 | } 168 | 169 | return nil 170 | } 171 | 172 | func (s *scaffold) genFormStaticFle(d data) error { 173 | walkerFuc := func(path string, f os.FileInfo, err error) error { 174 | if f.Mode().IsRegular() == true { 175 | src, err := os.Open(path) 176 | if err != nil { 177 | return pkgErr.WithStack(err) 178 | } 179 | defer src.Close() 180 | 181 | basepath := filepath.Join(Gopath, GoScaffoldPath, "static") 182 | distRelFilePath, err := filepath.Rel(basepath, path) 183 | if err != nil { 184 | return pkgErr.WithStack(err) 185 | } 186 | 187 | distAbsFilePath := filepath.Join(d.AbsGenProjectPath, distRelFilePath) 188 | 189 | if err := os.MkdirAll(filepath.Dir(distAbsFilePath), os.ModePerm); err != nil { 190 | return pkgErr.WithStack(err) 191 | } 192 | 193 | dist, err := os.Create(distAbsFilePath) 194 | if err != nil { 195 | return pkgErr.WithStack(err) 196 | } 197 | defer dist.Close() 198 | 199 | if _, err := io.Copy(dist, src); err != nil { 200 | return pkgErr.WithStack(err) 201 | } 202 | 203 | fmt.Printf("Create %s \n", distRelFilePath) 204 | } 205 | 206 | return nil 207 | } 208 | 209 | walkPath := filepath.Join(Gopath, GoScaffoldPath, "static") 210 | return filepath.Walk(walkPath, walkerFuc) 211 | } 212 | 213 | func (s *scaffold) debugPrintf(format string, a ...interface{}) { 214 | if s.debug == true { 215 | fmt.Printf(format, a...) 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /scaffold/scaffold_test.go: -------------------------------------------------------------------------------- 1 | package scaffold 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestScaffold(t *testing.T) { 14 | 15 | tempDir, err := ioutil.TempDir(filepath.Join(Gopath, "src"), "test") 16 | 17 | if !filepath.IsAbs(tempDir) { 18 | tempDir, err = filepath.Abs(tempDir) 19 | assert.NoError(t, err) 20 | } 21 | 22 | fmt.Printf("tempDir:%s\n", tempDir) 23 | assert.NoError(t, New(true).Generate(tempDir)) 24 | 25 | defer os.RemoveAll(tempDir) // clean up 26 | } 27 | -------------------------------------------------------------------------------- /static/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run 2 | run: 3 | go run cmd/main.go 4 | 5 | .PHONY: up 6 | up: 7 | docker-compose up -d 8 | 9 | .PHONY: down 10 | down: 11 | docker-compose down -------------------------------------------------------------------------------- /static/config/config.yml: -------------------------------------------------------------------------------- 1 | http: 2 | listenAddr: ":8080" 3 | 4 | release: 5 | releaseVersion: "@RELEASE_VERSION@" 6 | releaseTime: "@RELEASE_TIME@" 7 | 8 | 9 | database: 10 | url: root:root@tcp(db:3306)/?charset=utf8&parseTime=true 11 | maxIdle: 50 12 | maxActive: 100 13 | logMode: true 14 | -------------------------------------------------------------------------------- /template/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | #build stage 3 | FROM golang:alpine AS builder 4 | WORKDIR /go/src/{{.ProjectPath}} 5 | COPY . . 6 | RUN apk add --no-cache git 7 | RUN go get ./... 8 | RUN go build -o {{.ProjectName}} ./cmd/main.go 9 | 10 | #final stage 11 | FROM alpine:latest 12 | RUN apk --no-cache add ca-certificates 13 | RUN apk add --no-cache bash 14 | COPY --from=builder /go/src/{{.ProjectPath}}/{{.ProjectName}} /{{.ProjectName}} 15 | COPY --from=builder /go/src/{{.ProjectPath}}/config/config.yml /config.yml 16 | 17 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh ./wait-for-it.sh 18 | RUN ["chmod", "+x", "./wait-for-it.sh"] 19 | LABEL Name={{.ProjectName}} 20 | EXPOSE 8080 21 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # {{.ProjectName}} 2 | 3 | ## Run service by using: 4 | ```sh 5 | $ make run 6 | ``` -------------------------------------------------------------------------------- /template/cmd/main.tmpl: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "{{.ProjectPath}}/config" 5 | "{{.ProjectPath}}/model" 6 | "{{.ProjectPath}}/web" 7 | 8 | "log" 9 | "os" 10 | "os/signal" 11 | ) 12 | 13 | func main() { 14 | cfg, err := config.New() 15 | if err != nil { 16 | log.Fatalf("Failed to reading config file, %s\n", err) 17 | } 18 | 19 | service, err := model.New(cfg.Database) 20 | if err != nil { 21 | log.Fatalf("Failed to initialize model for operating all service, %s\n", err) 22 | } 23 | 24 | server := web.NewServer(cfg, service) 25 | go func() { 26 | if err := server.ListenAndServe(); err != nil { 27 | log.Fatalf("Failed to listen for http server, %s\n", err) 28 | } 29 | }() 30 | 31 | quit := make(chan os.Signal) 32 | signal.Notify(quit, os.Interrupt) 33 | 34 | log.Println("{{.ProjectName}} is running") 35 | {{.Quit | unescaped}} 36 | log.Println("{{.ProjectName}} is stopped") 37 | } 38 | -------------------------------------------------------------------------------- /template/config/config.tmpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/spf13/viper" 4 | 5 | // Config stores configuration variables. 6 | type Config struct { 7 | Database *Database 8 | HTTP *HTTP 9 | Release *Release 10 | } 11 | 12 | // New returns a new config instance. 13 | func New() (*Config, error) { 14 | cfg := &Config{} 15 | 16 | viper.New() 17 | viper.SetConfigType("yml") 18 | viper.SetConfigName("config") 19 | viper.AddConfigPath("$GOPATH/src/{{.ProjectPath}}/config/.") 20 | viper.AddConfigPath("./") 21 | 22 | if err := viper.ReadInConfig(); err != nil { 23 | return nil, err 24 | } 25 | 26 | if err := viper.Unmarshal(cfg); err != nil { 27 | return nil, err 28 | } 29 | return cfg, nil 30 | } 31 | -------------------------------------------------------------------------------- /template/config/database.tmpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // Database is the postgres configuration. 4 | type Database struct { 5 | URL string 6 | MaxIdle int 7 | MaxActive int 8 | LogMode bool 9 | } 10 | -------------------------------------------------------------------------------- /template/config/http.tmpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // HTTP is the configuration of http server. 4 | type HTTP struct { 5 | ListenAddr string 6 | } 7 | -------------------------------------------------------------------------------- /template/config/release.tmpl: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // Release is the Release configuration of pluto bi server. 4 | type Release struct { 5 | ReleaseVersion string 6 | ReleaseTime string 7 | } 8 | -------------------------------------------------------------------------------- /template/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | api: 5 | build: . 6 | image: {{.ProjectName}} 7 | ports: 8 | - 8080:8080 9 | depends_on: 10 | - db 11 | command: ["./wait-for-it.sh","db:3306", "--","./{{.ProjectName}}"] 12 | db: 13 | image: 'mysql' 14 | command: --default-authentication-plugin=mysql_native_password 15 | restart: always 16 | ports: 17 | - 3306:3306 18 | environment: 19 | - MYSQL_ROOT_PASSWORD=root 20 | -------------------------------------------------------------------------------- /template/model/model.tmpl: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "{{.ProjectPath}}/config" 5 | 6 | "github.com/jinzhu/gorm" 7 | "github.com/pkg/errors" 8 | 9 | _ "github.com/jinzhu/gorm/dialects/mysql" //mysql dialects 10 | ) 11 | 12 | // Service is the interface of all model service. 13 | type Service interface { 14 | } 15 | 16 | type service struct { 17 | } 18 | 19 | // New returns a Service instance for operating all model service. 20 | func New(dbCfg *config.Database) (Service, error) { 21 | _, err := newDB(dbCfg) //needs to pass db as 22 | if err != nil { 23 | return nil, errors.Wrap(err, "Failed to initialize db of grom") 24 | } 25 | 26 | serv := &service{} 27 | return serv, nil 28 | } 29 | 30 | func newDB(dbCfg *config.Database) (*gorm.DB, error) { 31 | db, err := gorm.Open("mysql", dbCfg.URL) 32 | if err != nil { 33 | return nil, errors.Wrap(err, "Failed to open db URL") 34 | } 35 | db.DB().SetMaxOpenConns(dbCfg.MaxActive) 36 | db.DB().SetMaxIdleConns(dbCfg.MaxIdle) 37 | 38 | db.LogMode(dbCfg.LogMode) 39 | return db, nil 40 | } 41 | -------------------------------------------------------------------------------- /template/web/routes.tmpl: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import "net/http" 4 | 5 | func (srv *server) routes() http.Handler { 6 | srv.router.GET("{{.ProjectName}}/version", srv.Version) 7 | 8 | //Declare web routing table at here. 9 | return srv.router 10 | } 11 | -------------------------------------------------------------------------------- /template/web/server.tmpl: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "{{.ProjectPath}}/config" 5 | "{{.ProjectPath}}/model" 6 | "net/http" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | type server struct { 12 | config *config.Config 13 | router *gin.Engine 14 | service model.Service 15 | } 16 | 17 | // NewServer returns new http.Server. 18 | func NewServer(cfg *config.Config, service model.Service) *http.Server { 19 | gin.SetMode(gin.ReleaseMode) 20 | srv := &server{ 21 | config: cfg, 22 | router: gin.Default(), 23 | service: service, 24 | } 25 | 26 | return &http.Server{ 27 | Addr: cfg.HTTP.ListenAddr, 28 | Handler: srv.routes(), 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /template/web/version.tmpl: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | func (srv *server) Version(c *gin.Context) { 8 | c.Writer.Header().Set("Content-Type", "application/json; charset=utf-8") 9 | c.JSON(200, &vesionOut{ 10 | Code: "0", 11 | Message: "OK", 12 | ReleaseTime: srv.config.Release.ReleaseTime, 13 | ReleaseVersion: srv.config.Release.ReleaseVersion, 14 | }, 15 | ) 16 | } 17 | 18 | type vesionOut struct { 19 | Code string `json:"code"` 20 | ReleaseTime string `json:"releaseTime"` 21 | ReleaseVersion string `json:"releaseVersion"` 22 | Message string `json:"message"` 23 | } 24 | --------------------------------------------------------------------------------