diff --git a/cmd/init.go b/cmd/init.go index 430ac85..d43a041 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -124,7 +124,7 @@ func runInitAction(cmd *cobra.Command, args []string) { // ask project name log.Info("Name of the project:") - config.ProjectName = helpers.StringInput() + config.ProjectName = helpers.AlphanumericalAndSpaceInput() // ask project description log.Info("Description of the project:") @@ -188,4 +188,9 @@ func runInitAction(cmd *cobra.Command, args []string) { } 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 + } } diff --git a/go.mod b/go.mod index f0a0655..fb1c262 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/blang/semver v3.5.1+incompatible + github.com/iancoleman/strcase v0.2.0 github.com/juju/errors v1.0.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 diff --git a/go.sum b/go.sum index 6f9842f..2151f5b 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM= diff --git a/helpers/api_types/base/create_project_skeleton.go b/helpers/api_types/base/create_project_skeleton.go new file mode 100644 index 0000000..03ec2b6 --- /dev/null +++ b/helpers/api_types/base/create_project_skeleton.go @@ -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" +) + +// CreateProjectSkeleton will generate all the files needed to start a new project. +func (a APIType) CreateProjectSkeleton(path string, config *models.Config) error { + return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName()) +} diff --git a/helpers/api_types/base/generate_makefile.go b/helpers/api_types/base/generate_makefile.go new file mode 100644 index 0000000..1e17c5e --- /dev/null +++ b/helpers/api_types/base/generate_makefile.go @@ -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" +) + +// GenerateMakefile will generate makefile based on the given config. +func (a APIType) GenerateMakefile(path string, config *models.Config) error { + return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName()) +} diff --git a/helpers/api_types/go_swagger/constants.go b/helpers/api_types/go_swagger/constants.go new file mode 100644 index 0000000..4e6d2b7 --- /dev/null +++ b/helpers/api_types/go_swagger/constants.go @@ -0,0 +1,4 @@ +package go_swagger + +// templateDirectory contain the path to the templates for that apiType. +const templateDirectory = "templates/go-swagger" diff --git a/helpers/api_types/go_swagger/create_directories.go b/helpers/api_types/go_swagger/create_directories.go new file mode 100644 index 0000000..0221a11 --- /dev/null +++ b/helpers/api_types/go_swagger/create_directories.go @@ -0,0 +1,44 @@ +package go_swagger + +import ( + "path/filepath" + + "github.com/juju/errors" + + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + + log "github.com/sirupsen/logrus" +) + +var standardDirectories = []string{ + "api", + "chart", + "cmd", + "models", + "pkg", + "restapi", + "testdata", +} + +// createDirectories will create all skeleton directories for the project. +func (a APIType) createDirectories(path string) error { + log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) + + for _, directory := range standardDirectories { + + log.Debugf("Will create directory %s", directory) + + fullPath := filepath.Join(path, directory) + + created, err := helpers.CheckAndCreateDir(fullPath) + if err != nil { + log.Errorf("Failed to create directory %s", directory) + return errors.Trace(err) + } + if !created { + log.Debugf("Skipping directory %s", directory) + } + } + + return nil +} diff --git a/helpers/api_types/go_swagger/create_project_skeleton.go b/helpers/api_types/go_swagger/create_project_skeleton.go index 970dd96..c84c8a1 100644 --- a/helpers/api_types/go_swagger/create_project_skeleton.go +++ b/helpers/api_types/go_swagger/create_project_skeleton.go @@ -1,13 +1,32 @@ package go_swagger import ( + "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" ) // CreateProjectSkeleton will generate all the files needed to start a new project. -// it will return a list of created files or an error -func (a APIType) CreateProjectSkeleton(path string) ([]string, error) { - log.Debugf("Starting %s create project skeleton", string(a.GetName())) +func (a APIType) CreateProjectSkeleton(path string, config *models.Config) error { + log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) - return nil, nil + err := a.createDirectories(path) + if err != nil { + log.Error("Fail to create project directories") + return errors.Trace(err) + } + + // Generate Makefile + err = a.GenerateMakefile(path, config) + if err != nil { + log.Error("Fail to generate Makefile") + return errors.Trace(err) + } + // Generate Readme + // Generate api.yaml + + return nil } diff --git a/helpers/api_types/go_swagger/generate_makefile.go b/helpers/api_types/go_swagger/generate_makefile.go new file mode 100644 index 0000000..7f30335 --- /dev/null +++ b/helpers/api_types/go_swagger/generate_makefile.go @@ -0,0 +1,36 @@ +package go_swagger + +import ( + "path/filepath" + + "github.com/iancoleman/strcase" + "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" +) + +type makefile struct { + AppNameKebabCase string +} + +// GenerateMakefile will generate makefile based on the given config. +func (a APIType) GenerateMakefile(path string, config *models.Config) error { + log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) + + templatePath := filepath.Join(templateDirectory, "Makefile.tmpl") + savePath := filepath.Join(path, "Makefile") + + data := makefile{ + AppNameKebabCase: strcase.ToKebab(config.ProjectName), + } + + err := helpers.WriteTemplate(templatePath, savePath, data) + if err != nil { + return errors.Trace(err) + } + + return nil +} diff --git a/helpers/api_types/interface.go b/helpers/api_types/interface.go index f0305e6..0244773 100644 --- a/helpers/api_types/interface.go +++ b/helpers/api_types/interface.go @@ -5,6 +5,8 @@ import "git.home.m-and-m.ovh/mderasse/gouick/models" // APITypeInterface is the interface that need to be respected by an APIType. type APITypeInterface interface { CheckInitialize() error - GetName() models.APITypeName + CreateProjectSkeleton(path string, config *models.Config) error + GenerateMakefile(path string, config *models.Config) error GetInitializeUserInput(params *models.Config) (*models.Config, error) + GetName() models.APITypeName } diff --git a/helpers/file.go b/helpers/file.go index 32c90b2..9ad10ba 100644 --- a/helpers/file.go +++ b/helpers/file.go @@ -3,6 +3,7 @@ package helpers import ( "io/fs" "os" + "path" "path/filepath" "github.com/juju/errors" @@ -136,3 +137,12 @@ func RemoveDirectoryContent(path string) error { return nil } + +// GetExecutableDirectory will return the directory of Gouick. +func GetExecutableDirectory() (string, error) { + e, err := os.Executable() + if err != nil { + return "", errors.Trace(err) + } + return path.Dir(e), nil +} diff --git a/helpers/template.go b/helpers/template.go new file mode 100644 index 0000000..6666d25 --- /dev/null +++ b/helpers/template.go @@ -0,0 +1,50 @@ +package helpers + +import ( + "os" + "path/filepath" + "text/template" + + "github.com/juju/errors" + + log "github.com/sirupsen/logrus" +) + +// WriteTemplate will parse the given template filepath, and write the result to the savePath. +func WriteTemplate(templatePath string, savePath string, data interface{}) error { + + execDirectory, err := GetExecutableDirectory() + if err != nil { + log.Error("Fail to get Gouick directory") + return errors.Trace(err) + } + + templatePath = filepath.Join(execDirectory, templatePath) + + template, err := template.ParseFiles(templatePath) + if err != nil { + log.Errorf("Fail to parse the template %s", templatePath) + return errors.Trace(err) + } + + //nolint: gosec // We compute the savePath + fh, err := os.Create(savePath) + if err != nil { + log.Errorf("Fail to create saving path %s", savePath) + return errors.Trace(err) + } + + defer func() { + if err := fh.Close(); err != nil { + log.Errorf("Error closing file: %s", err) + } + }() + + err = template.Execute(fh, data) + if err != nil { + log.Errorf("Fail to write compute the template content for %s", savePath) + return errors.Trace(err) + } + + return nil +} diff --git a/templates/go-swagger/Makefile.go.tmpl b/templates/go-swagger/Makefile.tmpl similarity index 92% rename from templates/go-swagger/Makefile.go.tmpl rename to templates/go-swagger/Makefile.tmpl index 45a1a5c..7e64aa8 100644 --- a/templates/go-swagger/Makefile.go.tmpl +++ b/templates/go-swagger/Makefile.tmpl @@ -8,4 +8,4 @@ generate: gouick generate launch: - @$(CMD) \ No newline at end of file + @$(CMD)