Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: define interfaces for file and project generation #1568

Merged
merged 10 commits into from
Sep 1, 2023
8 changes: 4 additions & 4 deletions modulegen/cmd/modules/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ var newExampleCmd = &cobra.Command{
Short: "Create a new Example",
Long: "Create a new Example",
RunE: func(cmd *cobra.Command, args []string) error {
return internal.Generate(*exampleVar, false)
return internal.Generate(tcModuleVar, false)
},
}

func init() {
newExampleCmd.Flags().StringVarP(&exampleVar.Name, nameFlag, "n", "", "Name of the example. Only alphabetical characters are allowed.")
newExampleCmd.Flags().StringVarP(&exampleVar.NameTitle, titleFlag, "t", "", "(Optional) Title of the example name, used to override the name in the case of mixed casing (Mongodb -> MongoDB). Use camel-case when needed. Only alphabetical characters are allowed.")
newExampleCmd.Flags().StringVarP(&exampleVar.Image, imageFlag, "i", "", "Fully-qualified name of the Docker image to be used by the example")
newExampleCmd.Flags().StringVarP(&tcModuleVar.Name, nameFlag, "n", "", "Name of the example. Only alphabetical characters are allowed.")
newExampleCmd.Flags().StringVarP(&tcModuleVar.NameTitle, titleFlag, "t", "", "(Optional) Title of the example name, used to override the name in the case of mixed casing (Mongodb -> MongoDB). Use camel-case when needed. Only alphabetical characters are allowed.")
newExampleCmd.Flags().StringVarP(&tcModuleVar.Image, imageFlag, "i", "", "Fully-qualified name of the Docker image to be used by the example")

_ = newExampleCmd.MarkFlagRequired(imageFlag)
_ = newExampleCmd.MarkFlagRequired(nameFlag)
Expand Down
2 changes: 1 addition & 1 deletion modulegen/cmd/modules/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/testcontainers/testcontainers-go/modulegen/internal/context"
)

var exampleVar = &context.ExampleVar{}
var tcModuleVar = context.TestcontainersModuleVar{}

