feat(template): Refactor template standard variable and implement dockerfile
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Matthieu 'JP' DERASSE 2022-09-29 20:04:37 +00:00
parent edbd97705a
commit ac7df8be2d
Signed by: mderasse
GPG Key ID: 55141C777B16A705
16 changed files with 191 additions and 98 deletions

View File

@ -5,20 +5,43 @@ Copyright © 2022 Matthieu Derasse <git@derasse.fr>
package cmd package cmd
import ( import (
"fmt" "git.home.m-and-m.ovh/mderasse/gouick/helpers/api_types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
log "github.com/sirupsen/logrus"
) )
// dockerCmd represents the docker command. // dockerCmd represents the docker command.
var dockerCmd = &cobra.Command{ var dockerCmd = &cobra.Command{
Use: "docker", Use: "docker",
Short: "Generate Dockerfile for API & Workers", Short: "Generate Dockerfile & co for API, Crons and Workers",
Run: func(cmd *cobra.Command, args []string) { Run: runGenerateDockerAction,
fmt.Println("docker called")
},
} }
func init() { func init() {
generateCmd.AddCommand(dockerCmd) generateCmd.AddCommand(dockerCmd)
} }
// runGenerateDockerAction will generate the Dockerfile & co for the current project.
func runGenerateDockerAction(cmd *cobra.Command, args []string) {
log.Debugf("Starting command GenerateDocker")
currentPath, config, err := loadProjectAndConfig()
if err != nil {
return
}
apiType, err := api_types.GetAPIType(config.ProjectType)
if err != nil {
log.Error("Impossible to load that API Type generator")
return
}
// Generate Dockerfile
log.Info("Generating Dockerfile")
err = apiType.GenerateDockerfile(currentPath, config)
if err != nil {
log.Errorf("Fail to generate Dockerfile. The following error happen: %s", err.Error())
return
}
}

View File

@ -131,13 +131,13 @@ func runInitAction(cmd *cobra.Command, args []string) {
// ask project contact // ask project contact
config.ProjectContact = models.ProjectContactStruct{} config.ProjectContact = models.ProjectContactStruct{}
log.Info("Mail address of the developer team:")
config.ProjectContact.Email = input.Mail(true)
log.Info("Name of the team:") log.Info("Name of the team:")
config.ProjectContact.Name = input.String(true) config.ProjectContact.Name = input.String(true)
log.Info("URL of the contact informatino of the team:") log.Info("Mail address of the developer team:")
config.ProjectContact.Email = input.Mail(true)
log.Info("URL of the contact information of the team:")
config.ProjectContact.URL = input.String(false) config.ProjectContact.URL = input.String(false)
// launch GetInitializeUserInput from selected api type // launch GetInitializeUserInput from selected api type
@ -193,6 +193,14 @@ func runInitAction(cmd *cobra.Command, args []string) {
return return
} }
// Create API Skeleton
log.Info("Creating API skeleton")
err = apiType.CreateProjectSkeleton(projectDirPath, config)
if err != nil {
log.Errorf("Fail to create the project skeleton. The following error happen: %s", err.Error())
return
}
// Generate Makefile // Generate Makefile
log.Info("Generating Makefile") log.Info("Generating Makefile")
err = apiType.GenerateMakefile(projectDirPath, config) err = apiType.GenerateMakefile(projectDirPath, config)
@ -209,11 +217,11 @@ func runInitAction(cmd *cobra.Command, args []string) {
return return
} }
// Create API Skeleton // Generate Launcher
log.Info("Creating API skeleton") log.Info("Generating Launcher")
err = apiType.CreateProjectSkeleton(projectDirPath, config) err = apiType.GenerateLauncher(projectDirPath, config)
if err != nil { if err != nil {
log.Errorf("Fail to create the project skeleton. The following error happen: %s", err.Error()) log.Errorf("Fail to generate launcher.sh. The following error happen: %s", err.Error())
return return
} }
} }

1
go.mod
View File

