Fix command name collision on generator

When creating new commands via `cobra add`, it is not possible to add
commands with the same name to different parents. They will just
overwrite each other.

With this patch, the command's object identifier is templated
`parentCommandCmd`, the `Use` field `command` and the file name
`parent_command.go`.

Fixes #1059
Fixes #1131

Signed-off-by: Carlos Marx <me@carlosmarx.com>
This commit is contained in:
Carlos Marx 2021-07-08 11:14:40 -03:00
parent de187e874d
commit b45934648f
4 changed files with 83 additions and 12 deletions

View file

@ -46,9 +46,13 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
wd, err := os.Getwd()
cobra.CheckErr(err)
commandName := validateCmdName(args[0])
commandUse := validateCmdName(args[0])
commandName, commandFileName := generateCmdFileName(commandUse, parentName)
command := &Command{
CmdName: commandName,
CmdUse: commandUse,
CmdFileName: commandFileName,
CmdParent: parentName,
Project: &Project{
AbsolutePath: wd,
@ -122,3 +126,39 @@ func validateCmdName(source string) string {
}
return output
}
// generateCmdFileName returns a lowerCamelCase command name and a snake_case
// file name, combining the given command name and the parent command name.
func generateCmdFileName(cmd, parent string) (string, string) {
var cmdName string
var cmdFileName string
if parent == "rootCmd" {
return cmd, cmd
}
l := len(parent)
if parent[l-3:] == "Cmd" {
parent = parent[:l-3]
}
upperCmd := string(unicode.ToUpper(rune(cmd[0]))) + cmd[1:]
lowerParent := string(unicode.ToLower(rune(parent[0]))) + parent[1:]
cmdName = lowerParent + upperCmd
l = len(cmdName)
cmdFileName = string(cmdName[0])
for i := 1; i < l; i++ {
if unicode.IsUpper(rune(cmdName[i])) {
cmdFileName += "_"
}
cmdFileName += string(unicode.ToLower(rune(cmdName[i])))
}
l = len(cmdFileName)
if cmdFileName[l-5:] == "_test" {
cmdFileName += "cmd"
}
return cmdName, cmdFileName
}

View file

@ -9,6 +9,8 @@ import (
func TestGoldenAddCmd(t *testing.T) {
command := &Command{
CmdName: "test",
CmdUse: "test",
CmdFileName: "test",
CmdParent: parentName,
Project: getProject(),
}
@ -48,3 +50,30 @@ func TestValidateCmdName(t *testing.T) {
}
}
}
func TestGenerateCmdFileName(t *testing.T) {
testCases := []struct {
inputCmd string
inputParent string
expectedCmd string
expectedFile string
}{
{"cmdname", "parent", "parentCmdname", "parent_cmdname"},
{"cmdname", "parentCmd", "parentCmdname", "parent_cmdname"},
{"CmdName", "ParentCmd", "parentCmdName", "parent_cmd_name"},
{"cmdname", "granpaParentCmd", "granpaParentCmdname", "granpa_parent_cmdname"},
{"test", "granpaParentCmd", "granpaParentTest", "granpa_parent_testcmd"},
{"cmdname", "rootCmd", "cmdname", "cmdname"},
}
for _, testCase := range testCases {
got1, got2 := generateCmdFileName(testCase.inputCmd, testCase.inputParent)
if testCase.expectedCmd != got1 || testCase.expectedFile != got2 {
t.Errorf(
"Expected %q and %q, got %q and %q",
testCase.expectedCmd, testCase.expectedFile,
got1, got2,
)
}
}
}

View file

@ -22,6 +22,8 @@ type Project struct {
type Command struct {
CmdName string
CmdUse string
CmdFileName string
CmdParent string
*Project
}
@ -83,7 +85,7 @@ func (p *Project) createLicenseFile() error {
}
func (c *Command) Create() error {
cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdName))
cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdFileName))
if err != nil {
return err
}

View file

@ -113,9 +113,9 @@ import (
"github.com/spf13/cobra"
)
// {{ .CmdName }}Cmd represents the {{ .CmdName }} command
// {{ .CmdName }}Cmd represents the {{ .CmdUse }} command
var {{ .CmdName }}Cmd = &cobra.Command{
Use: "{{ .CmdName }}",
Use: "{{ .CmdUse }}",
Short: "A brief description of your command",
Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
@ -124,7 +124,7 @@ Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.` + "`" + `,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("{{ .CmdName }} called")
fmt.Println("{{ .CmdUse }} called")
},
}