Skip to content

Commit

Permalink
Add scripts; Refactor config
Browse files Browse the repository at this point in the history
  • Loading branch information
marcinhlybin committed Sep 20, 2024
1 parent b3e7595 commit d8068c0
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 114 deletions.
52 changes: 52 additions & 0 deletions addons/script.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package addons

import (
"fmt"
"os"
"os/exec"

"github.com/marcinhlybin/docker-env/logger"
)

type Script struct {
Name string
Path string
}

func NewScript(name, path string) *Script {
return &Script{
Name: name,
Path: path,
}
}

// Helper function to run a script
func RunScript(name, path string) error {
s := NewScript(name, path)
return s.Run()
}

func (s *Script) Run() error {
if s.Path == "" {
return nil
}

// Check if script exists
if _, err := os.Stat(s.Path); err != nil {
return fmt.Errorf("cannot open %s script '%s': %w", s.Name, s.Path, err)
}

logger.Info("Running", s.Name, "scripts")
return s.execute()
}

func (s *Script) execute() error {
cmd := exec.Command("/bin/sh", s.Path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("%s script failed: %w", s.Name, err)
}

return nil
}
2 changes: 1 addition & 1 deletion cmd/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func cleanupAction(c *cli.Context) error {
return err
}

logger.SetPrefix(reg.Config().Project)
logger.SetPrefix(reg.Config().ComposeProjectName)

return reg.Cleanup()
}
6 changes: 5 additions & 1 deletion cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ func NewRegistry(c *cli.Context) (*registry.DockerProjectRegistry, error) {
}

func NewConfig(c *cli.Context) (*config.Config, error) {
return config.NewConfig(c.String("config"))
cfg := config.NewConfig()
if err := cfg.LoadConfig(c.String("config")); err != nil {
return nil, err
}
return cfg, nil
}