@ -5,7 +5,6 @@ go 1.17
require ( require (
github.com/blang/semver v3.5.1+incompatible github.com/blang/semver v3.5.1+incompatible
github.com/go-swagger/go-swagger v0.29.0 github.com/go-swagger/go-swagger v0.29.0
github.com/iancoleman/strcase v0.2.0
github.com/jessevdk/go-flags v1.5.0 github.com/jessevdk/go-flags v1.5.0
github.com/juju/errors v1.0.0 github.com/juju/errors v1.0.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1

1
go.sum
View File

@ -400,7 +400,6 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=

View File

@ -0,0 +1,13 @@
package base
import (
"github.com/juju/errors"
"git.home.m-and-m.ovh/mderasse/gouick/helpers"
"git.home.m-and-m.ovh/mderasse/gouick/models"
)
// GenerateDockerfile will generate dockerfile based on the given config.
func (a APIType) GenerateDockerfile(path string, config *models.Config) error {
return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName())
}

View File

@ -0,0 +1,47 @@
package go_swagger
import (
"github.com/juju/errors"
"git.home.m-and-m.ovh/mderasse/gouick/models"
log "github.com/sirupsen/logrus"
)
type stdTemplateStruct struct {
categorizedProcess
Config *models.Config
}
type categorizedProcess struct {
APIs []*models.Process
Crons []*models.Process
Workers []*models.Process
}
// getStdTemplate will generate the "basic" struct we will provide to a template.
func (a APIType) getStdTemplate(path string, config *models.Config) (*stdTemplateStruct, error) {
data := stdTemplateStruct{
Config: config,
}
processes, err := a.getProcesses(path)
if err != nil {
log.Error("Fail to list processes")
return nil, errors.Trace(err)
}
for _, process := range processes {
switch process.Type {
case models.ProcessType_API:
data.APIs = append(data.APIs, process)
case models.ProcessType_CRON:
data.Crons = append(data.Crons, process)
case models.ProcessType_WORKER:
data.Workers = append(data.Workers, process)
}
}
return &data, nil
}

View File

@ -0,0 +1,33 @@
package go_swagger
import (
"path/filepath"
"github.com/juju/errors"
"git.home.m-and-m.ovh/mderasse/gouick/helpers"
"git.home.m-and-m.ovh/mderasse/gouick/models"
log "github.com/sirupsen/logrus"
)
// GenerateDockerfile will generate a Dockerfile based on the given config.
func (a APIType) GenerateDockerfile(path string, config *models.Config) error {
log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName())
templatePath := filepath.Join(templateDirectory, "Dockerfile.tmpl")
savePath := filepath.Join(path, "Dockerfile")
data, err := a.getStdTemplate(path, config)
if err != nil {
log.Error("Fail to generate standard template variable")
return errors.Trace(err)
}
err = helpers.WriteTemplate(templatePath, savePath, data)
if err != nil {
return errors.Trace(err)
}
return nil
}

View File

