From 566911ed03ec6b46bf12173f35e57f374074ba0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 14 Feb 2023 15:36:53 +0100 Subject: [PATCH] feat: support generating Go modules or example modules (#826) * chore: create a separate module for the generator * chore: get the root directory in the new layout * feat: support for creating modules or examples * fix: update dependabot and mkdocs * chore: extract example parent dir calculation to a function * chore: define entrypoint and container name methods * chore: rename setupTech to startContainer * chore: rename setup function in example modules * chor: include modulegen in dependabot * chore: add build script for modulegen * chore: include modulegen tests in CI * fix: update tests * docs: add missing dependabot entry * chore: update GH workflow example type * fix: do not depend on hardcoded lengths * chore: generate modules in its own directory in docs * chore: add build script for modules * docs: reuse --- .github/dependabot.yml | 6 + .github/workflows/ci.yml | 4 +- docs/examples/index.md | 38 +--- docs/modules/index.md | 56 +++++ docs/{examples => modules}/localstack.md | 0 examples/Makefile | 7 - examples/_template/example.go.tmpl | 28 --- examples/bigtable/bigtable.go | 5 +- examples/bigtable/bigtable_test.go | 2 +- examples/cockroachdb/cockroachdb.go | 2 +- examples/cockroachdb/cockroachdb_test.go | 2 +- examples/consul/consul.go | 4 +- examples/consul/consul_test.go | 2 +- examples/datastore/datastore.go | 5 +- examples/datastore/datastore_test.go | 2 +- examples/firestore/firestore.go | 5 +- examples/firestore/firestore_test.go | 2 +- examples/mongodb/mongodb.go | 4 +- examples/mongodb/mongodb_test.go | 2 +- examples/mysql/mysql.go | 4 +- examples/mysql/mysql_test.go | 2 +- examples/nginx/nginx.go | 2 +- examples/nginx/nginx_test.go | 2 +- examples/postgres/postgres.go | 4 +- examples/postgres/postgres_test.go | 8 +- examples/pubsub/pubsub.go | 5 +- examples/pubsub/pubsub_test.go | 2 +- examples/pulsar/pulsar.go | 2 +- examples/pulsar/pulsar_test.go | 2 +- examples/redis/redis.go | 2 +- examples/redis/redis_test.go | 2 +- examples/spanner/spanner.go | 5 +- examples/spanner/spanner_test.go | 2 +- examples/toxiproxy/toxiproxy.go | 5 +- examples/toxiproxy/toxiproxy_test.go | 2 +- go.mod | 4 +- mkdocs.yml | 4 +- modulegen/Makefile | 1 + {examples => modulegen}/README.md | 0 .../_template/Makefile.tmpl | 0 {examples => modulegen}/_template/ci.yml.tmpl | 2 +- .../_template/docs_example.md.tmpl | 0 modulegen/_template/example.go.tmpl | 28 +++ .../_template/example_test.go.tmpl | 0 {examples => modulegen}/_template/go.mod.tmpl | 0 .../_template/tools.go.tmpl | 0 {examples => modulegen}/dependabot.go | 4 +- {examples => modulegen}/dependabot_test.go | 40 +++- modulegen/go.mod | 26 +++ modulegen/go.sum | 94 ++++++++ {examples => modulegen}/main.go | 111 +++++++--- {examples => modulegen}/main_test.go | 201 ++++++++++++++---- {examples => modulegen}/mkdocs.go | 1 + {examples => modulegen}/mkdocs_test.go | 5 +- modulegen/tools/tools.go | 11 + modules/Makefile | 9 + 56 files changed, 579 insertions(+), 189 deletions(-) create mode 100644 docs/modules/index.md rename docs/{examples => modules}/localstack.md (100%) delete mode 100644 examples/_template/example.go.tmpl create mode 100644 modulegen/Makefile rename {examples => modulegen}/README.md (100%) rename {examples => modulegen}/_template/Makefile.tmpl (100%) rename {examples => modulegen}/_template/ci.yml.tmpl (94%) rename {examples => modulegen}/_template/docs_example.md.tmpl (100%) create mode 100644 modulegen/_template/example.go.tmpl rename {examples => modulegen}/_template/example_test.go.tmpl (100%) rename {examples => modulegen}/_template/go.mod.tmpl (100%) rename {examples => modulegen}/_template/tools.go.tmpl (100%) rename {examples => modulegen}/dependabot.go (95%) rename {examples => modulegen}/dependabot_test.go (66%) create mode 100644 modulegen/go.mod create mode 100644 modulegen/go.sum rename {examples => modulegen}/main.go (62%) rename {examples => modulegen}/main_test.go (61%) rename {examples => modulegen}/mkdocs.go (97%) rename {examples => modulegen}/mkdocs_test.go (93%) create mode 100644 modulegen/tools/tools.go create mode 100644 modules/Makefile diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 33cb472657..92f9ee5cf1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,12 @@ updates: interval: weekly open-pull-requests-limit: 3 rebase-strategy: disabled + - package-ecosystem: gomod + directory: /modulegen + schedule: + interval: weekly + open-pull-requests-limit: 3 + rebase-strategy: disabled - package-ecosystem: gomod directory: /modules/compose schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f87b0a3292..a64972b0d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,9 +43,9 @@ jobs: if: ${{ matrix.platform == 'ubuntu-latest' }} run: make test-unit - - name: Run example generator tests + - name: Run module generator tests if: ${{ matrix.platform == 'ubuntu-latest' }} - run: make -C examples test-unit + run: make -C modulegen test-unit - name: Run checker run: | diff --git a/docs/examples/index.md b/docs/examples/index.md index 4c6c4c1a08..00c0af2a7e 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -1,42 +1,12 @@ # Code examples -In this section you'll discover how to create code examples for _Testcontainers for Go_. +In this section you'll discover how to create code examples for _Testcontainers for Go_, which are almost the same as Go modules, but without exporting any public API. -## Interested in adding a new example? - -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, 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. - - a Makefile to run the tests in a consistent manner - - a tools.go file including the build tools (i.e. `gotestsum`) used to build/run the example. -- a markdown file in the docs/examples directory including the snippets for both the creation of the container and a simple test. -- a new Nav entry for the example in the docs site, adding it to the `mkdocs.yml` file located at the root directory of the project. -- a GitHub workflow file in the .github/workflows directory to run the tests for the example. - -### Command line flags - -| Flag | Type | Required | Description | -|------|------|----------|-------------| -| -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') | -| -title | string | No | A variant of the name supporting mixed casing (i.e. 'MongoDB'). Only alphabetical characters are allowed. | - -### What is this tool not doing? +Their main goal is to create shareable code snippets on how to use certain technology (e.g. a database, a web server), in order to explore its usage before converting the example module into a real Go module exposing a public API. -- If the example name does not contain alphabetical 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: +## Interested in adding a new example? -```shell -go run . --name ${NAME_OF_YOUR_EXAMPLE} --image "${REGISTRY}/${EXAMPLE}:${TAG}" --title ${TITLE_OF_YOUR_EXAMPLE} -``` +Please refer to the documentation of the code generation tool [here](../modules/index.md). ## Update Go dependencies in the examples diff --git a/docs/modules/index.md b/docs/modules/index.md new file mode 100644 index 0000000000..492488cdb2 --- /dev/null +++ b/docs/modules/index.md @@ -0,0 +1,56 @@ +# Testcontainers for Go modules + +In this section you'll discover how to create Go modules for _Testcontainers for Go_. + +## Interested in adding a new module? + +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, including the current version of _Testcontainer for Go_. + - a Go package named after the module, 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. + - a Makefile to run the tests in a consistent manner + - a tools.go file including the build tools (i.e. `gotestsum`) used to build/run the example. +- a markdown file in the docs/modules directory including the snippets for both the creation of the container and a simple test. +- a new Nav entry for the module in the docs site, adding it to the `mkdocs.yml` file located at the root directory of the project. +- a GitHub workflow file in the .github/workflows directory to run the tests for the example. +- an entry in Dependabot's configuration file, in order to receive dependency updates. + +### Command line flags + +| Flag | Type | Required | Description | +|------|------|----------|-------------| +| -name | string | Yes | Name of the module, 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 module (i.e. 'docker.io/org/project:tag') | +| -title | string | No | A variant of the name supporting mixed casing (i.e. 'MongoDB'). Only alphabetical characters are allowed. | +| -as-module | bool | No | If set, the module will be generated as a Go module, under the modules directory. Otherwise, it will be generated as a subdirectory of the examples directory. | + +### What is this tool not doing? + +- If the module name does not contain alphabetical characters, it will exit the generation. +- If the module already exists, it will exit without updating the existing files. + +### How to run the tool + +From the [`modulegen` directory]({{repo_url}}/tree/main/modulegen), please run: + +```shell +go run . --name ${NAME_OF_YOUR_MODULE} --image "${REGISTRY}/${MODULE}:${TAG}" --title ${TITLE_OF_YOUR_MODULE} +``` + +or for creating a Go module: + +```shell +go run . --name ${NAME_OF_YOUR_MODULE} --image "${REGISTRY}/${MODULE}:${TAG}" --title ${TITLE_OF_YOUR_MODULE} --as-module +``` + +## Update Go dependencies in the modules + +To update the Go dependencies in the modules, please run: + +```shell +$ cd modules +$ make tidy-examples +``` diff --git a/docs/examples/localstack.md b/docs/modules/localstack.md similarity index 100% rename from docs/examples/localstack.md rename to docs/modules/localstack.md diff --git a/examples/Makefile b/examples/Makefile index 287b71f193..24a12345f9 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -4,13 +4,6 @@ include ../commons-test.mk dependencies-scan-examples: @find . -type f -name Makefile -execdir make dependencies-scan \; -.PHONY: test -test: test-unit - $(MAKE) -C cockroachdb test - $(MAKE) -C nginx test - $(MAKE) -C pulsar test - $(MAKE) -C redis test - .PHONY: tidy-examples tidy-examples: @find . -type f -name Makefile -execdir make tools-tidy \; diff --git a/examples/_template/example.go.tmpl b/examples/_template/example.go.tmpl deleted file mode 100644 index 5e726f3717..0000000000 --- a/examples/_template/example.go.tmpl +++ /dev/null @@ -1,28 +0,0 @@ -{{ $lower := ToLower }}{{ $title := Title }}{{ $lowerTitle := ToLowerTitle }}package {{ $lower }} - -import ( - "context" - - "github.com/testcontainers/testcontainers-go" -) - -// {{ $lowerTitle }}Container represents the {{ $title }} container type used in the module -type {{ $lowerTitle }}Container struct { - testcontainers.Container -} - -// setup{{ $title }} creates an instance of the {{ $title }} container type -func setup{{ $title }}(ctx context.Context) (*{{ $lowerTitle }}Container, error) { - req := testcontainers.ContainerRequest{ - Image: "{{ .Image }}", - } - container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: req, - Started: true, - }) - if err != nil { - return nil, err - } - - return &{{ $lowerTitle }}Container{Container: container}, nil -} diff --git a/examples/bigtable/bigtable.go b/examples/bigtable/bigtable.go index 6601a2ec8d..f6c32bac7d 100644 --- a/examples/bigtable/bigtable.go +++ b/examples/bigtable/bigtable.go @@ -3,6 +3,7 @@ package bigtable import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go/wait" "github.com/testcontainers/testcontainers-go" @@ -14,8 +15,8 @@ type bigtableContainer struct { URI string } -// setupBigtable creates an instance of the bigtable container type -func setupBigtable(ctx context.Context) (*bigtableContainer, error) { +// startContainer creates an instance of the bigtable container type +func startContainer(ctx context.Context) (*bigtableContainer, error) { req := testcontainers.ContainerRequest{ Image: "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators", ExposedPorts: []string{"9000/tcp"}, diff --git a/examples/bigtable/bigtable_test.go b/examples/bigtable/bigtable_test.go index bfc60b20c4..f724ee8585 100644 --- a/examples/bigtable/bigtable_test.go +++ b/examples/bigtable/bigtable_test.go @@ -18,7 +18,7 @@ const ( func TestBigtable(t *testing.T) { ctx := context.Background() - container, err := setupBigtable(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/cockroachdb/cockroachdb.go b/examples/cockroachdb/cockroachdb.go index 12114874e5..176c1a371d 100644 --- a/examples/cockroachdb/cockroachdb.go +++ b/examples/cockroachdb/cockroachdb.go @@ -14,7 +14,7 @@ type cockroachDBContainer struct { URI string } -func setupCockroachDB(ctx context.Context) (*cockroachDBContainer, error) { +func startContainer(ctx context.Context) (*cockroachDBContainer, error) { req := testcontainers.ContainerRequest{ Image: "cockroachdb/cockroach:latest-v21.1", ExposedPorts: []string{"26257/tcp", "8080/tcp"}, diff --git a/examples/cockroachdb/cockroachdb_test.go b/examples/cockroachdb/cockroachdb_test.go index 932630e002..38706d9737 100644 --- a/examples/cockroachdb/cockroachdb_test.go +++ b/examples/cockroachdb/cockroachdb_test.go @@ -48,7 +48,7 @@ func TestIntegrationDBInsertSelect(t *testing.T) { ctx := context.Background() - cdbContainer, err := setupCockroachDB(ctx) + cdbContainer, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/consul/consul.go b/examples/consul/consul.go index 22a7230bb6..1f2e83bbd6 100644 --- a/examples/consul/consul.go +++ b/examples/consul/consul.go @@ -14,8 +14,8 @@ type consulContainer struct { endpoint string } -// setupConsul creates an instance of the consul container type -func setupConsul(ctx context.Context) (*consulContainer, error) { +// startContainer creates an instance of the consul container type +func startContainer(ctx context.Context) (*consulContainer, error) { req := testcontainers.ContainerRequest{ Image: "consul:latest", ExposedPorts: []string{"8500/tcp", "8600/udp"}, diff --git a/examples/consul/consul_test.go b/examples/consul/consul_test.go index d454172de3..f22e89290c 100644 --- a/examples/consul/consul_test.go +++ b/examples/consul/consul_test.go @@ -11,7 +11,7 @@ import ( func TestConsul(t *testing.T) { ctx := context.Background() - container, err := setupConsul(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/datastore/datastore.go b/examples/datastore/datastore.go index 906a186388..488dd56de2 100644 --- a/examples/datastore/datastore.go +++ b/examples/datastore/datastore.go @@ -3,6 +3,7 @@ package datastore import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" ) @@ -13,8 +14,8 @@ type datastoreContainer struct { URI string } -// setupDatastore creates an instance of the datastore container type -func setupDatastore(ctx context.Context) (*datastoreContainer, error) { +// startContainer creates an instance of the datastore container type +func startContainer(ctx context.Context) (*datastoreContainer, error) { req := testcontainers.ContainerRequest{ Image: "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators", ExposedPorts: []string{"8081/tcp"}, diff --git a/examples/datastore/datastore_test.go b/examples/datastore/datastore_test.go index cec88724cd..f8a45ee828 100644 --- a/examples/datastore/datastore_test.go +++ b/examples/datastore/datastore_test.go @@ -16,7 +16,7 @@ type Task struct { func TestDatastore(t *testing.T) { ctx := context.Background() - container, err := setupDatastore(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/firestore/firestore.go b/examples/firestore/firestore.go index c591021e07..4e0ef27d06 100644 --- a/examples/firestore/firestore.go +++ b/examples/firestore/firestore.go @@ -3,6 +3,7 @@ package firestore import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go/wait" "github.com/testcontainers/testcontainers-go" @@ -14,8 +15,8 @@ type firestoreContainer struct { URI string } -// setupFirestore creates an instance of the firestore container type -func setupFirestore(ctx context.Context) (*firestoreContainer, error) { +// startContainer creates an instance of the firestore container type +func startContainer(ctx context.Context) (*firestoreContainer, error) { req := testcontainers.ContainerRequest{ Image: "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators", ExposedPorts: []string{"8080/tcp"}, diff --git a/examples/firestore/firestore_test.go b/examples/firestore/firestore_test.go index 2912b04faf..398fdac767 100644 --- a/examples/firestore/firestore_test.go +++ b/examples/firestore/firestore_test.go @@ -27,7 +27,7 @@ func (ec emulatorCreds) RequireTransportSecurity() bool { func TestFirestore(t *testing.T) { ctx := context.Background() - container, err := setupFirestore(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/mongodb/mongodb.go b/examples/mongodb/mongodb.go index 4d1880e219..5d73f79113 100644 --- a/examples/mongodb/mongodb.go +++ b/examples/mongodb/mongodb.go @@ -12,8 +12,8 @@ type mongodbContainer struct { testcontainers.Container } -// setupMongoDB creates an instance of the mongodb container type -func setupMongoDB(ctx context.Context) (*mongodbContainer, error) { +// startContainer creates an instance of the mongodb container type +func startContainer(ctx context.Context) (*mongodbContainer, error) { req := testcontainers.ContainerRequest{ Image: "mongo:6", ExposedPorts: []string{"27017/tcp"}, diff --git a/examples/mongodb/mongodb_test.go b/examples/mongodb/mongodb_test.go index 3f0668aa74..9b3e3b9d7f 100644 --- a/examples/mongodb/mongodb_test.go +++ b/examples/mongodb/mongodb_test.go @@ -12,7 +12,7 @@ import ( func TestMongoDB(t *testing.T) { ctx := context.Background() - container, err := setupMongoDB(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/mysql/mysql.go b/examples/mysql/mysql.go index 19160dbd70..2a8cf42192 100644 --- a/examples/mysql/mysql.go +++ b/examples/mysql/mysql.go @@ -12,8 +12,8 @@ type mysqlContainer struct { testcontainers.Container } -// setupMysql creates an instance of the mysql container type -func setupMysql(ctx context.Context) (*mysqlContainer, error) { +// startContainer creates an instance of the mysql container type +func startContainer(ctx context.Context) (*mysqlContainer, error) { req := testcontainers.ContainerRequest{ Image: "mysql:8", ExposedPorts: []string{"3306/tcp", "33060/tcp"}, diff --git a/examples/mysql/mysql_test.go b/examples/mysql/mysql_test.go index d185bf1e24..7e450c4644 100644 --- a/examples/mysql/mysql_test.go +++ b/examples/mysql/mysql_test.go @@ -13,7 +13,7 @@ import ( func TestMysql(t *testing.T) { ctx := context.Background() - container, err := setupMysql(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/nginx/nginx.go b/examples/nginx/nginx.go index 0062b05f61..435f638f40 100644 --- a/examples/nginx/nginx.go +++ b/examples/nginx/nginx.go @@ -13,7 +13,7 @@ type nginxContainer struct { URI string } -func setupNginx(ctx context.Context) (*nginxContainer, error) { +func startContainer(ctx context.Context) (*nginxContainer, error) { req := testcontainers.ContainerRequest{ Image: "nginx", ExposedPorts: []string{"80/tcp"}, diff --git a/examples/nginx/nginx_test.go b/examples/nginx/nginx_test.go index bc7e647baf..3d7b8ada48 100644 --- a/examples/nginx/nginx_test.go +++ b/examples/nginx/nginx_test.go @@ -13,7 +13,7 @@ func TestIntegrationNginxLatestReturn(t *testing.T) { ctx := context.Background() - nginxC, err := setupNginx(ctx) + nginxC, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/postgres/postgres.go b/examples/postgres/postgres.go index 87385f5753..015d4b29a1 100644 --- a/examples/postgres/postgres.go +++ b/examples/postgres/postgres.go @@ -35,8 +35,8 @@ func WithInitialDatabase(user string, password string, dbName string) func(req * } } -// setupPostgres creates an instance of the postgres container type -func setupPostgres(ctx context.Context, opts ...postgresContainerOption) (*postgresContainer, error) { +// startContainer creates an instance of the postgres container type +func startContainer(ctx context.Context, opts ...postgresContainerOption) (*postgresContainer, error) { req := testcontainers.ContainerRequest{ Image: "postgres:11-alpine", Env: map[string]string{}, diff --git a/examples/postgres/postgres_test.go b/examples/postgres/postgres_test.go index d70ae65d74..9c57c542f7 100644 --- a/examples/postgres/postgres_test.go +++ b/examples/postgres/postgres_test.go @@ -25,7 +25,7 @@ func TestPostgres(t *testing.T) { port, err := nat.NewPort("tcp", "5432") require.NoError(t, err) - container, err := setupPostgres(ctx, + container, err := startContainer(ctx, WithPort(port.Port()), WithInitialDatabase(user, password, dbname), WithWaitStrategy(wait.ForLog("database system is ready to accept connections").WithOccurrence(2).WithStartupTimeout(5*time.Second)), @@ -77,12 +77,12 @@ func TestContainerWithWaitForSQL(t *testing.T) { } t.Run("default query", func(t *testing.T) { - container, err := setupPostgres(ctx, WithPort(port), WithInitialDatabase("postgres", "password", dbname), WithWaitStrategy(wait.ForSQL(nat.Port(port), "postgres", dbURL))) + container, err := startContainer(ctx, WithPort(port), WithInitialDatabase("postgres", "password", dbname), WithWaitStrategy(wait.ForSQL(nat.Port(port), "postgres", dbURL))) require.NoError(t, err) require.NotNil(t, container) }) t.Run("custom query", func(t *testing.T) { - container, err := setupPostgres( + container, err := startContainer( ctx, WithPort(port), WithInitialDatabase(user, password, dbname), @@ -92,7 +92,7 @@ func TestContainerWithWaitForSQL(t *testing.T) { require.NotNil(t, container) }) t.Run("custom bad query", func(t *testing.T) { - container, err := setupPostgres( + container, err := startContainer( ctx, WithPort(port), WithInitialDatabase(user, password, dbname), diff --git a/examples/pubsub/pubsub.go b/examples/pubsub/pubsub.go index 10d5074544..374bf487e8 100644 --- a/examples/pubsub/pubsub.go +++ b/examples/pubsub/pubsub.go @@ -3,6 +3,7 @@ package pubsub import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" ) @@ -13,8 +14,8 @@ type pubsubContainer struct { URI string } -// setupPubsub creates an instance of the pubsub container type -func setupPubsub(ctx context.Context) (*pubsubContainer, error) { +// startContainer creates an instance of the pubsub container type +func startContainer(ctx context.Context) (*pubsubContainer, error) { req := testcontainers.ContainerRequest{ Image: "gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators", ExposedPorts: []string{"8085/tcp"}, diff --git a/examples/pubsub/pubsub_test.go b/examples/pubsub/pubsub_test.go index 14d06654ac..67c97bd38d 100644 --- a/examples/pubsub/pubsub_test.go +++ b/examples/pubsub/pubsub_test.go @@ -12,7 +12,7 @@ import ( func TestPubsub(t *testing.T) { ctx := context.Background() - container, err := setupPubsub(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/pulsar/pulsar.go b/examples/pulsar/pulsar.go index 920d8782cf..00af752733 100644 --- a/examples/pulsar/pulsar.go +++ b/examples/pulsar/pulsar.go @@ -14,7 +14,7 @@ type pulsarContainer struct { URI string } -func setupPulsar(ctx context.Context) (*pulsarContainer, error) { +func startContainer(ctx context.Context) (*pulsarContainer, error) { matchAdminResponse := func(r io.Reader) bool { respBytes, _ := io.ReadAll(r) resp := string(respBytes) diff --git a/examples/pulsar/pulsar_test.go b/examples/pulsar/pulsar_test.go index 14f4d9fec5..024a4f14e5 100644 --- a/examples/pulsar/pulsar_test.go +++ b/examples/pulsar/pulsar_test.go @@ -13,7 +13,7 @@ func TestPulsar(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - c, err := setupPulsar(ctx) + c, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/redis/redis.go b/examples/redis/redis.go index 1a6236fe0f..9e40597ef4 100644 --- a/examples/redis/redis.go +++ b/examples/redis/redis.go @@ -13,7 +13,7 @@ type redisContainer struct { URI string } -func setupRedis(ctx context.Context) (*redisContainer, error) { +func startContainer(ctx context.Context) (*redisContainer, error) { req := testcontainers.ContainerRequest{ Image: "redis:6", ExposedPorts: []string{"6379/tcp"}, diff --git a/examples/redis/redis_test.go b/examples/redis/redis_test.go index a1b462c62c..8a96974d7f 100644 --- a/examples/redis/redis_test.go +++ b/examples/redis/redis_test.go @@ -18,7 +18,7 @@ func TestIntegrationSetGet(t *testing.T) { ctx := context.Background() - redisContainer, err := setupRedis(ctx) + redisContainer, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/spanner/spanner.go b/examples/spanner/spanner.go index b0302594f8..ad8f3370af 100644 --- a/examples/spanner/spanner.go +++ b/examples/spanner/spanner.go @@ -3,6 +3,7 @@ package spanner import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go/wait" "github.com/testcontainers/testcontainers-go" @@ -14,8 +15,8 @@ type spannerContainer struct { GRPCEndpoint string } -// setupSpanner creates an instance of the spanner container type -func setupSpanner(ctx context.Context) (*spannerContainer, error) { +// startContainer creates an instance of the spanner container type +func startContainer(ctx context.Context) (*spannerContainer, error) { req := testcontainers.ContainerRequest{ Image: "gcr.io/cloud-spanner-emulator/emulator:1.4.0", ExposedPorts: []string{"9010/tcp"}, diff --git a/examples/spanner/spanner_test.go b/examples/spanner/spanner_test.go index 22a84c337e..3715dc88ae 100644 --- a/examples/spanner/spanner_test.go +++ b/examples/spanner/spanner_test.go @@ -24,7 +24,7 @@ const ( func TestSpanner(t *testing.T) { ctx := context.Background() - container, err := setupSpanner(ctx) + container, err := startContainer(ctx) if err != nil { t.Fatal(err) } diff --git a/examples/toxiproxy/toxiproxy.go b/examples/toxiproxy/toxiproxy.go index b07402305b..ed335c14f3 100644 --- a/examples/toxiproxy/toxiproxy.go +++ b/examples/toxiproxy/toxiproxy.go @@ -3,6 +3,7 @@ package toxiproxy import ( "context" "fmt" + "github.com/testcontainers/testcontainers-go/wait" "github.com/testcontainers/testcontainers-go" @@ -14,8 +15,8 @@ type toxiproxyContainer struct { URI string } -// setupToxiproxy creates an instance of the toxiproxy container type -func setupToxiproxy(ctx context.Context, network string, networkAlias []string) (*toxiproxyContainer, error) { +// startContainer creates an instance of the toxiproxy container type +func startContainer(ctx context.Context, network string, networkAlias []string) (*toxiproxyContainer, error) { req := testcontainers.ContainerRequest{ Image: "ghcr.io/shopify/toxiproxy:2.5.0", ExposedPorts: []string{"8474/tcp", "8666/tcp"}, diff --git a/examples/toxiproxy/toxiproxy_test.go b/examples/toxiproxy/toxiproxy_test.go index 9a4eaccb71..5cee012924 100644 --- a/examples/toxiproxy/toxiproxy_test.go +++ b/examples/toxiproxy/toxiproxy_test.go @@ -25,7 +25,7 @@ func TestToxiproxy(t *testing.T) { t.Fatal(err) } - toxiproxyContainer, err := setupToxiproxy(ctx, "newNetwork", []string{"toxiproxy"}) + toxiproxyContainer, err := startContainer(ctx, "newNetwork", []string{"toxiproxy"}) if err != nil { t.Fatal(err) } diff --git a/go.mod b/go.mod index b055fe0ff6..f7829d18da 100644 --- a/go.mod +++ b/go.mod @@ -14,8 +14,6 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc2 github.com/stretchr/testify v1.8.1 golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 - gopkg.in/yaml.v3 v3.0.1 gotest.tools/gotestsum v1.9.0 ) @@ -51,10 +49,12 @@ require ( golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.1.12 // indirect google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad // indirect google.golang.org/grpc v1.47.0 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/mkdocs.yml b/mkdocs.yml index 5a3774c59a..4240089631 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,6 +46,9 @@ nav: - Log: features/wait/log.md - Multi: features/wait/multi.md - SQL: features/wait/sql.md + - Modules: + - modules/index.md + - modules/localstack.md - Examples: - examples/index.md - examples/bigtable.md @@ -53,7 +56,6 @@ nav: - examples/consul.md - examples/datastore.md - examples/firestore.md - - examples/localstack.md - examples/mongodb.md - examples/mysql.md - examples/nginx.md diff --git a/modulegen/Makefile b/modulegen/Makefile new file mode 100644 index 0000000000..748cb213ea --- /dev/null +++ b/modulegen/Makefile @@ -0,0 +1 @@ +include ../commons-test.mk diff --git a/examples/README.md b/modulegen/README.md similarity index 100% rename from examples/README.md rename to modulegen/README.md diff --git a/examples/_template/Makefile.tmpl b/modulegen/_template/Makefile.tmpl similarity index 100% rename from examples/_template/Makefile.tmpl rename to modulegen/_template/Makefile.tmpl diff --git a/examples/_template/ci.yml.tmpl b/modulegen/_template/ci.yml.tmpl similarity index 94% rename from examples/_template/ci.yml.tmpl rename to modulegen/_template/ci.yml.tmpl index f27d16d8aa..23ecb4a289 100644 --- a/examples/_template/ci.yml.tmpl +++ b/modulegen/_template/ci.yml.tmpl @@ -1,4 +1,4 @@ -{{ $lower := ToLower }}name: {{ Title }} example pipeline +{{ $lower := ToLower }}name: {{ Title }} {{ ExampleType }} pipeline on: [push, pull_request] diff --git a/examples/_template/docs_example.md.tmpl b/modulegen/_template/docs_example.md.tmpl similarity index 100% rename from examples/_template/docs_example.md.tmpl rename to modulegen/_template/docs_example.md.tmpl diff --git a/modulegen/_template/example.go.tmpl b/modulegen/_template/example.go.tmpl new file mode 100644 index 0000000000..4936388a94 --- /dev/null +++ b/modulegen/_template/example.go.tmpl @@ -0,0 +1,28 @@ +{{ $entrypoint := Entrypoint }}{{ $containerName := ContainerName }}{{ $lower := ToLower }}{{ $title := Title }}package {{ $lower }} + +import ( + "context" + + "github.com/testcontainers/testcontainers-go" +) + +// {{ $containerName }} represents the {{ $title }} container type used in the module +type {{ $containerName }} struct { + testcontainers.Container +} + +// {{ $entrypoint }} creates an instance of the {{ $title }} container type +func {{ $entrypoint }}(ctx context.Context) (*{{ $containerName }}, error) { + req := testcontainers.ContainerRequest{ + Image: "{{ .Image }}", + } + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + if err != nil { + return nil, err + } + + return &{{ $containerName }}{Container: container}, nil +} diff --git a/examples/_template/example_test.go.tmpl b/modulegen/_template/example_test.go.tmpl similarity index 100% rename from examples/_template/example_test.go.tmpl rename to modulegen/_template/example_test.go.tmpl diff --git a/examples/_template/go.mod.tmpl b/modulegen/_template/go.mod.tmpl similarity index 100% rename from examples/_template/go.mod.tmpl rename to modulegen/_template/go.mod.tmpl diff --git a/examples/_template/tools.go.tmpl b/modulegen/_template/tools.go.tmpl similarity index 100% rename from examples/_template/tools.go.tmpl rename to modulegen/_template/tools.go.tmpl diff --git a/examples/dependabot.go b/modulegen/dependabot.go similarity index 95% rename from examples/dependabot.go rename to modulegen/dependabot.go index 43196c93d6..1ca36fa7e7 100644 --- a/examples/dependabot.go +++ b/modulegen/dependabot.go @@ -26,9 +26,9 @@ type Update struct { RebaseStrategy string `yaml:"rebase-strategy"` } -func NewUpdate(example string) Update { +func NewUpdate(example Example) Update { return Update{ - Directory: "/examples/" + example, + Directory: "/" + example.ParentDir() + "/" + example.Lower(), OpenPullRequestsLimit: 3, PackageEcosystem: "gomod", RebaseStrategy: "disabled", diff --git a/examples/dependabot_test.go b/modulegen/dependabot_test.go similarity index 66% rename from examples/dependabot_test.go rename to modulegen/dependabot_test.go index 675737c2bd..b21f1c63ef 100644 --- a/examples/dependabot_test.go +++ b/modulegen/dependabot_test.go @@ -28,6 +28,32 @@ func TestGetDependabotConfigFile(t *testing.T) { assert.True(t, strings.HasSuffix(file, filepath.Join("testcontainers-go", ".github", "dependabot.yml"))) } +func TestNewUpdate(t *testing.T) { + tests := []struct { + isModule bool + parentDir string + }{ + {true, "/modules"}, + {false, "/examples"}, + } + + for _, test := range tests { + update := NewUpdate(Example{ + Name: "Test", + IsModule: test.isModule, + Image: "test", + TitleName: "Test", + TCVersion: "v1.0.0", + }) + + assert.Equal(t, update.Directory, test.parentDir+"/test") + assert.Equal(t, update.PackageEcosystem, "gomod") + assert.Equal(t, update.OpenPullRequestsLimit, 3) + assert.Equal(t, update.Schedule.Interval, "weekly") + assert.Equal(t, update.RebaseStrategy, "disabled") + } +} + func TestReadDependabotConfig(t *testing.T) { tmp := t.TempDir() @@ -49,11 +75,19 @@ func TestReadDependabotConfig(t *testing.T) { func TestExamplesHasDependabotEntry(t *testing.T) { examples, err := getExamples() require.NoError(t, err) - exampleUpdates, err := getDependabotUpdates() + dependabotUpdates, err := getDependabotUpdates() require.NoError(t, err) - // we have to exclude the main and compose modules from the examples updates - assert.Equal(t, len(exampleUpdates)-3, len(examples)) + exampleUpdates := []Update{} + // exclude the Go modules from the examples updates + for _, update := range dependabotUpdates { + if update.Directory == "/" || update.Directory == "/modulegen" || strings.HasPrefix(update.Directory, "/modules") { + continue + } + exampleUpdates = append(exampleUpdates, update) + } + + assert.Equal(t, len(exampleUpdates), len(examples)) // all example modules exist in the dependabot updates for _, example := range examples { diff --git a/modulegen/go.mod b/modulegen/go.mod new file mode 100644 index 0000000000..8cf874daed --- /dev/null +++ b/modulegen/go.mod @@ -0,0 +1,26 @@ +module github.com/testcontainers/testcontainers-go/modulegen + +go 1.18 + +require ( + github.com/stretchr/testify v1.8.1 + golang.org/x/text v0.7.0 + gopkg.in/yaml.v3 v3.0.1 + gotest.tools/gotestsum v1.9.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dnephin/pflag v1.0.7 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect + golang.org/x/tools v0.1.12 // indirect +) diff --git a/modulegen/go.sum b/modulegen/go.sum new file mode 100644 index 0000000000..1366a02dec --- /dev/null +++ b/modulegen/go.sum @@ -0,0 +1,94 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/gotestsum v1.9.0 h1:Jbo/0k/sIOXIJu51IZxEAt27n77xspFEfL6SqKUR72A= +gotest.tools/gotestsum v1.9.0/go.mod h1:6JHCiN6TEjA7Kaz23q1bH0e2Dc3YJjDUZ0DmctFZf+w= +gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= +gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= diff --git a/examples/main.go b/modulegen/main.go similarity index 62% rename from examples/main.go rename to modulegen/main.go index ac7332da9b..48154e284f 100644 --- a/examples/main.go +++ b/modulegen/main.go @@ -17,6 +17,7 @@ import ( "golang.org/x/text/language" ) +var asModuleVar bool var nameVar string var nameTitleVar string var imageVar string @@ -29,26 +30,54 @@ func init() { flag.StringVar(&nameVar, "name", "", "Name of the example. Only alphabetical characters are allowed.") flag.StringVar(&nameTitleVar, "title", "", "(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.") flag.StringVar(&imageVar, "image", "", "Fully-qualified name of the Docker image to be used by the example") + flag.BoolVar(&asModuleVar, "as-module", false, "If set, the example will be generated as a Go module, under the modules directory. Otherwise, it will be generated as a subdirectory of the examples directory.") } type Example struct { Image string // fully qualified name of the Docker image + IsModule bool // if true, the example will be generated as a Go module Name string TitleName string // title of the name: e.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() + + if e.IsModule { + name = e.Title() + } else { + if e.TitleName != "" { + r, n := utf8.DecodeRuneInString(e.TitleName) + name = string(unicode.ToLower(r)) + e.TitleName[n:] + } + } + + return name + "Container" +} + +// 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 "StartContainer" +func (e *Example) Entrypoint() string { + if e.IsModule { + return "StartContainer" + } + + return "startContainer" +} + func (e *Example) Lower() string { return strings.ToLower(e.Name) } -func (e *Example) LowerTitle() string { - if e.TitleName != "" { - r, n := utf8.DecodeRuneInString(e.TitleName) - return string(unicode.ToLower(r)) + e.TitleName[n:] +func (e *Example) ParentDir() string { + if e.IsModule { + return "modules" } - return cases.Title(language.Und, cases.NoLower).String(e.Lower()) + return "examples" } func (e *Example) Title() string { @@ -59,6 +88,13 @@ func (e *Example) Title() string { return cases.Title(language.Und, cases.NoLower).String(e.Lower()) } +func (e *Example) Type() string { + if e.IsModule { + return "module" + } + return "example" +} + func (e *Example) Validate() error { if !regexp.MustCompile(`^[A-Za-z]+$`).MatchString(e.Name) { return fmt.Errorf("invalid name: %s. Only alphabetical characters are allowed", e.Name) @@ -85,13 +121,13 @@ func main() { } } - examplesDir, err := filepath.Abs(filepath.Dir(nameVar)) + currentDir, err := filepath.Abs(filepath.Dir(".")) if err != nil { - fmt.Printf(">> could not get the examples dir: %v\n", err) + fmt.Printf(">> could not get the root dir: %v\n", err) os.Exit(1) } - rootDir := filepath.Dir(examplesDir) + rootDir := filepath.Dir(currentDir) mkdocsConfig, err := readMkdocsConfig(rootDir) if err != nil { @@ -101,6 +137,7 @@ func main() { example := Example{ Image: imageVar, + IsModule: asModuleVar, Name: nameVar, TitleName: nameTitleVar, TCVersion: mkdocsConfig.Extra.LatestVersion, @@ -113,14 +150,14 @@ func main() { } cmd := exec.Command("go", "mod", "tidy") - cmd.Dir = filepath.Join(rootDir, "examples", example.Lower()) + cmd.Dir = filepath.Join(rootDir, example.ParentDir(), example.Lower()) err = cmd.Run() if err != nil { fmt.Printf(">> error synchronizing the dependencies: %v\n", err) os.Exit(1) } - fmt.Println("Please go to", example.Lower(), "directory to check the results, where 'go mod tidy' was executed to synchronize the dependencies") + fmt.Println("Please go to", cmd.Dir, "directory to check the results, where 'go mod tidy' was executed to synchronize the dependencies") fmt.Println("Commit the modified files and submit a pull request to include them into the project") fmt.Println("Thanks!") } @@ -131,18 +168,20 @@ func generate(example Example, rootDir string) error { } githubWorkflowsDir := filepath.Join(rootDir, ".github", "workflows") - examplesDir := filepath.Join(rootDir, "examples") - docsDir := filepath.Join(rootDir, "docs", "examples") + outputDir := filepath.Join(rootDir, example.ParentDir()) + docsOuputDir := filepath.Join(rootDir, "docs", example.ParentDir()) funcMap := template.FuncMap{ - "ToLower": func() string { return example.Lower() }, - "Title": func() string { return example.Title() }, - "ToLowerTitle": func() string { return example.LowerTitle() }, - "codeinclude": func(s string) template.HTML { return template.HTML(s) }, // escape HTML comments for codeinclude + "Entrypoint": func() string { return example.Entrypoint() }, + "ContainerName": func() string { return example.ContainerName() }, + "ExampleType": func() string { return example.Type() }, + "ToLower": func() string { return example.Lower() }, + "Title": func() string { return example.Title() }, + "codeinclude": func(s string) template.HTML { return template.HTML(s) }, // escape HTML comments for codeinclude } // create the example dir - err := os.MkdirAll(examplesDir, 0700) + err := os.MkdirAll(outputDir, 0700) if err != nil { return err } @@ -161,15 +200,20 @@ func generate(example Example, rootDir string) error { if strings.EqualFold(tmpl, "docs_example.md") { // docs example file will go into the docs directory - exampleFilePath = filepath.Join(docsDir, exampleLower+".md") + exampleFilePath = filepath.Join(docsOuputDir, exampleLower+".md") } else if strings.EqualFold(tmpl, "ci.yml") { // GitHub workflow example file will go into the .github/workflows directory - exampleFilePath = filepath.Join(githubWorkflowsDir, exampleLower+"-example.yml") + fileName := exampleLower + "-example.yml" + if example.IsModule { + fileName = "module-" + exampleLower + ".yml" + } + + exampleFilePath = filepath.Join(githubWorkflowsDir, fileName) } else if strings.EqualFold(tmpl, "tools.go") { // tools.go example file will go into the tools package - exampleFilePath = filepath.Join(examplesDir, exampleLower, "tools", tmpl) + exampleFilePath = filepath.Join(outputDir, exampleLower, "tools", tmpl) } else { - exampleFilePath = filepath.Join(examplesDir, exampleLower, strings.ReplaceAll(tmpl, "example", exampleLower)) + exampleFilePath = filepath.Join(outputDir, exampleLower, strings.ReplaceAll(tmpl, "example", exampleLower)) } err = os.MkdirAll(filepath.Dir(exampleFilePath), 0777) @@ -187,13 +231,13 @@ func generate(example Example, rootDir string) error { } // update examples in mkdocs - err = generateMkdocs(rootDir, exampleLower) + err = generateMkdocs(rootDir, example) if err != nil { return err } // update examples in dependabot - err = generateDependabotUpdates(rootDir, exampleLower) + err = generateDependabotUpdates(rootDir, example) if err != nil { return err } @@ -201,7 +245,7 @@ func generate(example Example, rootDir string) error { return nil } -func generateDependabotUpdates(rootDir string, exampleLower string) error { +func generateDependabotUpdates(rootDir string, example Example) error { // update examples in dependabot dependabotConfig, err := readDependabotConfig(rootDir) if err != nil { @@ -223,7 +267,7 @@ func generateDependabotUpdates(rootDir string, exampleLower string) error { } } - exampleUpdates = append(exampleUpdates, NewUpdate(exampleLower)) + exampleUpdates = append(exampleUpdates, NewUpdate(example)) sort.Sort(exampleUpdates) // prepend the main and compose modules @@ -234,14 +278,17 @@ func generateDependabotUpdates(rootDir string, exampleLower string) error { return writeDependabotConfig(rootDir, dependabotConfig) } -func generateMkdocs(rootDir string, exampleLower string) error { +func generateMkdocs(rootDir string, example Example) error { // update examples in mkdocs mkdocsConfig, err := readMkdocsConfig(rootDir) if err != nil { return err } - mkdocsExamplesNav := mkdocsConfig.Nav[3].Examples + mkdocsExamplesNav := mkdocsConfig.Nav[4].Examples + if example.IsModule { + mkdocsExamplesNav = mkdocsConfig.Nav[3].Modules + } // make sure the index.md is the first element in the list of examples in the nav examplesNav := make([]string, len(mkdocsExamplesNav)-1) @@ -255,13 +302,17 @@ func generateMkdocs(rootDir string, exampleLower string) error { } } - examplesNav = append(examplesNav, "examples/"+exampleLower+".md") + examplesNav = append(examplesNav, example.ParentDir()+"/"+example.Lower()+".md") sort.Strings(examplesNav) // prepend the index.md file - examplesNav = append([]string{"examples/index.md"}, examplesNav...) + examplesNav = append([]string{example.ParentDir() + "/index.md"}, examplesNav...) - mkdocsConfig.Nav[3].Examples = examplesNav + if example.IsModule { + mkdocsConfig.Nav[3].Modules = examplesNav + } else { + mkdocsConfig.Nav[4].Examples = examplesNav + } return writeMkdocsConfig(rootDir, mkdocsConfig) } diff --git a/examples/main_test.go b/modulegen/main_test.go similarity index 61% rename from examples/main_test.go rename to modulegen/main_test.go index ca5f985bf4..44fb8c76a1 100644 --- a/examples/main_test.go +++ b/modulegen/main_test.go @@ -9,29 +9,72 @@ import ( "github.com/stretchr/testify/assert" ) -func TestExampleWithTitle(t *testing.T) { - t.Run("with title", func(t *testing.T) { - example := Example{ - Name: "mongoDB", - Image: "mongodb:latest", - TitleName: "MongoDB", - } - - assert.Equal(t, example.Lower(), "mongodb") - assert.Equal(t, example.Title(), "MongoDB") - assert.Equal(t, example.LowerTitle(), "mongoDB") - }) - - t.Run("without title", func(t *testing.T) { - example := Example{ - Name: "mongoDB", - Image: "mongodb:latest", - } +func TestExample(t *testing.T) { + tests := []struct { + name string + example Example + expectedContainerName string + expectedEntrypoint string + expectedTitle string + }{ + { + name: "Module with title", + example: Example{ + Name: "mongoDB", + IsModule: true, + Image: "mongodb:latest", + TitleName: "MongoDB", + }, + expectedContainerName: "MongoDBContainer", + expectedEntrypoint: "StartContainer", + expectedTitle: "MongoDB", + }, + { + name: "Module without title", + example: Example{ + Name: "mongoDB", + IsModule: true, + Image: "mongodb:latest", + }, + expectedContainerName: "MongodbContainer", + expectedEntrypoint: "StartContainer", + expectedTitle: "Mongodb", + }, + { + name: "Example with title", + example: Example{ + Name: "mongoDB", + IsModule: false, + Image: "mongodb:latest", + TitleName: "MongoDB", + }, + expectedContainerName: "mongoDBContainer", + expectedEntrypoint: "startContainer", + expectedTitle: "MongoDB", + }, + { + name: "Example without title", + example: Example{ + Name: "mongoDB", + IsModule: false, + Image: "mongodb:latest", + }, + expectedContainerName: "mongodbContainer", + expectedEntrypoint: "startContainer", + expectedTitle: "Mongodb", + }, + } - assert.Equal(t, example.Lower(), "mongodb") - assert.Equal(t, example.Title(), "Mongodb") - assert.Equal(t, example.LowerTitle(), "Mongodb") - }) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + example := test.example + + assert.Equal(t, "mongodb", example.Lower()) + assert.Equal(t, test.expectedTitle, example.Title()) + assert.Equal(t, test.expectedContainerName, example.ContainerName()) + assert.Equal(t, test.expectedEntrypoint, example.Entrypoint()) + }) + } } func TestGenerateWrongExampleName(t *testing.T) { @@ -149,6 +192,7 @@ func TestGenerate(t *testing.T) { example := Example{ Name: "foodb", TitleName: "FooDB", + IsModule: false, Image: "docker.io/example/foodb:latest", TCVersion: "v0.0.0-test", } @@ -192,6 +236,78 @@ func TestGenerate(t *testing.T) { assertDependabotExamplesUpdates(t, example, originalDependabotConfig, rootTmp) } +func TestGenerateModule(t *testing.T) { + rootTmp := t.TempDir() + modulesTmp := filepath.Join(rootTmp, "modules") + modulesDocTmp := filepath.Join(rootTmp, "docs", "modules") + githubWorkflowsTmp := filepath.Join(rootTmp, ".github", "workflows") + + err := os.MkdirAll(modulesTmp, 0777) + assert.Nil(t, err) + err = os.MkdirAll(modulesDocTmp, 0777) + assert.Nil(t, err) + err = os.MkdirAll(githubWorkflowsTmp, 0777) + assert.Nil(t, err) + + err = copyInitialMkdocsConfig(t, rootTmp) + assert.Nil(t, err) + + originalConfig, err := readMkdocsConfig(rootTmp) + assert.Nil(t, err) + + err = copyInitialDependabotConfig(t, rootTmp) + assert.Nil(t, err) + + originalDependabotConfig, err := readDependabotConfig(rootTmp) + assert.Nil(t, err) + + example := Example{ + Name: "foodb", + TitleName: "FooDB", + IsModule: true, + Image: "docker.io/example/foodb:latest", + TCVersion: "v0.0.0-test", + } + exampleNameLower := example.Lower() + + err = generate(example, rootTmp) + assert.Nil(t, err) + + templatesDir, err := os.ReadDir(filepath.Join(".", "_template")) + assert.Nil(t, err) + + exampleDirPath := filepath.Join(modulesTmp, exampleNameLower) + newExampleDir, err := os.ReadDir(exampleDirPath) + assert.Nil(t, err) + + exampleDirFileInfo, err := os.Stat(exampleDirPath) + assert.Nil(t, err) // error nil implies the file exist + assert.True(t, exampleDirFileInfo.IsDir()) + + exampleDocFile := filepath.Join(modulesDocTmp, exampleNameLower+".md") + _, err = os.Stat(exampleDocFile) + assert.Nil(t, err) // error nil implies the file exist + + exampleWorkflowFile := filepath.Join(githubWorkflowsTmp, "module-"+exampleNameLower+".yml") + _, err = os.Stat(exampleWorkflowFile) + assert.Nil(t, err) // error nil implies the file exist + + // check the number of template files is equal to examples + 2 (the doc and the github workflow) + assert.Equal(t, len(newExampleDir)+2, len(templatesDir)) + + assertExampleDocContent(t, example, exampleDocFile) + assertExampleGithubWorkflowContent(t, example, exampleWorkflowFile) + + generatedTemplatesDir := filepath.Join(modulesTmp, exampleNameLower) + assertExampleTestContent(t, example, filepath.Join(generatedTemplatesDir, exampleNameLower+"_test.go")) + assertExampleContent(t, example, filepath.Join(generatedTemplatesDir, exampleNameLower+".go")) + assertGoModContent(t, example, filepath.Join(generatedTemplatesDir, "go.mod")) + assertMakefileContent(t, example, filepath.Join(generatedTemplatesDir, "Makefile")) + assertToolsGoContent(t, example, filepath.Join(generatedTemplatesDir, "tools", "tools.go")) + assertMkdocsExamplesNav(t, example, originalConfig, rootTmp) + assertDependabotExamplesUpdates(t, example, originalDependabotConfig, rootTmp) +} + // assert content in the Examples nav from mkdocs.yml func assertDependabotExamplesUpdates(t *testing.T, example Example, originalConfig *DependabotConfig, rootDir string) { config, err := readDependabotConfig(rootDir) @@ -204,7 +320,7 @@ func assertDependabotExamplesUpdates(t *testing.T, example Example, originalConf // the example should be in the dependabot updates found := false for _, ex := range examples { - directory := "/examples/" + example.Lower() + directory := "/" + example.ParentDir() + "/" + example.Lower() if directory == ex.Directory { found = true } @@ -214,8 +330,8 @@ func assertDependabotExamplesUpdates(t *testing.T, example Example, originalConf // first item is the main module assert.Equal(t, "/", examples[0].Directory, examples) - // second item is the compose module - assert.Equal(t, "/modules/compose", examples[1].Directory, examples) + // second item is the modulegen module + assert.Equal(t, "/modulegen", examples[1].Directory, examples) } // assert content example file in the docs @@ -253,17 +369,18 @@ func assertExampleContent(t *testing.T, example Example, exampleFile string) { assert.Nil(t, err) lower := example.Lower() - lowerTitle := example.LowerTitle() + containerName := example.ContainerName() exampleName := example.Title() + entrypoint := example.Entrypoint() data := strings.Split(string(content), "\n") assert.Equal(t, data[0], "package "+lower) - assert.Equal(t, data[8], "// "+lowerTitle+"Container represents the "+exampleName+" container type used in the module") - assert.Equal(t, data[9], "type "+lowerTitle+"Container struct {") - assert.Equal(t, data[13], "// setup"+exampleName+" creates an instance of the "+exampleName+" container type") - assert.Equal(t, data[14], "func setup"+exampleName+"(ctx context.Context) (*"+lowerTitle+"Container, error) {") + assert.Equal(t, data[8], "// "+containerName+" represents the "+exampleName+" container type used in the module") + assert.Equal(t, data[9], "type "+containerName+" struct {") + assert.Equal(t, data[13], "// "+entrypoint+" creates an instance of the "+exampleName+" container type") + assert.Equal(t, data[14], "func "+entrypoint+"(ctx context.Context) (*"+containerName+", error) {") assert.Equal(t, data[16], "\t\tImage: \""+example.Image+"\",") - assert.Equal(t, data[26], "\treturn &"+lowerTitle+"Container{Container: container}, nil") + assert.Equal(t, data[26], "\treturn &"+containerName+"{Container: container}, nil") } // assert content GitHub workflow for the example @@ -274,8 +391,13 @@ func assertExampleGithubWorkflowContent(t *testing.T, example Example, exampleWo lower := example.Lower() title := example.Title() + exampleType := "example" + if example.IsModule { + exampleType = "module" + } + data := strings.Split(string(content), "\n") - assert.Equal(t, "name: "+title+" example pipeline", data[0]) + assert.Equal(t, "name: "+title+" "+exampleType+" pipeline", data[0]) assert.Equal(t, " test-"+lower+":", data[9]) assert.Equal(t, " go-version: ${{ matrix.go-version }}", data[19]) assert.Equal(t, " working-directory: ./examples/"+lower, data[26]) @@ -308,14 +430,21 @@ func assertMkdocsExamplesNav(t *testing.T, example Example, originalConfig *MkDo config, err := readMkdocsConfig(rootDir) assert.Nil(t, err) - examples := config.Nav[3].Examples + parentDir := example.ParentDir() + + examples := config.Nav[4].Examples + expectedEntries := originalConfig.Nav[4].Examples + if example.IsModule { + examples = config.Nav[3].Modules + expectedEntries = originalConfig.Nav[3].Modules + } - assert.Equal(t, len(originalConfig.Nav[3].Examples)+1, len(examples)) + assert.Equal(t, len(expectedEntries)+1, len(examples)) // the example should be in the nav found := false for _, ex := range examples { - markdownExample := "examples/" + example.Lower() + ".md" + markdownExample := example.ParentDir() + "/" + example.Lower() + ".md" if markdownExample == ex { found = true } @@ -324,7 +453,7 @@ func assertMkdocsExamplesNav(t *testing.T, example Example, originalConfig *MkDo assert.True(t, found) // first item is the index - assert.Equal(t, "examples/index.md", examples[0], examples) + assert.Equal(t, parentDir+"/index.md", examples[0], examples) } // assert content tools/tools.go diff --git a/examples/mkdocs.go b/modulegen/mkdocs.go similarity index 97% rename from examples/mkdocs.go rename to modulegen/mkdocs.go index 57a4b90d27..560924954b 100644 --- a/examples/mkdocs.go +++ b/modulegen/mkdocs.go @@ -32,6 +32,7 @@ type MkDocsConfig struct { Quickstart string `yaml:"Quickstart,omitempty"` Features []interface{} `yaml:"Features,omitempty"` Examples []string `yaml:"Examples,omitempty"` + Modules []string `yaml:"Modules,omitempty"` SystemRequirements []string `yaml:"System Requirements,omitempty"` Contributing []string `yaml:"Contributing,omitempty"` GettingHelp string `yaml:"Getting help,omitempty"` diff --git a/examples/mkdocs_test.go b/modulegen/mkdocs_test.go similarity index 93% rename from examples/mkdocs_test.go rename to modulegen/mkdocs_test.go index 38417f0631..40d0473ba6 100644 --- a/examples/mkdocs_test.go +++ b/modulegen/mkdocs_test.go @@ -53,7 +53,8 @@ func TestReadMkDocsConfig(t *testing.T) { nav := config.Nav assert.Equal(t, "index.md", nav[0].Home) assert.Greater(t, len(nav[2].Features), 0) - assert.Greater(t, len(nav[3].Examples), 0) + assert.Greater(t, len(nav[3].Modules), 0) + assert.Greater(t, len(nav[4].Examples), 0) } func TestExamples(t *testing.T) { @@ -63,7 +64,7 @@ func TestExamples(t *testing.T) { require.NoError(t, err) // we have to remove the index.md file from the examples docs - assert.Equal(t, len(examplesDocs)-2, len(examples)) + assert.Equal(t, len(examplesDocs)-1, len(examples)) // all example modules exist in the documentation for _, example := range examples { diff --git a/modulegen/tools/tools.go b/modulegen/tools/tools.go new file mode 100644 index 0000000000..724d23e17f --- /dev/null +++ b/modulegen/tools/tools.go @@ -0,0 +1,11 @@ +//go:build tools +// +build tools + +// This package contains the tool dependencies of the project. + +package tools + +import ( + // Register gotestsum for pinning version + _ "gotest.tools/gotestsum" +) diff --git a/modules/Makefile b/modules/Makefile new file mode 100644 index 0000000000..4de909017f --- /dev/null +++ b/modules/Makefile @@ -0,0 +1,9 @@ +include ../commons-test.mk + +.PHONY: dependencies-scan-modules +dependencies-scan-modules: + @find . -type f -name Makefile -execdir make dependencies-scan \; + +.PHONY: tidy-modules +tidy-modules: + @find . -type f -name Makefile -execdir make tools-tidy \;