func ExitWithErrorOnArgs(c *cli.Context) {
Expand Down
107 changes: 48 additions & 59 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,73 @@ import (

// Defaults for the config
var (
DefaultConfigPath = ".docker-env/config.yaml"
DefaultOverrideConfigPath = ".docker-env/config.override.yaml"
DefaultComposeFile = "docker-compose.yml"
DefaultComposeDefaultProfile = "app"
DefaultComposeSidecarProfile = "sidecar"
DefaultTerminalDefaultService = "app"
DefaultTerminalDefaultCommand = "/bin/bash"
DefaultVscodeDefaultService = "app"
DefaultVscodeDefaultDir = "/"
ConfigPath = ".docker-env/config.yaml"
OverrideConfigPath = ".docker-env/config.override.yaml"
)

type Config struct {
Project string `yaml:"project"`
Secrets []string `yaml:"secrets"`
EnvFiles []string `yaml:"env_files"`
Path string
ComposeProjectName string `yaml:"compose_project_name"`
ComposeFile string `yaml:"compose_file"`
ComposeDefaultProfile string `yaml:"compose_default_profile"`
ComposeSidecarProfile string `yaml:"compose_sidecar_profile"`
EnvFiles []string `yaml:"env_files"`
TerminalDefaultService string `yaml:"terminal_default_service"`
TerminalDefaultCommand string `yaml:"terminal_default_command"`
VscodeDefaultService string `yaml:"vscode_default_service"`
VscodeDefaultDir string `yaml:"vscode_default_dir"`
AwsLogin bool `yaml:"aws_login"`
AwsRegion string `yaml:"aws_region"`
AwsRepository string `yaml:"aws_repository"`
PreStartScript string `yaml:"pre_start_script"`
PostStartScript string `yaml:"post_start_script"`
PostStopScript string `yaml:"post_stop_script"`
Vars []string `yaml:"vars"`
}

// Read and parse the config file with fields validation
func NewConfig(path string) (*Config, error) {
var cfg Config
func NewConfig() *Config {
return &Config{
ComposeFile: "docker-compose.yml",
ComposeDefaultProfile: "app",
ComposeSidecarProfile: "sidecar",
EnvFiles: []string{},
TerminalDefaultService: "app",
TerminalDefaultCommand: "/bin/bash",
VscodeDefaultService: "app",
VscodeDefaultDir: "/",
PreStartScript: "",
PostStartScript: "",
PostStopScript: "",
Vars: []string{},
}
}

func (cfg *Config) LoadConfig(path string) error {
if path == "" {
path = DefaultConfigPath
path = ConfigPath
}

// Read main config file
if err := loadConfigFile(path, &cfg); err != nil {
return nil, err
if err := readConfigFile(path, cfg); err != nil {
return err
}

// Read override config file if it exists
overridePath := DefaultOverrideConfigPath
if _, err := os.Stat(overridePath); err == nil {
if err := loadConfigFile(overridePath, &cfg); err != nil {
return nil, err
if _, err := os.Stat(OverrideConfigPath); err == nil {
if err := readConfigFile(OverrideConfigPath, cfg); err != nil {
return err
}
}

setDefaults(&cfg)

// Validate config
if err := ValidateConfig(&cfg); err != nil {
return nil, fmt.Errorf("config validation failed: %w", err)
if err := cfg.validateConfig(); err != nil {
return fmt.Errorf("config validation failed: %w", err)
}

return &cfg, nil
return nil
}

func loadConfigFile(path string, cfg *Config) error {
func readConfigFile(path string, cfg *Config) error {
file, err := os.Open(path)
if err != nil {
return err
Expand All @@ -84,45 +92,26 @@ func loadConfigFile(path string, cfg *Config) error {
return nil
}

func setDefaults(cfg *Config) {
if cfg.ComposeFile == "" {
cfg.ComposeFile = DefaultComposeFile
}
if cfg.ComposeDefaultProfile == "" {
cfg.ComposeDefaultProfile = DefaultComposeDefaultProfile
}
if cfg.ComposeSidecarProfile == "" {
cfg.ComposeSidecarProfile = DefaultComposeSidecarProfile
}
if cfg.TerminalDefaultService == "" {
cfg.TerminalDefaultService = DefaultTerminalDefaultService
}
if cfg.TerminalDefaultCommand == "" {
cfg.TerminalDefaultCommand = DefaultTerminalDefaultCommand
}
if cfg.VscodeDefaultService == "" {
cfg.VscodeDefaultService = DefaultVscodeDefaultService
}
if cfg.VscodeDefaultDir == "" {
cfg.VscodeDefaultDir = DefaultVscodeDefaultDir
}
}

func (c *Config) ShowConfig() error {
fmt.Println("Project name:", c.Project)
fmt.Println("Mandatory secrets:", strings.Join(c.Secrets, ", "))
fmt.Println("Env files:", strings.Join(c.EnvFiles, ", "))
fmt.Println()
fmt.Println("Compose project name:", c.ComposeProjectName)
fmt.Println("Compose file:", c.ComposeFile)
fmt.Println("Compose default profile:", c.ComposeDefaultProfile)
fmt.Println("Compose sidecar profile:", c.ComposeSidecarProfile)
fmt.Println()
fmt.Println("Env files:", strings.Join(c.EnvFiles, ", "))
fmt.Println("Vars:", strings.Join(c.Vars, ", "))
fmt.Println()
fmt.Println("Pre-start script:", c.PreStartScript)
fmt.Println("Post-start script:", c.PostStartScript)
fmt.Println("Post-stop script:", c.PostStopScript)
fmt.Println()
fmt.Println("AWS login:", c.AwsLogin)
fmt.Println("AWS region:", c.AwsRegion)
fmt.Println("AWS repository:", c.AwsRepository)
fmt.Println()
fmt.Println("Terminal default service:", c.TerminalDefaultService)
fmt.Println("Terminal default command:", c.TerminalDefaultCommand)
fmt.Println("VSCode default service:", c.VscodeDefaultService)
fmt.Println("VSCode default directory:", c.VscodeDefaultDir)
fmt.Println("AWS login:", c.AwsLogin)
fmt.Println("AWS region:", c.AwsRegion)
fmt.Println("AWS repository:", c.AwsRepository)
return nil
}
75 changes: 34 additions & 41 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
package config_test

import (
"fmt"
"os"
"testing"

"github.com/marcinhlybin/docker-env/config"
"github.com/marcinhlybin/docker-env/test_helpers"
"github.com/stretchr/testify/assert"
)

func createTempConfigFile(t *testing.T, content string) string {
tmpfile, err := os.CreateTemp("", "config-*.yaml")
if err != nil {
t.Fatal(err)
}

if _, err := tmpfile.Write([]byte(content)); err != nil {
t.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
t.Fatal(err)
}

return tmpfile.Name()
}

func TestNewConfig_DefaultConfig(t *testing.T) {
configContent := `
project: test_project
secrets:
- secret1
- secret2
compose_project_name: test_project
vars:
- var1
- var2
env_files:
- .env
- %s
compose_file: docker-compose.yml
compose_default_profile: app
aws_login: true
aws_region: us-west-2
aws_repository: 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo
`
configPath := createTempConfigFile(t, configContent)
// Create temp env file
envFile := test_helpers.CreateTempFile(t, "var1=value1\nvar2=value")
defer os.Remove(envFile)

// Inject the env file path into the config content
configContent = fmt.Sprintf(configContent, envFile)

configPath := test_helpers.CreateTempFile(t, configContent)
defer os.Remove(configPath)

cfg, err := config.NewConfig(configPath)
cfg := config.NewConfig()
err := cfg.LoadConfig(configPath)

assert.NoError(t, err)
assert.Equal(t, "test_project", cfg.Project)
assert.Equal(t, []string{"secret1", "secret2"}, cfg.Secrets)
assert.Equal(t, []string{".env"}, cfg.EnvFiles)
assert.Equal(t, "test_project", cfg.ComposeProjectName)
assert.Equal(t, []string{"var1", "var2"}, cfg.Vars)
assert.Equal(t, 1, len(cfg.EnvFiles))
assert.Equal(t, "docker-compose.yml", cfg.ComposeFile)
assert.Equal(t, "app", cfg.ComposeDefaultProfile)
assert.True(t, cfg.AwsLogin)
Expand All @@ -55,49 +50,47 @@ aws_repository: 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo

func TestNewConfig_OverrideConfig(t *testing.T) {
configContent := `
project: test_project
secrets:
- secret1
- secret2
env_files:
- .env
compose_project_name: test_project
compose_file: docker-compose.yml
compose_default_profile: app
aws_login: true
aws_region: us-west-2
aws_repository: 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo
`
overrideContent := `
project: override_project
compose_project_name: override_project
aws_region: us-east-1
`
configPath := createTempConfigFile(t, configContent)
configPath := test_helpers.CreateTempFile(t, configContent)
defer os.Remove(configPath)

overridePath := createTempConfigFile(t, overrideContent)
overridePath := test_helpers.CreateTempFile(t, overrideContent)
defer os.Remove(overridePath)

// Temporarily override the default override config path
config.DefaultOverrideConfigPath = overridePath
config.OverrideConfigPath = overridePath

cfg, err := config.NewConfig(configPath)
cfg := config.NewConfig()
err := cfg.LoadConfig(configPath)
assert.NoError(t, err)
assert.Equal(t, "override_project", cfg.Project)
assert.Equal(t, "override_project", cfg.ComposeProjectName)
assert.Equal(t, "us-east-1", cfg.AwsRegion)
}

func TestNewConfig_MissingConfigFile(t *testing.T) {
_, err := config.NewConfig("nonexistent.yaml")
cfg := config.NewConfig()
err := cfg.LoadConfig("nonexistent.yaml")
assert.Error(t, err)
}

func TestNewConfig_InvalidConfigFile(t *testing.T) {
configContent := `
invalid_yaml_content
`
configPath := createTempConfigFile(t, configContent)
configPath := test_helpers.CreateTempFile(t, configContent)
defer os.Remove(configPath)

_, err := config.NewConfig(configPath)
cfg := config.NewConfig()
err := cfg.LoadConfig(configPath)
assert.Error(t, err)
}
Loading

0 comments on commit d8068c0

Please sign in to comment.