feat: validate remaining unsupported items of the support-matrix (#429)

* feat: validate remaining unsupported items of the support-matrix

Validate unsupported compose features: external configs, container_name,
and placement.

This makes the code match the support-matrix as of now (added comment to
that effect as well).

Signed-off-by: Miek Gieben <miek@miek.nl>

* support matrix: some deploy modes are supported

Add tests for the various non-supported deploy modes.
Prefix the warnings with `deploy ` to signal the section, and to
differentiate between top level 'labels' and 'deploy labels'.

Signed-off-by: Miek Gieben <miek@miek.nl>

---------

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben authored and GitHub committed 2026-09-04 10:40:03 +10:00
1 parent 1c29d4d5d0
commit aaf67687d2
2 files changed
+113 -5

No files matched your search

+40 -5
View File
@@ -454,13 +454,22 @@ func validateServicesExtensions(project *types.Project) error {
// validateServicesFeatures checks services for unsupported features and returns all found.
func validateServicesFeatures(project *types.Project) []error {
err := func(service, feature string) error {
return fmt.Errorf("service '%s': unsupported feature '%s', see %s",
service, feature, "https://uncloud.run/docs/compose-file-reference/support-matrix")
// XXX(miek): as of Sep 2026 these checks are in check with the support-matrix, except for a short syntax
// check.
var errs []error
const supportmatrix = "https://uncloud.run/docs/compose-file-reference/support-matrix"
for _, config := range project.Configs {
if config.External {
errs = append(errs, fmt.Errorf("config '%s': unsupported feature '%s', see %s",
config.Name, "external", supportmatrix))
}
}
// TODO: check other commonly used but unsupported features.
var errs []error
err := func(service, feature string) error {
return fmt.Errorf("service '%s': unsupported feature '%s', see %s",
service, feature, supportmatrix)
}
for _, service := range project.Services {
if service.SecurityOpt != nil {
errs = append(errs, err(service.Name, "security_opt"))
@@ -489,6 +498,32 @@ func validateServicesFeatures(project *types.Project) []error {
if service.StorageOpt != nil {
errs = append(errs, err(service.Name, "storage_opt"))
}
if service.ContainerName != "" {
errs = append(errs, err(service.Name, "container_name"))
}
if service.Deploy != nil {
if len(service.Deploy.Placement.Constraints) > 0 || len(service.Deploy.Placement.Preferences) > 0 {
errs = append(errs, fmt.Errorf(
"service '%s': deploy placement is not supported, "+
"use x-machines instead: %s", service.Name,
"https://uncloud.run/docs/compose-file-reference/extensions#x-machines"))
}
if service.Deploy.RestartPolicy != nil {
errs = append(errs, fmt.Errorf(
"service '%s': deploy restart_policy defaults to 'unless-stopped'", service.Name))
}
if service.Deploy.Mode != "" && service.Deploy.Mode != "global" && service.Deploy.Mode != "replicated" {
errs = append(errs, fmt.Errorf(
"service '%s': deploy mode must either be 'global' or 'replicated'", service.Name))
}
if service.Deploy.RollbackConfig != nil {
errs = append(errs, err(service.Name, "deploy rollback_config"))
}
if len(service.Deploy.Labels) != 0 {
errs = append(errs, err(service.Name, "deploy labels"))
}
}
// we only allow the 'default' network, nothing else.
if x := service.Networks; x != nil {
if len(x) != 1 {