var NewCmd = &cobra.Command{
Use: "new",
Expand Down
8 changes: 4 additions & 4 deletions modulegen/cmd/modules/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ var newModuleCmd = &cobra.Command{
Short: "Create a new Module",
Long: "Create a new Module",
RunE: func(cmd *cobra.Command, args []string) error {
return internal.Generate(*exampleVar, true)
return internal.Generate(tcModuleVar, true)
},
}

func init() {
newModuleCmd.Flags().StringVarP(&exampleVar.Name, nameFlag, "n", "", "Name of the module. Only alphabetical characters are allowed.")
newModuleCmd.Flags().StringVarP(&exampleVar.NameTitle, titleFlag, "t", "", "(Optional) Title of the module name, used to override the name in the case of mixed casing (Mongodb -> MongoDB). Use camel-case when needed. Only alphabetical characters are allowed.")
newModuleCmd.Flags().StringVarP(&exampleVar.Image, imageFlag, "i", "", "Fully-qualified name of the Docker image to be used by the module")
newModuleCmd.Flags().StringVarP(&tcModuleVar.Name, nameFlag, "n", "", "Name of the module. Only alphabetical characters are allowed.")
newModuleCmd.Flags().StringVarP(&tcModuleVar.NameTitle, titleFlag, "t", "", "(Optional) Title of the module name, used to override the name in the case of mixed casing (Mongodb -> MongoDB). Use camel-case when needed. Only alphabetical characters are allowed.")
newModuleCmd.Flags().StringVarP(&tcModuleVar.Image, imageFlag, "i", "", "Fully-qualified name of the Docker image to be used by the module")

_ = newModuleCmd.MarkFlagRequired(imageFlag)
_ = newModuleCmd.MarkFlagRequired(nameFlag)
Expand Down
2 changes: 1 addition & 1 deletion modulegen/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func TestModulesHasDependabotEntry(t *testing.T) {
}
}

func getTestRootContext(t *testing.T) *context.Context {
func getTestRootContext(t *testing.T) context.Context {
current, err := os.Getwd()
require.NoError(t, err)
return context.New(filepath.Dir(current))
Expand Down
2 changes: 1 addition & 1 deletion modulegen/internal/context/cmd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package context

type ExampleVar struct {
type TestcontainersModuleVar struct {
Name string
NameTitle string
Image string
Expand Down
34 changes: 17 additions & 17 deletions modulegen/internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ type Context struct {
RootDir string
}

func (ctx *Context) DependabotConfigFile() string {
func (ctx Context) DependabotConfigFile() string {
return filepath.Join(ctx.GithubDir(), "dependabot.yml")
}

func (ctx *Context) DocsDir() string {
func (ctx Context) DocsDir() string {
return filepath.Join(ctx.RootDir, "docs")
}

func (ctx *Context) GithubDir() string {
func (ctx Context) GithubDir() string {
return filepath.Join(ctx.RootDir, ".github")
}

func (ctx *Context) GithubWorkflowsDir() string {
func (ctx Context) GithubWorkflowsDir() string {
return filepath.Join(ctx.GithubDir(), "workflows")
}

func (ctx *Context) GoModFile() string {
func (ctx Context) GoModFile() string {
return filepath.Join(ctx.RootDir, "go.mod")
}

func (ctx *Context) getModulesByBaseDir(baseDir string) ([]string, error) {
func (ctx Context) getModulesByBaseDir(baseDir string) ([]string, error) {
dir := filepath.Join(ctx.RootDir, baseDir)

allFiles, err := os.ReadDir(dir)
Expand All @@ -49,7 +49,7 @@ func (ctx *Context) getModulesByBaseDir(baseDir string) ([]string, error) {
return dirs, nil
}

func (ctx *Context) getMarkdownsFromDir(baseDir string) ([]string, error) {
func (ctx Context) getMarkdownsFromDir(baseDir string) ([]string, error) {
dir := filepath.Join(ctx.DocsDir(), baseDir)

allFiles, err := os.ReadDir(dir)
Expand All @@ -68,38 +68,38 @@ func (ctx *Context) getMarkdownsFromDir(baseDir string) ([]string, error) {
return dirs, nil
}

func (ctx *Context) GetExamples() ([]string, error) {
func (ctx Context) GetExamples() ([]string, error) {
return ctx.getModulesByBaseDir("examples")
}

func (ctx *Context) GetModules() ([]string, error) {
func (ctx Context) GetModules() ([]string, error) {
return ctx.getModulesByBaseDir("modules")
}

func (ctx *Context) GetExamplesDocs() ([]string, error) {
func (ctx Context) GetExamplesDocs() ([]string, error) {
return ctx.getMarkdownsFromDir("examples")
}

func (ctx *Context) GetModulesDocs() ([]string, error) {
func (ctx Context) GetModulesDocs() ([]string, error) {
return ctx.getMarkdownsFromDir("modules")
}

func (ctx *Context) MkdocsConfigFile() string {
func (ctx Context) MkdocsConfigFile() string {
return filepath.Join(ctx.RootDir, "mkdocs.yml")
}

func (ctx *Context) VSCodeWorkspaceFile() string {
func (ctx Context) VSCodeWorkspaceFile() string {
return filepath.Join(ctx.RootDir, ".vscode", ".testcontainers-go.code-workspace")
}

func New(dir string) *Context {
return &Context{RootDir: dir}
func New(dir string) Context {
return Context{RootDir: dir}
}

func GetRootContext() (*Context, error) {
func GetRootContext() (Context, error) {
current, err := os.Getwd()
if err != nil {
return nil, err
return Context{}, err
mdelapenya marked this conversation as resolved.
Show resolved Hide resolved
}
return New(filepath.Dir(current)), nil
}
54 changes: 27 additions & 27 deletions modulegen/internal/context/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@ import (
"golang.org/x/text/language"
)

type Example struct {
type TestcontainersModule struct {
Image string // fully qualified name of the Docker image
IsModule bool // if true, the example will be generated as a Go module
IsModule bool // if true, the module will be generated as a Go module, otherwise an example
Name string
TitleName string // title of the name: e.g. "mongodb" -> "MongoDB"
TitleName string // title of the name: m.g. "mongodb" -> "MongoDB"
TCVersion string // Testcontainers for Go version
}

// ContainerName returns the name of the container, which is the lower-cased title of the example
// If the title is set, it will be used instead of the name
func (e *Example) ContainerName() string {
name := e.Lower()
func (m *TestcontainersModule) ContainerName() string {
name := m.Lower()

if e.IsModule {
name = e.Title()
if m.IsModule {
name = m.Title()
} else {
if e.TitleName != "" {
r, n := utf8.DecodeRuneInString(e.TitleName)
name = string(unicode.ToLower(r)) + e.TitleName[n:]
if m.TitleName != "" {
r, n := utf8.DecodeRuneInString(m.TitleName)
name = string(unicode.ToLower(r)) + m.TitleName[n:]
}
}

Expand All @@ -38,48 +38,48 @@ func (e *Example) ContainerName() string {

// Entrypoint returns the name of the entrypoint function, which is the lower-cased title of the example
// If the example is a module, the entrypoint will be "RunContainer"
func (e *Example) Entrypoint() string {
if e.IsModule {
func (m *TestcontainersModule) Entrypoint() string {
if m.IsModule {
return "RunContainer"
}

return "runContainer"
}

func (e *Example) Lower() string {
return strings.ToLower(e.Name)
func (m *TestcontainersModule) Lower() string {
return strings.ToLower(m.Name)
}

func (e *Example) ParentDir() string {
if e.IsModule {
func (m *TestcontainersModule) ParentDir() string {
if m.IsModule {
return "modules"
}

return "examples"
}

func (e *Example) Title() string {
if e.TitleName != "" {
return e.TitleName
func (m *TestcontainersModule) Title() string {
if m.TitleName != "" {
return m.TitleName
}

return cases.Title(language.Und, cases.NoLower).String(e.Lower())
return cases.Title(language.Und, cases.NoLower).String(m.Lower())
}

func (e *Example) Type() string {
if e.IsModule {
func (m *TestcontainersModule) Type() string {
if m.IsModule {
return "module"
}
return "example"
}

func (e *Example) Validate() error {
if !regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*$`).MatchString(e.Name) {
return fmt.Errorf("invalid name: %s. Only alphanumerical characters are allowed (leading character must be a letter)", e.Name)
func (m *TestcontainersModule) Validate() error {
if !regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*$`).MatchString(m.Name) {
return fmt.Errorf("invalid name: %s. Only alphanumerical characters are allowed (leading character must be a letter)", m.Name)
}

if !regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*$`).MatchString(e.TitleName) {
return fmt.Errorf("invalid title: %s. Only alphanumerical characters are allowed (leading character must be a letter)", e.TitleName)
if !regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*$`).MatchString(m.TitleName) {
return fmt.Errorf("invalid title: %s. Only alphanumerical characters are allowed (leading character must be a letter)", m.TitleName)
}

return nil
Expand Down
34 changes: 24 additions & 10 deletions modulegen/internal/dependabot/main.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
package dependabot

import (
"github.com/testcontainers/testcontainers-go/modulegen/internal/context"
)

// update examples in dependabot
func GenerateDependabotUpdates(ctx *context.Context, example context.Example) error {
directory := "/" + example.ParentDir() + "/" + example.Lower()
return UpdateConfig(ctx.DependabotConfigFile(), directory, "gomod")
}
import "github.com/testcontainers/testcontainers-go/modulegen/internal/context"

type Generator struct{}

// AddModule update dependabot with the new module
func (g Generator) AddModule(ctx context.Context, tcModule context.TestcontainersModule) error {
configFile := ctx.DependabotConfigFile()

func UpdateConfig(configFile string, directory string, packageEcosystem string) error {
config, err := readConfig(configFile)
if err != nil {
return err
}

packageEcosystem := "gomod"
directory := "/" + tcModule.ParentDir() + "/" + tcModule.Lower()

config.addUpdate(newUpdate(directory, packageEcosystem))

return writeConfig(configFile, config)
}

// Generate generates dependabot config file from source
func (g Generator) Generate(ctx context.Context) error {
configFile := ctx.DependabotConfigFile()

config, err := readConfig(configFile)
if err != nil {
return err
}

return writeConfig(configFile, config)
}

Expand Down
Loading