Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
336225b
chore: bring back dependabot generation
mdelapenya Feb 25, 2025
15ef34b
chore: replace assert with require
mdelapenya Feb 26, 2025
854a005
feat: add a modulegen command to refresh the project files
mdelapenya Feb 26, 2025
96d2fb6
chore: exclude compose from the mkdocs nav entries
mdelapenya Feb 26, 2025
39c813e
fix: remove extra comma after refresh
mdelapenya Feb 26, 2025
79668fb
chore: readd dependabot updates
mdelapenya Feb 26, 2025
ef5785d
fix: lint
mdelapenya Feb 26, 2025
3147018
chore: wrap errors in dependabot files
mdelapenya Feb 26, 2025
12edc06
docs: document new types and functions
mdelapenya Feb 26, 2025
3242f71
chore: simplify types merging generator and refresher
mdelapenya Feb 26, 2025
4876835
chore: include modulegen in dependabot
mdelapenya Feb 26, 2025
96c282f
chore: check modulegen is included in the dependabot updates
mdelapenya Feb 26, 2025
25a1dce
docs: document new command
mdelapenya Feb 26, 2025
aff348c
chore: exclude dependabot changes from the build pipeline
mdelapenya Feb 26, 2025
b28f115
fix: lint
mdelapenya Feb 26, 2025
43a4884
chore: wrap errors and add docs
mdelapenya Feb 26, 2025
e6d1327
chore: simplify dependabot config to use directories instead of one e…
mdelapenya Feb 27, 2025
50185af
chore: use filepath
mdelapenya Feb 27, 2025
05062d8
chore: more wrap errors
mdelapenya Feb 27, 2025
bfedc43
docs: be explicit
mdelapenya Feb 27, 2025
aeadc83
chore: more filepaths to fix WIndows tests
mdelapenya Feb 27, 2025
aadeaac
fix: module path uses slashes
mdelapenya Feb 27, 2025
9064bdf
fix: test
mdelapenya Feb 27, 2025
d061059
chore: dependabot must follow unix file path separator
mdelapenya Feb 27, 2025
f703bde
Merge branch 'main' into bring-back-dependabot
mdelapenya Mar 5, 2025
29cb0fa
Merge branch 'main' into bring-back-dependabot
mdelapenya Mar 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,72 @@ updates:
day: sunday
open-pull-requests-limit: 3
rebase-strategy: disabled
- package-ecosystem: gomod
directories:
- /
- /examples/nginx
- /examples/toxiproxy
- /modulegen
- /modules/artemis
- /modules/azurite
- /modules/cassandra
- /modules/chroma
- /modules/clickhouse
- /modules/cockroachdb
- /modules/compose
- /modules/consul
- /modules/couchbase
- /modules/databend
- /modules/dind
- /modules/dolt
- /modules/dynamodb
- /modules/elasticsearch
- /modules/etcd
- /modules/gcloud
- /modules/grafana-lgtm
- /modules/inbucket
- /modules/influxdb
- /modules/k3s
- /modules/k6
- /modules/kafka
- /modules/localstack
- /modules/mariadb
- /modules/meilisearch
- /modules/milvus
- /modules/minio
- /modules/mockserver
- /modules/mongodb
- /modules/mssql
- /modules/mysql
- /modules/nats
- /modules/neo4j
- /modules/ollama
- /modules/openfga
- /modules/openldap
- /modules/opensearch
- /modules/pinecone
- /modules/postgres
- /modules/pulsar
- /modules/qdrant
- /modules/rabbitmq
- /modules/redis
- /modules/redpanda
- /modules/registry
- /modules/scylladb
- /modules/surrealdb
- /modules/valkey
- /modules/vault
- /modules/vearch
- /modules/weaviate
- /modules/yugabytedb
schedule:
interval: monthly
day: sunday
open-pull-requests-limit: 3
rebase-strategy: disabled
- package-ecosystem: pip
directory: /
directories:
- /
schedule:
interval: monthly
day: sunday
Expand Down
18 changes: 18 additions & 0 deletions docs/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ $ cd modules
$ make tidy-examples
```

## Refreshing the modules

To refresh the modules, please run:

```shell
$ cd modulegen
$ go run . refresh
```

This command recreates all the project files for the modules and examples, including:

- the mkdocs.yml file, including all the modules and examples, excluding the `compose` module, as it has its own docs page.
- the dependabot config file, including all the modules, the examples and the modulegen module.
- the VSCode project file, including all the modules, the examples and the modulegen module.
- the Sonar properties file, including all the modules, the examples and the modulegen module.

Executing this command in a well-known state of the project, must not produce any changes in the project files.

## Interested in converting an example into a module?

The steps to convert an existing example, aka `${THE_EXAMPLE}`, into a module are the following:
Expand Down
24 changes: 24 additions & 0 deletions modulegen/cmd/modules/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package modules

import (
"fmt"

"github.com/spf13/cobra"

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

Expand All @@ -14,6 +17,27 @@ var NewCmd = &cobra.Command{
Long: "Create a new Example or Module",
}

var RefreshModulesCmd = &cobra.Command{
Use: "refresh",
Short: "Refresh the module and example files",
Long: "Refresh the module and example files, including the dependabot config, mkdocs config, sonar properties, vscode settings and makefiles for all the modules and examples",
RunE: func(_ *cobra.Command, _ []string) error {
ctx, err := context.GetRootContext()
if err != nil {
return fmt.Errorf(">> could not get the root dir: %w", err)
}

if err := internal.Refresh(ctx); err != nil {
return fmt.Errorf(">> could not refresh the modules: %w", err)
}

fmt.Println("Modules and examples refreshed.")
fmt.Println("🙏 Commit the modified files and submit a pull request to include them into the project.")
fmt.Println("Thanks!")
return nil
},
}

func init() {
NewCmd.AddCommand(newExampleCmd)
NewCmd.AddCommand(newModuleCmd)
Expand Down
1 change: 1 addition & 0 deletions modulegen/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ var NewRootCmd = &cobra.Command{

func init() {
NewRootCmd.AddCommand(modules.NewCmd)
NewRootCmd.AddCommand(modules.RefreshModulesCmd)
}
18 changes: 0 additions & 18 deletions modulegen/context_test.go

This file was deleted.

71 changes: 71 additions & 0 deletions modulegen/dependabot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

import (
"os"
"path/filepath"
"slices"
"strings"
"testing"

"github.com/stretchr/testify/require"

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

func TestGetDependabotConfigFile(t *testing.T) {
ctx := context.New(filepath.Join(t.TempDir(), "testcontainers-go"))

githubDir := ctx.GithubDir()
cfgFile := ctx.DependabotConfigFile()
err := os.MkdirAll(githubDir, 0o777)
require.NoError(t, err)

err = os.WriteFile(cfgFile, []byte{}, 0o777)
require.NoError(t, err)

file := ctx.DependabotConfigFile()
require.NotNil(t, file)

require.True(t, strings.HasSuffix(file, filepath.Join("testcontainers-go", ".github", "dependabot.yml")))
}

func TestExamplesHasDependabotEntry(t *testing.T) {
testProject := copyInitialProject(t)

examples, err := testProject.ctx.GetExamples()
require.NoError(t, err)
dependabotUpdates, err := dependabot.GetUpdates(testProject.ctx.DependabotConfigFile())
require.NoError(t, err)

// should be the second item in the updates
gomodUpdate := dependabotUpdates[1]

require.Equal(t, "monthly", gomodUpdate.Schedule.Interval)

// all example modules exist in the dependabot updates
for _, example := range examples {
dependabotDir := "/examples/" + example
require.True(t, slices.Contains(gomodUpdate.Directories, dependabotDir), "example %s is not present in the dependabot updates", example)
}
}

func TestModulesHasDependabotEntry(t *testing.T) {
testProject := copyInitialProject(t)

modules, err := testProject.ctx.GetModules()
require.NoError(t, err)
dependabotUpdates, err := dependabot.GetUpdates(testProject.ctx.DependabotConfigFile())
require.NoError(t, err)

// should be the second item in the updates
gomodUpdate := dependabotUpdates[1]

require.Equal(t, "monthly", gomodUpdate.Schedule.Interval)

// all modules exist in the dependabot updates
for _, module := range modules {
dependabotDir := "/modules/" + module
require.True(t, slices.Contains(gomodUpdate.Directories, dependabotDir), "module %s is not present in the dependabot updates", module)
}
}
11 changes: 9 additions & 2 deletions modulegen/internal/context/cmd.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package context

// TestcontainersModuleVar is a struct that contains the name, title and image of a testcontainers module.
// It's used to hold the input values from the command line.
type TestcontainersModuleVar struct {
Name string
// Name is the name of the module.
Name string

// NameTitle is the title of the module.
NameTitle string
Image string

// Image is the image of the module.
Image string
}
50 changes: 50 additions & 0 deletions modulegen/internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,61 @@ import (
"sort"
)

// Context is the context for the module generation.
// It provides the necessary information to generate the module or example,
// such as the different paths to the files and directories.
type Context struct {
RootDir string
}

// DependabotConfigFile returns, from the root directory, the relative path
// to the dependabot config file, "/.github/dependabot.yml".
func (ctx Context) DependabotConfigFile() string {
return filepath.Join(ctx.GithubDir(), "dependabot.yml")
}

// DocsDir returns, from the root directory, the relative path to the docs directory, "/docs".
func (ctx Context) DocsDir() string {
return filepath.Join(ctx.RootDir, "docs")
}

// ExamplesDir returns, from the root directory, the relative path to the examples directory, "/examples".
func (ctx Context) ExamplesDir() string {
return filepath.Join(ctx.RootDir, "examples")
}

// ExamplesDocsDir returns, from the docs directory, the relative path to the examples directory, "/docs/examples".
func (ctx Context) ExamplesDocsDir() string {
return filepath.Join(ctx.DocsDir(), "examples")
}

// ModulesDir returns, from the root directory, the relative path to the modules directory, "/modules".
func (ctx Context) ModulesDir() string {
return filepath.Join(ctx.RootDir, "modules")
}

// ModulesDocsDir returns, from the docs directory, the relative path to the modules directory, "/docs/modules".
func (ctx Context) ModulesDocsDir() string {
return filepath.Join(ctx.DocsDir(), "modules")
}

// GithubDir returns, from the root directory, the relative path to the github directory, "/.github".
func (ctx Context) GithubDir() string {
return filepath.Join(ctx.RootDir, ".github")
}

// GithubWorkflowsDir returns, from the github directory, the relative path to the workflows directory, "/.github/workflows".
func (ctx Context) GithubWorkflowsDir() string {
return filepath.Join(ctx.GithubDir(), "workflows")
}

// GoModFile returns, from the root directory, the relative path to the go.mod file, "/go.mod".
func (ctx Context) GoModFile() string {
return filepath.Join(ctx.RootDir, "go.mod")
}

// getModulesByBaseDir returns, from the root directory, the relative paths to the modules or examples,
// depending on the base directory.
func (ctx Context) getModulesByBaseDir(baseDir string) ([]string, error) {
dir := filepath.Join(ctx.RootDir, baseDir)

Expand All @@ -45,6 +80,8 @@ func (ctx Context) getModulesByBaseDir(baseDir string) ([]string, error) {
return dirs, nil
}

// getMarkdownsFromDir returns, from the docs directory, the relative paths to the markdown files,
// depending on the base directory.
func (ctx Context) getMarkdownsFromDir(baseDir string) ([]string, error) {
dir := filepath.Join(ctx.DocsDir(), baseDir)

Expand All @@ -64,38 +101,51 @@ func (ctx Context) getMarkdownsFromDir(baseDir string) ([]string, error) {
return dirs, nil
}

// GetExamples returns, from the root directory, a slice with the names of the examples
// that are located in the "examples" directory.
func (ctx Context) GetExamples() ([]string, error) {
return ctx.getModulesByBaseDir("examples")
}

// GetModules returns, from the root directory, a slice with the names of the modules
// that are located in the "modules" directory.
func (ctx Context) GetModules() ([]string, error) {
return ctx.getModulesByBaseDir("modules")
}

// GetExamplesDocs returns, from the docs directory, a slice with the names of the markdown files
// that are located in the "docs/examples" directory.
func (ctx Context) GetExamplesDocs() ([]string, error) {
return ctx.getMarkdownsFromDir("examples")
}

// GetModulesDocs returns, from the docs directory, a slice with the names of the markdown files
// that are located in the "docs/modules" directory.
func (ctx Context) GetModulesDocs() ([]string, error) {
return ctx.getMarkdownsFromDir("modules")
}

// MkdocsConfigFile returns, from the root directory, the relative path to the mkdocs config file, "/mkdocs.yml".
func (ctx Context) MkdocsConfigFile() string {
return filepath.Join(ctx.RootDir, "mkdocs.yml")
}

// SonarProjectFile returns, from the root directory, the relative path to the sonar project file, "/sonar-project.properties".
func (ctx Context) SonarProjectFile() string {
return filepath.Join(ctx.RootDir, "sonar-project.properties")
}

// VSCodeWorkspaceFile returns, from the root directory, the relative path to the vscode workspace file, "/.vscode/.testcontainers-go.code-workspace".
func (ctx Context) VSCodeWorkspaceFile() string {
return filepath.Join(ctx.RootDir, ".vscode", ".testcontainers-go.code-workspace")
}

// New returns a new Context with the given root directory.
func New(dir string) Context {
return Context{RootDir: dir}
}

// GetRootContext returns a new Context with the current working directory.
func GetRootContext() (Context, error) {
current, err := os.Getwd()
if err != nil {
Expand Down
Loading
Loading