diff --git a/pkg/domain/dockerCompose/config.go b/pkg/domain/dockerCompose/config.go index 946b672..706942f 100644 --- a/pkg/domain/dockerCompose/config.go +++ b/pkg/domain/dockerCompose/config.go @@ -71,24 +71,36 @@ func (c *Config) ExistsVolume(name string) bool { func (c *Config) Merge(config *Config) { for name, network := range config.Networks { if !c.ExistsNetwork(name) { + if c.Networks == nil { + c.Networks = make(map[string]*Network) + } c.Networks[name] = network } } for name, secret := range config.Secrets { if !c.ExistsSecret(name) { + if c.Secrets == nil { + c.Secrets = make(map[string]*Secret) + } c.Secrets[name] = secret } } for name, service := range config.Services { if !c.ExistsService(name) { + if c.Services == nil { + c.Services = make(map[string]*Service) + } c.Services[name] = service } } for name, volume := range config.Volumes { if !c.ExistsVolume(name) { + if c.Volumes == nil { + c.Volumes = make(map[string]*Volume) + } c.Volumes[name] = volume } } @@ -1242,7 +1254,11 @@ func (s *Service) SetVolume(src string, dest string, perm string) { } } -const ServiceDependsOnConditionServiceStarted string = "service_started" +const ( + ServiceDependsOnConditionServiceCompletedSuccessfully string = "service_completed_successfully" + ServiceDependsOnConditionServiceHealthy string = "service_healthy" + ServiceDependsOnConditionServiceStarted string = "service_started" +) // DependsOnContainer is a wrapper to handle different YAML type formats of DependsOn. type DependsOnContainer struct { @@ -1272,7 +1288,25 @@ func (sdoc *DependsOnContainer) Equal(equalable Equalable) bool { // MarshalYAML implements the MarshalYAML interface to customize the behavior when being marshaled into a YAML document. func (sdoc *DependsOnContainer) MarshalYAML() (interface{}, error) { - return sdoc.DependsOn, nil + var foundAnotherCondition bool = false + var dependencyNames []string + + for dependencyName, dependencyDefinition := range sdoc.DependsOn { + if dependencyDefinition.Condition == ServiceDependsOnConditionServiceStarted { + dependencyNames = append(dependencyNames, dependencyName) + continue + } + foundAnotherCondition = true + } + + switch { + case foundAnotherCondition: + return sdoc.DependsOn, nil + case !foundAnotherCondition && len(dependencyNames) > 0: + return dependencyNames, nil + default: + return nil, nil + } } // UnmarshalYAML implements the UnmarshalYAML interface to customize the behavior when being unmarshaled into a YAML diff --git a/pkg/domain/dockerCompose/config_test.go b/pkg/domain/dockerCompose/config_test.go index d949f3b..3f0e210 100644 --- a/pkg/domain/dockerCompose/config_test.go +++ b/pkg/domain/dockerCompose/config_test.go @@ -1,12 +1,90 @@ package dockerCompose_test import ( + "bytes" + "embed" + "strings" "testing" "git.cryptic.systems/volker.raschek/dcmerge/pkg/domain/dockerCompose" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" ) +//go:embed test/assets/merge +var testAssetsMerge embed.FS + +func TestConfig_Merge(t *testing.T) { + require := require.New(t) + + testAssetPath := "test/assets/merge" + + testAssetMergeDirEntries, err := testAssetsMerge.ReadDir(testAssetPath) + require.NoError(err) + + // iterate over testcase directories + for i, mergeDirEntry := range testAssetMergeDirEntries { + if !mergeDirEntry.IsDir() { + continue + } + + // iterate over files in testcase directories + testCaseAssetPath := testAssetPath + "/" + mergeDirEntry.Name() + testCaseDirEntries, err := testAssetsMerge.ReadDir(testCaseAssetPath) + require.NoError(err) + + expectedDockerComposeConfig := &dockerCompose.Config{} + dockerComposeConfigs := []*dockerCompose.Config{} + for _, testCaseDirEntry := range testCaseDirEntries { + if testCaseDirEntry.IsDir() { + continue + } + + dockerComposeConfigFile := testAssetPath + "/" + mergeDirEntry.Name() + "/" + testCaseDirEntry.Name() + b, err := testAssetsMerge.ReadFile(dockerComposeConfigFile) + require.NoError(err) + yamlDecoder := yaml.NewDecoder(bytes.NewReader(b)) + + switch { + case strings.HasPrefix(testCaseDirEntry.Name(), "expectedResult"): + err = yamlDecoder.Decode(expectedDockerComposeConfig) + require.NoError(err) + case strings.HasSuffix(testCaseDirEntry.Name(), ".yml") || strings.HasSuffix(testCaseDirEntry.Name(), ".yaml"): + dockerComposeConfig := &dockerCompose.Config{} + err = yamlDecoder.Decode(dockerComposeConfig) + require.NoError(err) + dockerComposeConfigs = append(dockerComposeConfigs, dockerComposeConfig) + } + } + + actualDockerComposeConfig := &dockerCompose.Config{} + for _, dockerComposeConfig := range dockerComposeConfigs { + actualDockerComposeConfig.Merge(dockerComposeConfig) + } + + expectedBytes := make([]byte, 0) + expectedBytesBuffer := bytes.NewBuffer(expectedBytes) + yamlEncoder := yaml.NewEncoder(expectedBytesBuffer) + err = yamlEncoder.Encode(expectedDockerComposeConfig) + require.NoError(err) + + err = yamlEncoder.Close() + require.NoError(err) + + actualBytes := make([]byte, 0) + actualBytesBuffer := bytes.NewBuffer(actualBytes) + yamlEncoder = yaml.NewEncoder(actualBytesBuffer) + err = yamlEncoder.Encode(actualDockerComposeConfig) + require.NoError(err) + + err = yamlEncoder.Close() + require.NoError(err) + + require.Equal(expectedBytesBuffer.String(), actualBytesBuffer.String(), "TestCase %v", i) + } + +} + func TestNetwork_Equal(t *testing.T) { require := require.New(t) diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-000.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-000.yml new file mode 100644 index 0000000..ddd6508 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-000.yml @@ -0,0 +1,6 @@ +services: + frontend: + depends_on: + backend: + condition: service_started + image: library/frontend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-001.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-001.yml new file mode 100644 index 0000000..eb2f6e0 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase000/docker-compose-001.yml @@ -0,0 +1,3 @@ +services: + backend: + image: library/backend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase000/expectedResult.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase000/expectedResult.yml new file mode 100644 index 0000000..24ae550 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase000/expectedResult.yml @@ -0,0 +1,7 @@ +services: + backend: + image: library/backend:latest + frontend: + depends_on: + - backend + image: library/frontend:latest diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-000.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-000.yml new file mode 100644 index 0000000..b21e0bd --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-000.yml @@ -0,0 +1,5 @@ +services: + frontend: + depends_on: + - backend + image: library/frontend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-001.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-001.yml new file mode 100644 index 0000000..eb2f6e0 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase001/docker-compose-001.yml @@ -0,0 +1,3 @@ +services: + backend: + image: library/backend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase001/expectedResult.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase001/expectedResult.yml new file mode 100644 index 0000000..24ae550 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase001/expectedResult.yml @@ -0,0 +1,7 @@ +services: + backend: + image: library/backend:latest + frontend: + depends_on: + - backend + image: library/frontend:latest diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-000.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-000.yml new file mode 100644 index 0000000..837e5d2 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-000.yml @@ -0,0 +1,6 @@ +services: + frontend: + depends_on: + backend: + condition: service_completed_successfully + image: library/frontend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-001.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-001.yml new file mode 100644 index 0000000..eb2f6e0 --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase002/docker-compose-001.yml @@ -0,0 +1,3 @@ +services: + backend: + image: library/backend:latest \ No newline at end of file diff --git a/pkg/domain/dockerCompose/test/assets/merge/testcase002/expectedResult.yml b/pkg/domain/dockerCompose/test/assets/merge/testcase002/expectedResult.yml new file mode 100644 index 0000000..72499ac --- /dev/null +++ b/pkg/domain/dockerCompose/test/assets/merge/testcase002/expectedResult.yml @@ -0,0 +1,8 @@ +services: + backend: + image: library/backend:latest + frontend: + depends_on: + backend: + condition: service_completed_successfully + image: library/frontend:latest diff --git a/pkg/domain/dockerCompose/test/assets/mergeExistingWin/.gitkeep b/pkg/domain/dockerCompose/test/assets/mergeExistingWin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pkg/domain/dockerCompose/test/assets/mergeLastWin/.gitkeep b/pkg/domain/dockerCompose/test/assets/mergeLastWin/.gitkeep new file mode 100644 index 0000000..e69de29