diff --git a/cmd/agent.go b/cmd/agent.go index e753adee..c72884bb 100644 --- a/cmd/agent.go +++ b/cmd/agent.go @@ -369,8 +369,8 @@ func getAgentList(logger logger.Logger, apiUrl string, apikey string, project pr return remoteAgents, err } -func normalAgentName(name string) string { - return util.SafeFilename(strings.ToLower(name)) +func normalAgentName(name string, isPython bool) string { + return util.SafeProjectFilename(strings.ToLower(name), isPython) } func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string, apikey string, theproject project.ProjectContext) ([]string, map[string]agentListState) { @@ -395,7 +395,8 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string, fileAgents := make(map[string]project.AgentConfig) fileAgentsByID := make(map[string]project.AgentConfig) for _, agent := range theproject.Project.Agents { - fileAgents[normalAgentName(agent.Name)] = agent + key := normalAgentName(agent.Name, theproject.Project.IsPython()) + fileAgents[key] = agent fileAgentsByID[agent.ID] = agent } @@ -405,10 +406,11 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string, // perform the reconcilation state := make(map[string]agentListState) for _, agent := range remoteAgents { - state[normalAgentName(agent.Name)] = agentListState{ + key := normalAgentName(agent.Name, theproject.Project.IsPython()) + state[key] = agentListState{ Agent: &agent, - Filename: filepath.Join(agentSrcDir, util.SafeFilename(agent.Name), agentFilename), - FoundLocal: util.Exists(filepath.Join(agentSrcDir, util.SafeFilename(agent.Name), agentFilename)), + Filename: filepath.Join(agentSrcDir, key, agentFilename), + FoundLocal: util.Exists(filepath.Join(agentSrcDir, key, agentFilename)), FoundRemote: true, } } @@ -418,7 +420,7 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string, } for _, filename := range localAgents { agentName := filepath.Base(filepath.Dir(filename)) - key := normalAgentName(agentName) + key := normalAgentName(agentName, theproject.Project.IsPython()) // var found bool // for _, agent := range remoteAgents { // if localAgent, ok := fileAgentsByID[agent.ID]; ok { diff --git a/cmd/profile.go b/cmd/profile.go index da3582ee..7d13d283 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -154,7 +154,7 @@ Examples: } return nil }) - fp := filepath.Join(filepath.Dir(cfgFile), util.SafeFilename(name)+".yaml") + fp := filepath.Join(filepath.Dir(cfgFile), util.SafeProjectFilename(name, false)+".yaml") os.WriteFile(fp, []byte(fmt.Sprintf(`name: "%s"`, name)+"\n"), 0644) }, } diff --git a/cmd/project.go b/cmd/project.go index d9b27747..86f2e22a 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -481,7 +481,7 @@ Examples: provider = resp.Provider } } - projectDir := filepath.Join(cwd, util.SafeFilename(name)) + projectDir := filepath.Join(cwd, util.SafeProjectFilename(name, provider.Language == "python")) dir, _ := cmd.Flags().GetString("dir") if dir != "" { absDir, err := filepath.Abs(dir) diff --git a/internal/bundler/bundler.go b/internal/bundler/bundler.go index 95e3c126..68be6cf7 100644 --- a/internal/bundler/bundler.go +++ b/internal/bundler/bundler.go @@ -336,11 +336,7 @@ func getAgents(theproject *project.Project, filename string) []AgentConfig { var agents []AgentConfig for _, agent := range theproject.Agents { var agentfilename string - if theproject.Bundler.Language == "python" { - agentfilename = util.SafePythonFilename(agent.Name) - } else { - agentfilename = util.SafeFilename(agent.Name) - } + agentfilename = util.SafeProjectFilename(agent.Name, theproject.IsPython()) agents = append(agents, AgentConfig{ ID: agent.ID, Name: agent.Name, diff --git a/internal/project/project.go b/internal/project/project.go index ba8310a5..61426b62 100644 --- a/internal/project/project.go +++ b/internal/project/project.go @@ -153,6 +153,14 @@ type Project struct { Agents []AgentConfig `json:"agents" yaml:"agents" hc:"The agents that are part of this project"` } +func (p *Project) SafeFilename() string { + return util.SafeProjectFilename(p.Name, p.IsPython()) +} + +func (p *Project) IsPython() bool { + return p.Bundler.Language == "python" || p.Bundler.Language == "py" +} + // Load will load the project from a file in the given directory. func (p *Project) Load(dir string) error { fn := getFilename(dir) diff --git a/internal/templates/steps.go b/internal/templates/steps.go index 3526bccb..30ce6472 100644 --- a/internal/templates/steps.go +++ b/internal/templates/steps.go @@ -546,7 +546,7 @@ func resolveStep(ctx TemplateContext, step any) (Step, bool) { } var name string if val, ok := kv["name"].(string); ok { - name = util.SafeFilename(ctx.Interpolate(val).(string)) + name = util.SafeProjectFilename(ctx.Interpolate(val).(string), ctx.Template.Language == "python") } var version string if val, ok := kv["version"].(string); ok { diff --git a/internal/templates/template.go b/internal/templates/template.go index 1fb51377..8a0a8e54 100644 --- a/internal/templates/template.go +++ b/internal/templates/template.go @@ -29,10 +29,7 @@ type TemplateContext struct { func funcTemplates(t *template.Template, isPython bool) *template.Template { return t.Funcs(template.FuncMap{ "safe_filename": func(s string) string { - if isPython { - return util.SafePythonFilename(s) - } - return util.SafeFilename(s) + return util.SafeProjectFilename(s, isPython) }, }) } diff --git a/internal/util/strings.go b/internal/util/strings.go index de497b50..2d8ebd25 100644 --- a/internal/util/strings.go +++ b/internal/util/strings.go @@ -11,22 +11,21 @@ var beginsWithNumber = regexp.MustCompile(`^[0-9]+`) var removeStartingDashes = regexp.MustCompile(`^[-]+`) var removeEndingDashes = regexp.MustCompile(`[-]+$`) -func SafeFilename(name string) string { - return safeNameTransformer.ReplaceAllString(name, "-") -} - -func SafePythonFilename(name string) string { - if beginsWithNumber.MatchString(name) { - name = beginsWithNumber.ReplaceAllString(name, "") +func SafeProjectFilename(name string, python bool) string { + if python { + if beginsWithNumber.MatchString(name) { + name = beginsWithNumber.ReplaceAllString(name, "") + } + name = safePythonNameTransformer.ReplaceAllString(name, "_") + if removeStartingDashes.MatchString(name) { + name = removeStartingDashes.ReplaceAllString(name, "") + } + if removeEndingDashes.MatchString(name) { + name = removeEndingDashes.ReplaceAllString(name, "") + } + return name } - name = safePythonNameTransformer.ReplaceAllString(name, "_") - if removeStartingDashes.MatchString(name) { - name = removeStartingDashes.ReplaceAllString(name, "") - } - if removeEndingDashes.MatchString(name) { - name = removeEndingDashes.ReplaceAllString(name, "") - } - return name + return safeNameTransformer.ReplaceAllString(name, "-") } func Pluralize(count int, singular string, plural string) string { diff --git a/internal/util/strings_test.go b/internal/util/strings_test.go index 5f791299..44327d1c 100644 --- a/internal/util/strings_test.go +++ b/internal/util/strings_test.go @@ -7,30 +7,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSafeFilename(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - {"empty string", "", ""}, - {"no special characters", "filename", "filename"}, - {"with spaces", "file name", "file-name"}, - {"with special characters", "file@#$%^&*()name", "file---------name"}, - {"mixed case", "FileName", "FileName"}, - {"with numbers", "file123name", "file123name"}, - {"with underscores", "file_name", "file_name"}, - {"with hyphens", "file-name", "file-name"}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - result := SafeFilename(test.input) - assert.Equal(t, test.expected, result) - }) - } -} - func TestPluralize(t *testing.T) { tests := []struct { name string @@ -99,7 +75,31 @@ func TestSafePythonFilename(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - result := SafePythonFilename(test.input) + result := SafeProjectFilename(test.input, true) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestSafeFilename(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + {"empty string", "", ""}, + {"no special characters", "filename", "filename"}, + {"with spaces", "file name", "file-name"}, + {"with special characters", "file@#$%^&*()name", "file---------name"}, + {"mixed case", "FileName", "FileName"}, + {"with numbers", "file123name", "file123name"}, + {"with underscores", "file_name", "file_name"}, + {"with hyphens", "file-name", "file-name"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := SafeProjectFilename(test.input, false) assert.Equal(t, test.expected, result) }) }