From e2729c4381cc7c1e8ec363b4e6e04c502290e1aa Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Fri, 3 Mar 2023 11:51:46 -0500 Subject: [PATCH] Describe valid project name on error PR #261 changed `docker compose` behavior to require normalized project names as input, instead of normalizing project names automatically. This landed in compose-spec/compose-go v1.2.5 and docker/compose v2.5.1. However, the previous error message gave no indication why a name isn't valid. This is surprising for users whose previously working project names no longer work with newer versions of `docker compose`. As of compose-spec/compose-spec#314, the spec now contains the text: > Project name MUST contain only lowercase letters, decimal digits, > dashes, and underscores, and MUST begin with a lowercase letter or > decimal digit. This updated error message provides a concise version of this requirement based on regular expression character range notation. See also: - compose-spec/compose-spec#311 - docker/compose#9741 Signed-off-by: Mike Bland --- cli/options.go | 3 ++- cli/options_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/options.go b/cli/options.go index 3a3a7f59a..0fd3e9b82 100644 --- a/cli/options.go +++ b/cli/options.go @@ -65,7 +65,8 @@ func NewProjectOptions(configs []string, opts ...ProjectOptionsFn) (*ProjectOpti func WithName(name string) ProjectOptionsFn { return func(o *ProjectOptions) error { if name != loader.NormalizeProjectName(name) { - return fmt.Errorf("%q is not a valid project name", name) + return fmt.Errorf("%q is not a valid project name: it must contain " + + "only characters from [a-z0-9_-] and start with [a-z0-9]", name) } o.Name = name return nil diff --git a/cli/options_test.go b/cli/options_test.go index 7e41c77b5..65d2963b7 100644 --- a/cli/options_test.go +++ b/cli/options_test.go @@ -54,7 +54,7 @@ func TestProjectName(t *testing.T) { t.Run("by name start with invalid char '-'", func(t *testing.T) { _, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithName("-my_project")) - assert.Error(t, err, `"-my_project" is not a valid project name`) + assert.ErrorContains(t, err, `"-my_project" is not a valid project name`) opts, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithEnv([]string{ fmt.Sprintf("%s=%s", consts.ComposeProjectName, "-my_project"), @@ -67,7 +67,7 @@ func TestProjectName(t *testing.T) { t.Run("by name start with invalid char '_'", func(t *testing.T) { _, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithName("_my_project")) - assert.Error(t, err, `"_my_project" is not a valid project name`) + assert.ErrorContains(t, err, `"_my_project" is not a valid project name`) opts, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithEnv([]string{ fmt.Sprintf("%s=%s", consts.ComposeProjectName, "_my_project"), @@ -80,7 +80,7 @@ func TestProjectName(t *testing.T) { t.Run("by name contains dots", func(t *testing.T) { _, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithName("www.my.project")) - assert.Error(t, err, `"www.my.project" is not a valid project name`) + assert.ErrorContains(t, err, `"www.my.project" is not a valid project name`) opts, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithEnv([]string{ fmt.Sprintf("%s=%s", consts.ComposeProjectName, "www.my.project"), @@ -93,7 +93,7 @@ func TestProjectName(t *testing.T) { t.Run("by name uppercase", func(t *testing.T) { _, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithName("MY_PROJECT")) - assert.Error(t, err, `"MY_PROJECT" is not a valid project name`) + assert.ErrorContains(t, err, `"MY_PROJECT" is not a valid project name`) opts, err := NewProjectOptions([]string{"testdata/simple/compose.yaml"}, WithEnv([]string{ fmt.Sprintf("%s=%s", consts.ComposeProjectName, "_my_project"),