@ -11,12 +11,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type launcherTemplate struct {
APIs []*models.Process
Crons []*models.Process
Workers []*models.Process
}
// GenerateLauncher will generate a launcher.sh based on the files found in cmd directory. // GenerateLauncher will generate a launcher.sh based on the files found in cmd directory.
func (a APIType) GenerateLauncher(path string, config *models.Config) error { func (a APIType) GenerateLauncher(path string, config *models.Config) error {
log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName())
@ -24,25 +18,12 @@ func (a APIType) GenerateLauncher(path string, config *models.Config) error {
templatePath := filepath.Join(templateDirectory, "launcher.sh.tmpl") templatePath := filepath.Join(templateDirectory, "launcher.sh.tmpl")
savePath := filepath.Join(path, "launcher.sh") savePath := filepath.Join(path, "launcher.sh")
data := launcherTemplate{} data, err := a.getStdTemplate(path, config)
processes, err := a.getProcesses(path)
if err != nil { if err != nil {
log.Error("Fail to list processes") log.Error("Fail to generate standard template variable")
return errors.Trace(err) return errors.Trace(err)
} }
for _, process := range processes {
switch process.Type {
case models.ProcessType_API:
data.APIs = append(data.APIs, process)
case models.ProcessType_CRON:
data.Crons = append(data.Crons, process)
case models.ProcessType_WORKER:
data.Workers = append(data.Workers, process)
}
}
err = helpers.WriteTemplate(templatePath, savePath, data) err = helpers.WriteTemplate(templatePath, savePath, data)
if err != nil { if err != nil {
return errors.Trace(err) return errors.Trace(err)

View File

@ -11,12 +11,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type makefileTemplate struct {
APIs []*models.Process
Crons []*models.Process
Workers []*models.Process
}
// GenerateMakefile will generate makefile based on the given config. // GenerateMakefile will generate makefile based on the given config.
// Launched only at project init or on force. // Launched only at project init or on force.
func (a APIType) GenerateMakefile(path string, config *models.Config) error { func (a APIType) GenerateMakefile(path string, config *models.Config) error {
@ -25,25 +19,12 @@ func (a APIType) GenerateMakefile(path string, config *models.Config) error {
templatePath := filepath.Join(templateDirectory, "Makefile.tmpl") templatePath := filepath.Join(templateDirectory, "Makefile.tmpl")
savePath := filepath.Join(path, "Makefile") savePath := filepath.Join(path, "Makefile")
data := makefileTemplate{} data, err := a.getStdTemplate(path, config)
processes, err := a.getProcesses(path)
if err != nil { if err != nil {
log.Error("Fail to list processes") log.Error("Fail to generate standard template variable")
return errors.Trace(err) return errors.Trace(err)
} }
for _, process := range processes {
switch process.Type {
case models.ProcessType_API:
data.APIs = append(data.APIs, process)
case models.ProcessType_CRON:
data.Crons = append(data.Crons, process)
case models.ProcessType_WORKER:
data.Workers = append(data.Workers, process)
}
}
err = helpers.WriteTemplate(templatePath, savePath, data) err = helpers.WriteTemplate(templatePath, savePath, data)
if err != nil { if err != nil {
return errors.Trace(err) return errors.Trace(err)

View File

@ -11,11 +11,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type readmeTemplate struct {
ProjectDescription string
ProjectName string
}
// GenerateReadme will generate a readme based on the given config. // GenerateReadme will generate a readme based on the given config.
// Launched only at project init. // Launched only at project init.
func (a APIType) GenerateReadme(path string, config *models.Config) error { func (a APIType) GenerateReadme(path string, config *models.Config) error {
@ -24,12 +19,13 @@ func (a APIType) GenerateReadme(path string, config *models.Config) error {
templatePath := filepath.Join(templateDirectory, "Readme.md.tmpl") templatePath := filepath.Join(templateDirectory, "Readme.md.tmpl")
savePath := filepath.Join(path, "Readme.md") savePath := filepath.Join(path, "Readme.md")
data := readmeTemplate{ data, err := a.getStdTemplate(path, config)
ProjectDescription: config.ProjectDescription, if err != nil {
ProjectName: config.ProjectName, log.Error("Fail to generate standard template variable")
return errors.Trace(err)
} }
err := helpers.WriteTemplate(templatePath, savePath, data) err = helpers.WriteTemplate(templatePath, savePath, data)
if err != nil { if err != nil {
return errors.Trace(err) return errors.Trace(err)
} }

View File

@ -90,7 +90,10 @@ func (a APIType) goSwaggerGenerate(path string) error {
Server: &generate.Server{}, Server: &generate.Server{},
} }
generateCmd.Server.Shared.Spec = flags.Filename(filepath.Join(path, mergeYamlFileName)) generateCmd.Server.Shared.Spec = flags.Filename(filepath.Join(path, mergeYamlFileName))
generateCmd.Server.Shared.Target = flags.Filename(path) //generateCmd.Server.Shared.Target = flags.Filename(path)
generateCmd.Server.ServerPackage = "restapi"
generateCmd.Server.Models.ModelPackage = "models"
generateCmd.Server.Operations.APIPackage = "operations"
generateCmd.Server.Shared.StrictResponders = true generateCmd.Server.Shared.StrictResponders = true
return generateCmd.Server.Execute(nil) return generateCmd.Server.Execute(nil)

View File

@ -12,18 +12,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type apiYamlTemplate struct {
ProjectDescription string
ProjectName string
ProjectContact apiYamlContact
}
type apiYamlContact struct {
Email string
Name string
URL string
}
// createDefaultAPIYamls will generate the main api yaml file based on the given config. // createDefaultAPIYamls will generate the main api yaml file based on the given config.
// Launched only at project init. // Launched only at project init.
func (a APIType) createDefaultAPIYamls(path string, config *models.Config) error { func (a APIType) createDefaultAPIYamls(path string, config *models.Config) error {
@ -49,14 +37,10 @@ func (a APIType) createDefaultAPIYamls(path string, config *models.Config) error
}, },
} }
data := apiYamlTemplate{ data, err := a.getStdTemplate(path, config)
ProjectDescription: config.ProjectDescription, if err != nil {
ProjectName: config.ProjectName, log.Error("Fail to generate standard template variable")
ProjectContact: apiYamlContact{ return errors.Trace(err)
Email: config.ProjectContact.Email,
Name: config.ProjectContact.Name,
URL: config.ProjectContact.URL,
},
} }
for _, templateFile := range templateFileList { for _, templateFile := range templateFileList {

View File

@ -6,6 +6,7 @@ import "git.home.m-and-m.ovh/mderasse/gouick/models"
type APITypeInterface interface { type APITypeInterface interface {
CheckInitialize() error CheckInitialize() error
CreateProjectSkeleton(path string, config *models.Config) error CreateProjectSkeleton(path string, config *models.Config) error
GenerateDockerfile(path string, config *models.Config) error
GenerateLauncher(path string, config *models.Config) error GenerateLauncher(path string, config *models.Config) error
GenerateMakefile(path string, config *models.Config) error GenerateMakefile(path string, config *models.Config) error
GenerateReadme(path string, config *models.Config) error GenerateReadme(path string, config *models.Config) error

View File

@ -0,0 +1,25 @@
# Code generated by gouick; DO NOT EDIT.
FROM alpine
LABEL maintainer="{{.Config.ProjectContact.Name}} <{{.Config.ProjectContact.Email}}>"
RUN apk add --no-cache ca-certificates
USER nobody
COPY launcher.sh \
{{- range .APIs }}
{{.Binary}} \
{{- end }}
{{- range .Crons }}
{{.Binary}} \
{{- end }}
{{- range .Workers }}
{{.Binary}} \
{{- end }}
/app/
# expose port 8080
EXPOSE 8080
CMD [ "/app/launcher.sh" ]

View File

@ -1,3 +1,3 @@
# {{ .ProjectName }} # {{ .Config.ProjectName }}
{{ .ProjectDescription }} {{ .Config.ProjectDescription }}

View File

@ -2,16 +2,16 @@
swagger: "2.0" swagger: "2.0"
info: info:
version: "1.0" version: "1.0"
title: "{{ .ProjectName }}" title: "{{ .Config.ProjectName }}"
description: "{{ .ProjectDescription }}" description: "{{ .Config.ProjectDescription }}"
contact: contact:
name: "{{ .ProjectContact.Name }}" name: "{{ .Config.ProjectContact.Name }}"
email: "{{ .ProjectContact.Email }}" email: "{{ .Config.ProjectContact.Email }}"
{{if .ProjectContact.URL }} {{- if .Config.ProjectContact.URL }}
url: "{{ .ProjectContact.URL }}" url: "{{ .Config.ProjectContact.URL }}"
{{end}} {{- end }}
consumes: consumes:
- "application/json" - "application/json"
produces: produces:
- "application/json" - "application/json"
basePath: "/" basePath: "/"