diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 04ef39d..d41a1fd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -10,6 +10,10 @@ jobs: go-version: '1.22.1' - name: Check out code uses: actions/checkout@v4.1.6 + - name: Set up Git + run: | + git config --global user.email "action@github.com" + git config --global user.name "GitHub Action" - name: Test and generate coverage report run: go test -coverprofile=coverage.out ./... - name: Upload coverage reports to Codecov diff --git a/.goji.json b/.goji.json index 096056b..39cfd4a 100644 --- a/.goji.json +++ b/.goji.json @@ -1,11 +1,11 @@ { - "noemojis": false, + "noemoji": false, "scopes": [ "home", "accounts", "ci" ], - "signoff": true, + "signoff": false, "skipquestions": null, "subjectmaxlength": 100, "types": [ diff --git a/cmd/root.go b/cmd/root.go index 0dc9fab..f45683a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -48,13 +48,13 @@ var rootCmd = &cobra.Command{ var commitBody string if typeFlag != "" && messageFlag != "" { // If all flags are provided, construct the commit message from them - var typeMatch string + typeMatch := "" for _, t := range config.Types { if typeFlag == t.Name { if !config.NoEmoji { typeMatch = fmt.Sprintf("%s %s", t.Name, t.Emoji) } else { - typeMatch = fmt.Sprintf(t.Name) + typeMatch = t.Name } break } @@ -109,7 +109,6 @@ var rootCmd = &cobra.Command{ func init() { rootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "Display version information") - // rootCmd.Flags().BoolVarP(&signFlag, "sign-off", "S", false, "add a Signed-off-by trailer") rootCmd.Flags().StringVarP(&typeFlag, "type", "t", "", "Specify the type from the config file") rootCmd.Flags().StringVarP(&scopeFlag, "scope", "s", "", "Specify a custom scope") rootCmd.Flags().StringVarP(&messageFlag, "message", "m", "", "Specify a commit message") @@ -122,6 +121,15 @@ func Execute() { } } +// commit executes a git commit with the given message and body. +// +// Parameters: +// - message: the commit message. +// - body: the commit body. +// - sign: a boolean indicating whether to add a Signed-off-by trailer. +// +// Returns: +// - error: an error if the git commit execution fails. func commit(message, body string, sign bool) error { args := []string{"commit", "-m", message, "-m", body} if sign { diff --git a/cmd/root_test.go b/cmd/root_test.go new file mode 100644 index 0000000..6d18366 --- /dev/null +++ b/cmd/root_test.go @@ -0,0 +1,101 @@ +package cmd + +import ( + "bytes" + "fmt" + "io" + "os" + "os/exec" + "testing" + + "github.com/alecthomas/assert/v2" + "github.com/fatih/color" + "github.com/spf13/cobra" +) + +func TestCommit(t *testing.T) { + t.Run("success", func(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + + tempDir, err := os.MkdirTemp("", "git-commit-test") + if err != nil { + t.Fatalf("error creating temp dir: %v", err) + } + defer os.RemoveAll(tempDir) + + if err := os.Chdir(tempDir); err != nil { + t.Fatalf("error changing to temp dir: %v", err) + } + + if err := exec.Command("git", "init").Run(); err != nil { + t.Fatalf("error initializing git repo: %v", err) + } + + if err := os.WriteFile("testfile", []byte("test content"), 0644); err != nil { + t.Fatalf("error writing testfile: %v", err) + } + + if err := exec.Command("git", "add", "testfile").Run(); err != nil { + t.Fatalf("error adding testfile to index: %v", err) + } + + if err := commit("test commit", "test commit body", false); err != nil { + t.Fatalf("error committing: %v", err) + } + + if err := exec.Command("git", "log", "-1", "--pretty=%s").Run(); err != nil { + t.Fatalf("error checking commit: %v", err) + } + }) +} + +func TestRootCmd_VersionFlag(t *testing.T) { + + var versionFlag bool + // Save the original os.Stdout + originalStdout := os.Stdout + // Create a buffer to capture the output + r, w, _ := os.Pipe() + os.Stdout = w + + // Create a new command + cmd := &cobra.Command{ + Use: "goji", + Short: "Goji CLI", + Long: `Goji is a cli tool to generate conventional commits with emojis`, + Run: func(cmd *cobra.Command, args []string) { + if versionFlag { + color.Set(color.FgGreen) + fmt.Printf("goji version: v%s\n", version) + color.Unset() + return + } + }, + } + + // Set the version flag + cmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "Display version information") + cmd.SetArgs([]string{"--version"}) + + // Execute the command + if err := cmd.Execute(); err != nil { + t.Fatalf("Error executing command: %v", err) + } + + // Close the writer and restore os.Stdout + w.Close() + os.Stdout = originalStdout + + // Read the captured output + var buf bytes.Buffer + _, err := io.Copy(&buf, r) + if err != nil { + t.Fatalf("Error reading captured output: %v", err) + } + output := buf.String() + + // Assert that the output contains the expected version string + assert.Contains(t, output, "goji version: v") +} diff --git a/go.mod b/go.mod index d6e4493..536e7ec 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/muandane/goji go 1.22.2 require ( + github.com/alecthomas/assert/v2 v2.2.1 github.com/charmbracelet/glamour v0.7.0 github.com/charmbracelet/huh v0.4.2 github.com/charmbracelet/huh/spinner v0.0.0-20240404200615-66118a2cb3cf @@ -18,6 +19,7 @@ require ( require ( github.com/alecthomas/chroma/v2 v2.8.0 // indirect + github.com/alecthomas/repr v0.2.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -37,6 +39,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect diff --git a/pkg/config/config.go b/pkg/config/config.go index ddacc67..ecbf352 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -19,7 +19,6 @@ func ViperConfig() (*Config, error) { homeDir, _ := os.UserHomeDir() if _, err = os.Stat(filepath.Join(gitDir, ".goji.json")); err == nil { viper.AddConfigPath(gitDir) - // fmt.Printf("using repo conf") // used for debug } else { viper.AddConfigPath(homeDir) // fmt.Printf("using home conf") // used for debug diff --git a/pkg/config/configInit.go b/pkg/config/configInit.go index 3b29355..f5a14dd 100644 --- a/pkg/config/configInit.go +++ b/pkg/config/configInit.go @@ -46,7 +46,7 @@ func SaveConfigToFile(config initConfig, file, dir string) error { viper.Set("skipQuestions", config.SkipQuestions) viper.Set("subjectMaxLength", config.SubjectMaxLength) viper.Set("signOff", config.SignOff) - viper.Set("noEmojis", config.NoEmoji) + viper.Set("noemoji", config.NoEmoji) viper.SetConfigName(file) viper.SetConfigType("json") diff --git a/pkg/config/configType.go b/pkg/config/configType.go index e4b0b40..ce0c142 100644 --- a/pkg/config/configType.go +++ b/pkg/config/configType.go @@ -23,10 +23,10 @@ type Gitmoji struct { Name string `json:"name"` } type initConfig struct { - Types []Gitmoji `json:"Types"` - Scopes []string `json:"Scopes"` - SkipQuestions []string `json:"SkipQuestions"` - SubjectMaxLength int `json:"SubjectMaxLength"` - SignOff bool `json:"SignOff"` - NoEmoji bool `json:"NoEmoji"` + Types []Gitmoji `json:"types"` + Scopes []string `json:"scopes"` + SkipQuestions []string `json:"skipQuestions"` + SubjectMaxLength int `json:"subjectMaxLength"` + SignOff bool `json:"signOff"` + NoEmoji bool `json:"noemoji"` }