Skip to content

Commit

Permalink
Accept module name as input to create command (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
Patel-Raj authored Sep 15, 2024
1 parent a0b774b commit ae0e782
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 14 deletions.
12 changes: 8 additions & 4 deletions .github/workflows/generate-linter-advanced.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,23 @@ jobs:
git config --global user.name 'testname'
git config --global user.email 'testemail@users.noreply.github.com'
- name: Set framework variable
id: set-proejct-directory
run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV

- name: build templates
run: script -q /dev/null -c "go run main.go create -n ${{ matrix.framework }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} --advanced --feature ${{ matrix.advanced }}" /dev/null
run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}} --advanced --feature ${{ matrix.advanced }}" /dev/null

- if: ${{ matrix.advanced == 'htmx' || matrix.advanced == 'tailwind' }}
name: Install Templ & gen templates
run: |
go install github.com/a-h/templ/cmd/templ@latest
/home/runner/go/bin/templ generate -path ${{ matrix.framework }}
/home/runner/go/bin/templ generate -path ${{ env.PROJECT_DIRECTORY }}
- name: golangci-lint
run: |
cd ${{ matrix.framework }}
cd ${{ env.PROJECT_DIRECTORY }}
golangci-lint run
- name: remove templates
run: rm -rf ${{ matrix.framework }}
run: rm -rf ${{ env.PROJECT_DIRECTORY }}
10 changes: 7 additions & 3 deletions .github/workflows/generate-linter-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ jobs:
git config --global user.name 'testname'
git config --global user.email 'testemail@users.noreply.github.com'
- name: Set framework variable
id: set-proejct-directory
run: echo "PROJECT_DIRECTORY=${{ matrix.framework }}" | sed 's/\//-/g' >> $GITHUB_ENV

- name: build templates
run: script -q /dev/null -c "go run main.go create -n ${{ matrix.framework }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}}" /dev/null
run: script -q /dev/null -c "go run main.go create -n ${{ env.PROJECT_DIRECTORY }} -f ${{ matrix.framework}} -d ${{ matrix.driver }} -g ${{ matrix.git}}" /dev/null

