Skip to content

Commit

Permalink
chore: adjust generator for the docs site (#639)
Browse files Browse the repository at this point in the history
* fix: use current release version in generated code

* docs: fix go run command to include all Go files

* chore: simplify generation arguments

* fix: make tests more resilient

* fix: make sure the index is the first item in the examples nav bar

* chore: allow alphabetical chars only as example name

* fix: use correct regexp

* fix: typo
  • Loading branch information
mdelapenya committed Nov 24, 2022
1 parent a53fa1f commit 57e54b3
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 24 deletions.
7 changes: 4 additions & 3 deletions docs/examples/index.md
Expand Up @@ -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.
Expand All @@ -21,17 +21,18 @@ 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

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}"
```
2 changes: 1 addition & 1 deletion examples/_template/go.mod.tmpl
Expand Up @@ -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
)

Expand Down
51 changes: 39 additions & 12 deletions examples/main.go
Expand Up @@ -6,6 +6,7 @@ import (
"html/template"
"os"
"path/filepath"
"regexp"
"sort"
"strings"

Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
65 changes: 57 additions & 8 deletions examples/main_test.go
Expand Up @@ -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")
Expand All @@ -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"))
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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
Expand Down

0 comments on commit 57e54b3

Please sign in to comment.