fix(docker-compose): extend YAML marshaler of service.dependsOn
The current implementation of the method DependsOnContainer.MarshalYAML() transform the short syntax into the long syntax. More about booth version types of depends_on is described here: - https://docs.docker.com/reference/compose-file/services/#short-syntax-1 - https://docs.docker.com/reference/compose-file/services/#long-syntax-1 Other applications are not compatible with the long syntax. For this reason the MarshalYAML method has been adapted to take care of the specific syntax. As documented of the long syntax, `depends_on.<dependency>.condition: service_started` is the same as `depends_on: [ 'dependency' ]`, the long syntax will be shortened when no other condition type of a dependency is specified.
This commit is contained in:
parent
ed7622a34f
commit
3c56ae6e5e
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
services:
|
||||
frontend:
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_started
|
||||
image: library/frontend:latest
|
@ -0,0 +1,3 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
@ -0,0 +1,7 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
||||
frontend:
|
||||
depends_on:
|
||||
- backend
|
||||
image: library/frontend:latest
|
@ -0,0 +1,5 @@
|
||||
services:
|
||||
frontend:
|
||||
depends_on:
|
||||
- backend
|
||||
image: library/frontend:latest
|
@ -0,0 +1,3 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
@ -0,0 +1,7 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
||||
frontend:
|
||||
depends_on:
|
||||
- backend
|
||||
image: library/frontend:latest
|
@ -0,0 +1,6 @@
|
||||
services:
|
||||
frontend:
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_completed_successfully
|
||||
image: library/frontend:latest
|
@ -0,0 +1,3 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
@ -0,0 +1,8 @@
|
||||
services:
|
||||
backend:
|
||||
image: library/backend:latest
|
||||
frontend:
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_completed_successfully
|
||||
image: library/frontend:latest
|
Loading…
x
Reference in New Issue
Block a user