Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate the project name when it's entered, fixes #514, fixes #86 #1147

Merged
merged 3 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/ddev/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,13 @@ func handleMainConfigArgs(cmd *cobra.Command, args []string, app *ddevapp.DdevAp
app.WebserverType = webserverTypeArg
}

provider, err := app.GetProvider()
util.CheckErr(err)
err = provider.ValidateField("Name", app.Name)
if err != nil {
return fmt.Errorf("failed to validate configuration: %v", err)
}

err = app.WriteConfig()
if err != nil {
return fmt.Errorf("could not write ddev config file %s: %v", app.ConfigPath, err)
Expand Down
45 changes: 45 additions & 0 deletions cmd/ddev/cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,48 @@ func TestConfigSetValues(t *testing.T) {
assert.Equal(uploadDir, app.UploadDir)
assert.Equal(webserverType, app.WebserverType)
}

// TestConfigInvalidProjectname tests to make sure that invalid projectnames
// are not accepted and valid names are accepted.
func TestConfigInvalidProjectname(t *testing.T) {
var err error
assert := asrt.New(t)

// Create a temporary directory and switch to it.
tmpdir := testcommon.CreateTmpDir(t.Name())
defer testcommon.CleanupDir(tmpdir)
defer testcommon.Chdir(tmpdir)()

// Create an existing docroot
docroot := "web"
if err = os.MkdirAll(filepath.Join(tmpdir, docroot), 0755); err != nil {
t.Errorf("Could not create docroot %s in %s", docroot, tmpdir)
}

// Test some valid project names
for _, projName := range []string{"no-spaces-but-hyphens", "UpperAndLower", "should.work.with.dots"} {
args := []string{
"config",
"--projectname", projName,
}

out, err := exec.RunCommand(DdevBin, args)
assert.NoError(err)
assert.NotContains(out, "is not a valid project name")
assert.Contains(out, "You may now run 'ddev start'")
}

// test some invalid project names.
for _, projName := range []string{"with spaces", "with_underscores", "no,commas-will-make-it"} {
args := []string{
"config",
"--projectname", projName,
}

out, err := exec.RunCommand(DdevBin, args)
assert.Error(err)
assert.Contains(out, fmt.Sprintf("%s is not a valid project name", projName))
assert.NotContains(out, "You may now run 'ddev start'")
}

}
9 changes: 3 additions & 6 deletions pkg/ddevapp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func (app *DdevApp) ValidateConfig() error {
// validate hostname
match := hostRegex.MatchString(app.GetHostname())
if !match {
return fmt.Errorf("%s is not a valid hostname. Please enter a site name in your configuration that will allow for a valid hostname. See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames for valid hostname requirements", app.GetHostname())
return fmt.Errorf("%s is not a valid hostname. Please enter a project name in your configuration that will allow for a valid hostname. See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames for valid hostname requirements", app.GetHostname())
}

// validate apptype
Expand Down Expand Up @@ -451,14 +451,13 @@ func (app *DdevApp) RenderComposeYAML() (string, error) {
return doc.String(), err
}

// Define an application name.
// prompt for a project name.
func (app *DdevApp) promptForName() error {
provider, err := app.GetProvider()
if err != nil {
return err
}

namePrompt := "Project name"
if app.Name == "" {
dir, err := os.Getwd()
// if working directory name is invalid for hostnames, we shouldn't suggest it
Expand All @@ -468,9 +467,7 @@ func (app *DdevApp) promptForName() error {
}
}

namePrompt = fmt.Sprintf("%s (%s)", namePrompt, app.Name)
fmt.Print(namePrompt + ": ")
app.Name = util.GetInput(app.Name)
app.Name = util.Prompt("Project name", app.Name)
return provider.ValidateField("Name", app.Name)
}

Expand Down
18 changes: 17 additions & 1 deletion pkg/ddevapp/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ func TestConfigCommand(t *testing.T) {
assert.Contains(out, testDir)
assert.Contains(out, fmt.Sprintf("'%s' is not a valid project type", invalidAppType))

// Create an example input buffer that writes an invalid projectname, then a valid-project-name,
// a valid document root,
// a valid app type
input = fmt.Sprintf("invalid_project_name\n%s\ndocroot\n%s", name, testValues[apptypePos])
scanner = bufio.NewScanner(strings.NewReader(input))
util.SetInputScanner(scanner)

restoreOutput = testcommon.CaptureUserOut()
err = app.PromptForConfig()
assert.NoError(err, t)
out = restoreOutput()

// Ensure we have expected vales in output.
assert.Contains(out, testDir)
assert.Contains(out, "invalid_project_name is not a valid project name")

// Ensure values were properly set on the app struct.
assert.Equal(name, app.Name)
assert.Equal(testValues[apptypePos], app.Type)
Expand Down Expand Up @@ -447,7 +463,7 @@ func TestValidate(t *testing.T) {

app.Name = "Invalid!"
err = app.ValidateConfig()
assert.EqualError(err, fmt.Sprintf("%s is not a valid hostname. Please enter a site name in your configuration that will allow for a valid hostname. See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames for valid hostname requirements", app.GetHostname()))
assert.EqualError(err, fmt.Sprintf("%s is not a valid hostname. Please enter a project name in your configuration that will allow for a valid hostname. See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames for valid hostname requirements", app.GetHostname()))

app.Docroot = "testdata"
app.Name = "valid"
Expand Down
13 changes: 12 additions & 1 deletion pkg/ddevapp/providerDefault.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package ddevapp

import "os"
import (
"fmt"
"os"
)

// DefaultProvider provides a no-op for the provider plugin interface methods.
type DefaultProvider struct{}
Expand All @@ -12,6 +15,14 @@ func (p *DefaultProvider) Init(app *DdevApp) error {

// ValidateField provides a no-op for the ValidateField operation.
func (p *DefaultProvider) ValidateField(field, value string) error {
if field == "Name" {
// validate project name
match := hostRegex.MatchString(value)
if !match {
return fmt.Errorf("%s is not a valid project name. Please enter a project name in your configuration that will allow for a valid hostname. See https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames for valid hostname requirements", value)
}

}
return nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
)

// RunCommand runs a command on the host system.
// returns the stdout of the command and an err
func RunCommand(command string, args []string) (string, error) {
output.UserOut.WithFields(log.Fields{
"Command": command + " " + strings.Join(args[:], " "),
Expand Down