diff --git a/docs/examples/index.md b/docs/examples/index.md index 0021771a33..9ed15c13be 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -7,7 +7,7 @@ In this section you'll discover how to create code examples for _Testcontainers We have provided a command line tool to generate the scaffolding for the code of the example you are interested in. This tool will generate: - a Go module for the example, including: - - go.mod and go.sum files + - go.mod and go.sum files, including the current version of _Testcontainer for Go_. - a Go package named after the example, in lowercase - a Go file for the creation of the container, using a dedicated struct in which the image flag is set as Docker image. - a Go test file for running a simple test for your container, consuming the above struct. @@ -21,11 +21,12 @@ We have provided a command line tool to generate the scaffolding for the code of | Flag | Type | Required | Description | |------|------|----------|-------------| -| -name | string | Yes | Name of the example, use camel-case when needed | +| -name | string | Yes | Name of the example, use camel-case when needed. Only alphabetical characters are allowed. | | -image | string | Yes | Fully-qualified name of the Docker image to be used by the example (i.e. 'docker.io/org/project:tag') | ### What is this tool not doing? +- If the example name does not contain alphabeticall characters, it will exit the generation. - If the example already exists, it will exit without updating the existing files. ### How to run the tool @@ -33,5 +34,5 @@ We have provided a command line tool to generate the scaffolding for the code of From the [`examples` directory]({{repo_url}}/tree/main/examples), please run: ```shell -go run main.go --name ${NAME_OF_YOUR_EXAMPLE} --image "${REGISTRY}/${EXAMPLE}:${TAG}" +go run . --name ${NAME_OF_YOUR_EXAMPLE} --image "${REGISTRY}/${EXAMPLE}:${TAG}" ``` diff --git a/examples/_template/go.mod.tmpl b/examples/_template/go.mod.tmpl index ba0bb5ea4f..942533d2be 100644 --- a/examples/_template/go.mod.tmpl +++ b/examples/_template/go.mod.tmpl @@ -3,7 +3,7 @@ go 1.18 require ( - github.com/testcontainers/testcontainers-go v0.15.0 + github.com/testcontainers/testcontainers-go v{{ .TCVersion }} gotest.tools/gotestsum v1.8.2 ) diff --git a/examples/main.go b/examples/main.go index 423e25e4e8..c4707214b7 100644 --- a/examples/main.go +++ b/examples/main.go @@ -6,6 +6,7 @@ import ( "html/template" "os" "path/filepath" + "regexp" "sort" "strings" @@ -21,13 +22,14 @@ var templates = []string{ } func init() { - flag.StringVar(&nameVar, "name", "", "Name of the example, use camel-case when needed") + flag.StringVar(&nameVar, "name", "", "Name of the example, use camel-case when needed. Only alphabetical characters are allowed.") flag.StringVar(&imageVar, "image", "", "Fully-qualified name of the Docker image to be used by the example") } type Example struct { - Image string // fully qualified name of the Docker image - Name string + Image string // fully qualified name of the Docker image + Name string + TCVersion string // Testcontainers for Go version } func (e *Example) Lower() string { @@ -58,17 +60,30 @@ func main() { os.Exit(1) } - githubWorkflowsPath := filepath.Join(filepath.Dir(examplesDir), ".github", "workflows") - examplesDocsPath := filepath.Join(filepath.Dir(examplesDir), "docs", "examples") + rootDir := filepath.Dir(examplesDir) - err = generate(Example{Name: nameVar, Image: imageVar}, examplesDir, examplesDocsPath, githubWorkflowsPath) + mkdocsConfig, err := readMkdocsConfig(rootDir) + if err != nil { + fmt.Printf(">> could not read MkDocs config: %v\n", err) + os.Exit(1) + } + + err = generate(Example{Name: nameVar, Image: imageVar, TCVersion: mkdocsConfig.Extra.LatestVersion}, rootDir) if err != nil { fmt.Printf(">> error generating the example: %v\n", err) os.Exit(1) } } -func generate(example Example, examplesDir string, docsDir string, githubWorkflowsDir string) error { +func generate(example Example, rootDir string) error { + if !regexp.MustCompile(`^[A-Za-z]+$`).MatchString(example.Name) { + return fmt.Errorf("invalid name: %s. Only alphabetical characters are allowed", example.Name) + } + + githubWorkflowsDir := filepath.Join(rootDir, ".github", "workflows") + examplesDir := filepath.Join(rootDir, "examples") + docsDir := filepath.Join(rootDir, "docs", "examples") + funcMap := template.FuncMap{ "ToLower": strings.ToLower, "Title": cases.Title(language.Und, cases.NoLower).String, @@ -120,8 +135,6 @@ func generate(example Example, examplesDir string, docsDir string, githubWorkflo } } - rootDir := filepath.Dir(examplesDir) - // update examples in mkdocs mkdocsConfig, err := readMkdocsConfig(rootDir) if err != nil { @@ -130,9 +143,23 @@ func generate(example Example, examplesDir string, docsDir string, githubWorkflo mkdocsExamplesNav := mkdocsConfig.Nav[3].Examples - mkdocsExamplesNav = append(mkdocsExamplesNav, "examples/"+exampleLower+".md") - sort.Strings(mkdocsExamplesNav) - mkdocsConfig.Nav[3].Examples = mkdocsExamplesNav + // make sure the index.md is the first element in the list of examples in the nav + examplesNav := make([]string, len(mkdocsExamplesNav)-1) + + for _, exampleNav := range mkdocsExamplesNav { + // filter out the index.md file + if !strings.HasSuffix("index.md", exampleNav) { + examplesNav = append(examplesNav, exampleNav) + } + } + + examplesNav = append(examplesNav, "examples/"+exampleLower+".md") + sort.Strings(examplesNav) + + // prepend the index.md file + examplesNav = append([]string{"examples/index.md"}, examplesNav...) + + mkdocsConfig.Nav[3].Examples = examplesNav err = writeMkdocsConfig(rootDir, mkdocsConfig) if err != nil { diff --git a/examples/main_test.go b/examples/main_test.go index 6128228287..31887eb106 100644 --- a/examples/main_test.go +++ b/examples/main_test.go @@ -9,6 +9,49 @@ import ( "github.com/stretchr/testify/assert" ) +func TestGenerateWrongExampleName(t *testing.T) { + rootTmp := t.TempDir() + examplesTmp := filepath.Join(rootTmp, "examples") + examplesDocTmp := filepath.Join(rootTmp, "docs", "examples") + githubWorkflowsTmp := filepath.Join(rootTmp, ".github", "workflows") + + err := os.MkdirAll(examplesTmp, 0777) + assert.Nil(t, err) + err = os.MkdirAll(examplesDocTmp, 0777) + assert.Nil(t, err) + err = os.MkdirAll(githubWorkflowsTmp, 0777) + assert.Nil(t, err) + + err = copyInitialConfig(t, rootTmp) + assert.Nil(t, err) + + tests := []struct { + name string + }{ + {name: " foo"}, + {name: "foo "}, + {name: "foo bar"}, + {name: "foo-bar"}, + {name: "foo/bar"}, + {name: "foo\\bar"}, + {name: "1foo"}, + {name: "foo1"}, + {name: "-foo"}, + {name: "foo-"}, + } + + for _, test := range tests { + example := Example{ + Name: test.name, + Image: "docker.io/example/" + test.name + ":latest", + TCVersion: "v0.0.0-test", + } + + err = generate(example, rootTmp) + assert.Error(t, err) + } +} + func TestGenerate(t *testing.T) { rootTmp := t.TempDir() examplesTmp := filepath.Join(rootTmp, "examples") @@ -26,12 +69,13 @@ func TestGenerate(t *testing.T) { assert.Nil(t, err) example := Example{ - Name: "foo", - Image: "docker.io/example/foo:latest", + Name: "foo", + Image: "docker.io/example/foo:latest", + TCVersion: "v0.0.0-test", } exampleNameLower := example.Lower() - err = generate(example, examplesTmp, examplesDocTmp, githubWorkflowsTmp) + err = generate(example, rootTmp) assert.Nil(t, err) templatesDir, err := os.ReadDir(filepath.Join(".", "_template")) @@ -127,10 +171,10 @@ func assertExampleGithubWorkflowContent(t *testing.T, example Example, exampleWo assert.Equal(t, "name: "+title+" example pipeline", data[0]) assert.Equal(t, " test-"+lower+":", data[5]) assert.Equal(t, " go-version: ${{ matrix.go-version }}", data[15]) - assert.Equal(t, " working-directory: ./examples/foo", data[22]) - assert.Equal(t, " working-directory: ./examples/foo", data[26]) - assert.Equal(t, " working-directory: ./examples/foo", data[30]) - assert.Equal(t, " paths: \"**/TEST-foo*.xml\"", data[40]) + assert.Equal(t, " working-directory: ./examples/"+lower, data[22]) + assert.Equal(t, " working-directory: ./examples/"+lower, data[26]) + assert.Equal(t, " working-directory: ./examples/"+lower, data[30]) + assert.Equal(t, " paths: \"**/TEST-"+lower+"*.xml\"", data[40]) } // assert content go.mod @@ -139,7 +183,8 @@ func assertGoModContent(t *testing.T, example Example, goModFile string) { assert.Nil(t, err) data := strings.Split(string(content), "\n") - assert.Equal(t, data[0], "module github.com/testcontainers/testcontainers-go/examples/"+example.Lower()) + assert.Equal(t, "module github.com/testcontainers/testcontainers-go/examples/"+example.Lower(), data[0]) + assert.Equal(t, "\tgithub.com/testcontainers/testcontainers-go v"+example.TCVersion, data[5]) } // assert content Makefile @@ -156,6 +201,7 @@ func assertMkdocsExamplesNav(t *testing.T, example Example, rootDir string) { config, err := readMkdocsConfig(rootDir) assert.Nil(t, err) + // the example should be in the nav examples := config.Nav[3].Examples found := false for _, ex := range examples { @@ -166,6 +212,9 @@ func assertMkdocsExamplesNav(t *testing.T, example Example, rootDir string) { } assert.True(t, found) + + // first item is the index + assert.Equal(t, "examples/index.md", examples[0], examples) } // assert content tools/tools.go