- name: golangci-lint
run: |
cd ${{ matrix.framework }}
cd ${{ env.PROJECT_DIRECTORY }}
golangci-lint run
- name: remove templates
run: rm -rf ${{ matrix.framework }}
run: rm -rf ${{ env.PROJECT_DIRECTORY }}
24 changes: 19 additions & 5 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,15 @@ var createCmd = &cobra.Command{

isInteractive := false
flagName := cmd.Flag("name").Value.String()
if flagName != "" && doesDirectoryExistAndIsNotEmpty(flagName) {
err = fmt.Errorf("directory '%s' already exists and is not empty. Please choose a different name", flagName)

if flagName != "" && !utils.ValidateModuleName(flagName) {
err = fmt.Errorf("'%s' is not a valid module name. Please choose a different name", flagName)
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}

rootDirName := utils.GetRootDir(flagName)
if rootDirName != "" && doesDirectoryExistAndIsNotEmpty(rootDirName) {
err = fmt.Errorf("directory '%s' already exists and is not empty. Please choose a different name", rootDirName)
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}

Expand Down Expand Up @@ -126,8 +133,15 @@ var createCmd = &cobra.Command{
log.Printf("Name of project contains an error: %v", err)
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}
if doesDirectoryExistAndIsNotEmpty(options.ProjectName.Output) {
err = fmt.Errorf("directory '%s' already exists and is not empty. Please choose a different name", options.ProjectName.Output)

if options.ProjectName.Output != "" && !utils.ValidateModuleName(options.ProjectName.Output) {
err = fmt.Errorf("'%s' is not a valid module name. Please choose a different name", options.ProjectName.Output)
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}

rootDirName = utils.GetRootDir(options.ProjectName.Output)
if doesDirectoryExistAndIsNotEmpty(rootDirName) {
err = fmt.Errorf("directory '%s' already exists and is not empty. Please choose a different name", rootDirName)
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}
project.ExitCLI(tprogram)
Expand Down Expand Up @@ -264,7 +278,7 @@ var createCmd = &cobra.Command{
}

fmt.Println(endingMsgStyle.Render("\nNext steps:"))
fmt.Println(endingMsgStyle.Render(fmt.Sprintf("• cd into the newly created project with: `cd %s`\n", project.ProjectName)))
fmt.Println(endingMsgStyle.Render(fmt.Sprintf("• cd into the newly created project with: `cd %s`\n", utils.GetRootDir(project.ProjectName))))

if options.Advanced.Choices["Tailwind"] {
options.Advanced.Choices["Htmx"] = true
Expand Down
2 changes: 1 addition & 1 deletion cmd/program/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func (p *Project) CreateMainFile() error {
p.ProjectName = strings.TrimSpace(p.ProjectName)

// Create a new directory with the project name
projectPath := filepath.Join(p.AbsolutePath, p.ProjectName)
projectPath := filepath.Join(p.AbsolutePath, utils.GetRootDir(p.ProjectName))
if _, err := os.Stat(projectPath); os.IsNotExist(err) {
err := os.MkdirAll(projectPath, 0o751)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/ui/textinput/textinput.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type model struct {

// sanitizeInput verifies that an input text string gets validated
func sanitizeInput(input string) error {
matched, err := regexp.Match("^[a-zA-Z0-9_-]+$", []byte(input))
matched, err := regexp.Match("^[a-zA-Z0-9_\\/.-]+$", []byte(input))
if !matched {
return fmt.Errorf("string violates the input regex pattern, err: %v", err)
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/ui/textinput/textinput_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ func TestInputSanitization(t *testing.T) {
"new_project",
"NEW_PROJECT",
"new-project",
"new/project",
"new.project",
}
for _, testCase := range passTestCases {
if err := sanitizeInput(testCase); err != nil {
Expand Down
15 changes: 15 additions & 0 deletions cmd/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"bytes"
"fmt"
"os/exec"
"regexp"
"strings"

"github.com/spf13/pflag"
Expand Down Expand Up @@ -120,3 +121,17 @@ func CheckGitConfig(key string) (bool, error) {
// The command ran successfully, so the key is set.
return true, nil
}

// ValidateModuleName returns true if it's a valid module name.
// It allows any number of / and . characters in between.
func ValidateModuleName(moduleName string) bool {
matched, _ := regexp.Match("^[a-zA-Z0-9_-]+(?:[\\/.][a-zA-Z0-9_-]+)*$", []byte(moduleName))
return matched
}

// GetRootDir returns the project directory name from the module path.
// Returns the last token by splitting the moduleName with /
func GetRootDir(moduleName string) string {
tokens := strings.Split(moduleName, "/")
return tokens[len(tokens)-1]
}
57 changes: 57 additions & 0 deletions cmd/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package utils

import "testing"

func TestValidateModuleName(t *testing.T) {
passTestCases := []string{
"github.com/user/project",
"github.com/user/projec1-hyphen",
"github.com/user/projecT_under_Score",
"github.com/user/project.hyphen3",
"project",
"ProJEct",
"PRo_45-.4Jc",
"PRo_/4J/c",
}
for _, testCase := range passTestCases {
ok := ValidateModuleName(testCase)
if !ok {
t.Errorf("testing:%s expected:true got:%v", testCase, ok)
}
}

failTestCases := []string{
"",
"/",
".",
"//",
"/project",
"ProJEct/",
"PRo_$4Jc",
"PRo_@J/c",
}
for _, testCase := range failTestCases {
ok := ValidateModuleName(testCase)
if ok {
t.Errorf("testing:%s expected:false got:%v", testCase, ok)
}
}
}

func TestGeRootDir(t *testing.T) {
testCases := map[string]string{
"github.com/user/pro-ject": "pro-ject",
"pro-ject": "pro-ject",
"/": "",
"": "",
"//": "",
"@": "@",
}

for intput, output := range testCases {
rootDir := GetRootDir(intput)
if rootDir != output {
t.Errorf("testing:%s expected:%s got:%s", intput, output, rootDir)
}
}
}

0 comments on commit ae0e782

Please sign in to comment.