diff --git a/cmd/handler.go b/cmd/handler.go new file mode 100644 index 0000000..baa7ca3 --- /dev/null +++ b/cmd/handler.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "github.com/TwiN/go-color" + "io" + "log" + "rockstaedt/commit-message-check/internal/model" +) + +type Handler struct { + Config model.Config + Writer io.Writer +} + +func NewHandler(config model.Config) *Handler { + return &Handler{Config: config} +} + +func (h *Handler) Run(command string) int { + var status int + + switch command { + case "setup": + status = h.setup() + case "uninstall": + status = h.uninstall() + case "update": + status = h.update() + case "validate": + status = h.validate() + default: + log.Println("Unknown subcommand. Please check manual.") + return 1 + } + + return status +} + +func (h *Handler) notify(message string, txtColor ...string) { + if len(txtColor) > 0 && txtColor[0] == "green" { + message = color.InGreen(message) + } + + if len(txtColor) > 0 && txtColor[0] == "red" { + message = color.InRed(message) + } + + if len(txtColor) > 0 && txtColor[0] == "yellow" { + message = color.InYellow(message) + } + + _, err := h.Writer.Write([]byte(message + "\n")) + if err != nil { + log.Println("Error at writing!") + } +} diff --git a/cmd/handler_test.go b/cmd/handler_test.go new file mode 100644 index 0000000..f82729d --- /dev/null +++ b/cmd/handler_test.go @@ -0,0 +1,135 @@ +package cmd + +import ( + "bytes" + "errors" + "github.com/TwiN/go-color" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "log" + "os" + "rockstaedt/commit-message-check/internal/model" + "rockstaedt/commit-message-check/testdata/mocks" + "testing" +) + +func TestRun(t *testing.T) { + buffer := &bytes.Buffer{} + log.SetOutput(buffer) + + t.Run("executes uninstall command", func(t *testing.T) { + buffer.Reset() + myHandler := NewHandler(model.Config{GitPath: "/"}) + myHandler.Writer = buffer + + status := myHandler.Run("uninstall") + + assert.Contains(t, buffer.String(), "Could not delete") + assert.True(t, status > 0) + }) + + t.Run("executes setup command", func(t *testing.T) { + buffer.Reset() + protectedPath := t.TempDir() + "/fake" + err := os.Mkdir(protectedPath, 0000) + assert.Nil(t, err) + myHandler := NewHandler(model.Config{GitPath: protectedPath}) + myHandler.Writer = buffer + + status := myHandler.Run("setup") + + assert.Contains(t, buffer.String(), "Could not create") + assert.True(t, status > 0) + }) + + t.Run("executes update command", func(t *testing.T) { + buffer.Reset() + myHandler := NewHandler(model.Config{}) + myHandler.Writer = buffer + + status := myHandler.Run("update") + + assert.Contains(t, buffer.String(), "Error at retrieving") + assert.True(t, status > 0) + }) + + t.Run("executes validate command", func(t *testing.T) { + + buffer.Reset() + testFile := t.TempDir() + "/text.txt" + err := os.WriteFile(testFile, []byte("i am a commit msg"), 0666) + assert.Nil(t, err) + myHandler := NewHandler(model.Config{CommitMsgFile: testFile}) + + myHandler.Run("validate") + + assert.Equal(t, 0, buffer.Len()) + }) + + t.Run("prints warning when any other command", func(t *testing.T) { + buffer.Reset() + myHandler := NewHandler(model.Config{}) + + status := myHandler.Run("unknown") + + want := "Unknown subcommand. Please check manual." + assert.Contains(t, buffer.String(), want) + assert.Equal(t, 1, status) + }) +} + +func TestNotify(t *testing.T) { + fwm := &mocks.FakeWriterMock{} + handler := NewHandler(model.Config{}) + handler.Writer = fwm + + t.Run("writes a message to the writer", func(t *testing.T) { + fwm.ResetCalls() + fwm.On("Write", mock.Anything).Return(1, nil) + + handler.notify("I am a message") + + fwm.AssertCalled(t, "Write", []byte("I am a message\n")) + }) + + t.Run("colorize text in", func(t *testing.T) { + + t.Run("green", func(t *testing.T) { + fwm.ResetCalls() + fwm.On("Write", mock.Anything).Return(1, nil) + + handler.notify("I am a message", "green") + + fwm.AssertCalled(t, "Write", []byte(color.Green+"I am a message"+color.Reset+"\n")) + }) + + t.Run("red", func(t *testing.T) { + fwm.ResetCalls() + fwm.On("Write", mock.Anything).Return(1, nil) + + handler.notify("I am a message", "red") + + fwm.AssertCalled(t, "Write", []byte(color.Red+"I am a message"+color.Reset+"\n")) + }) + + t.Run("yellow", func(t *testing.T) { + fwm.ResetCalls() + fwm.On("Write", mock.Anything).Return(1, nil) + + handler.notify("I am", "yellow") + + fwm.AssertCalled(t, "Write", []byte(color.Yellow+"I am"+color.Reset+"\n")) + }) + }) + + t.Run("handles error at writing", func(t *testing.T) { + buffer := &bytes.Buffer{} + log.SetOutput(buffer) + fwm.ResetCalls() + fwm.On("Write", mock.Anything).Return(0, errors.New("error at writing")) + + handler.notify("this causes an error") + + assert.Contains(t, buffer.String(), "Error at writing!") + }) +} diff --git a/cmd/setup.go b/cmd/setup.go index efcfa54..90244d8 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -1,17 +1,16 @@ package cmd import ( - "log" "rockstaedt/commit-message-check/util" ) -func Setup(gitPath string) int { - err := util.WalkHookDirs(gitPath, util.CreateHook) +func (h *Handler) setup() int { + err := util.WalkHookDirs(h.Config.GitPath, util.CreateHook) if err != nil { - log.Println("[ERROR]\t Could not create commit-msg script.") + h.notify("Could not create commit-msg script.", "red") return 1 } - log.Println("[SUCCESS]\t commit-message-check successfully installed.") + h.notify("commit-message-check successfully installed.", "green") return 0 } diff --git a/cmd/setup_test.go b/cmd/setup_test.go index 075b591..dd30f94 100644 --- a/cmd/setup_test.go +++ b/cmd/setup_test.go @@ -3,53 +3,56 @@ package cmd import ( "bytes" "fmt" + "github.com/TwiN/go-color" "github.com/stretchr/testify/assert" - "log" "os" + "rockstaedt/commit-message-check/internal/model" "testing" ) func TestSetup(t *testing.T) { buffer := &bytes.Buffer{} - log.SetOutput(buffer) t.Run("returns 0 and", func(t *testing.T) { - createDirs := func() string { + fakeHandler := func() *Handler { path := t.TempDir() err := os.Mkdir(fmt.Sprintf("%s/hooks", path), os.ModePerm) assert.Nil(t, err) - return path - } + handler := NewHandler(model.Config{GitPath: path}) + handler.Writer = buffer - t.Run("creates commit-msg script in hook folder", func(t *testing.T) { - path := createDirs() + return handler + }() - status := Setup(path) + t.Run("creates commit-msg script in hook folder", func(t *testing.T) { + status := fakeHandler.setup() assert.Equal(t, 0, status) - assert.FileExists(t, fmt.Sprintf("%s/hooks/commit-msg", path)) + assert.FileExists(t, fmt.Sprintf("%s/hooks/commit-msg", fakeHandler.Config.GitPath)) }) t.Run("logs a success message", func(t *testing.T) { buffer.Reset() - path := createDirs() - _ = Setup(path) + _ = fakeHandler.setup() - assert.Contains(t, buffer.String(), "[SUCCESS]\t commit-message-check successfully installed.") + assert.Contains(t, buffer.String(), color.Green+"commit-message-check successfully installed.") }) }) t.Run("returns 1 when error at walking hooks and logs it", func(t *testing.T) { + buffer.Reset() errPath := t.TempDir() err := os.Mkdir(fmt.Sprintf("%s/hooks", errPath), 0000) assert.Nil(t, err) + handler := NewHandler(model.Config{GitPath: errPath}) + handler.Writer = buffer - status := Setup(errPath) + status := handler.setup() assert.Equal(t, 1, status) - assert.Contains(t, buffer.String(), "[ERROR]\t Could not create commit-msg script.") + assert.Contains(t, buffer.String(), color.Red+"Could not create commit-msg script.") }) } diff --git a/cmd/uninstall.go b/cmd/uninstall.go index 90a2836..142b245 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -1,17 +1,16 @@ package cmd import ( - "log" "rockstaedt/commit-message-check/util" ) -func Uninstall(gitPath string) int { - err := util.WalkHookDirs(gitPath, util.DeleteHook) +func (h *Handler) uninstall() int { + err := util.WalkHookDirs(h.Config.GitPath, util.DeleteHook) if err != nil { - log.Println("[ERROR]\t Could not delete commit-msg hook.") + h.notify("Could not delete commit-msg hook.", "red") return 1 } - log.Println("[SUCCESS]\t commit-message-check successfully uninstalled.") + h.notify("commit-message-check successfully uninstalled.", "green") return 0 } diff --git a/cmd/uninstall_test.go b/cmd/uninstall_test.go index e6d04b8..d206d11 100644 --- a/cmd/uninstall_test.go +++ b/cmd/uninstall_test.go @@ -3,17 +3,17 @@ package cmd import ( "bytes" "fmt" + "github.com/TwiN/go-color" "github.com/stretchr/testify/assert" - "log" "os" + "rockstaedt/commit-message-check/internal/model" "testing" ) func TestUninstall(t *testing.T) { buffer := &bytes.Buffer{} - log.SetOutput(buffer) - createDirs := func() string { + createFakeHandlerWithDirs := func() *Handler { path := t.TempDir() err := os.Mkdir(fmt.Sprintf("%s/hooks", path), os.ModePerm) assert.Nil(t, err) @@ -24,16 +24,20 @@ func TestUninstall(t *testing.T) { _, err = os.Create(fmt.Sprintf("%s/xyz/commit-msg", path)) assert.Nil(t, err) - return path + handler := NewHandler(model.Config{GitPath: path}) + handler.Writer = buffer + + return handler } t.Run("returns 0 and", func(t *testing.T) { t.Run("removes all occurrences of commit-msg", func(t *testing.T) { - path := createDirs() + handler := createFakeHandlerWithDirs() - status := Uninstall(path) + status := handler.uninstall() + path := handler.Config.GitPath assert.Equal(t, 0, status) assert.NoFileExists(t, fmt.Sprintf("%s/hooks/commit-msg", path)) assert.FileExists(t, fmt.Sprintf("%s/xyz/commit-msg", path)) @@ -41,11 +45,11 @@ func TestUninstall(t *testing.T) { t.Run("logs a success message", func(t *testing.T) { buffer.Reset() - path := createDirs() + handler := createFakeHandlerWithDirs() - _ = Uninstall(path) + _ = handler.uninstall() - assert.Contains(t, buffer.String(), "[SUCCESS]\t commit-message-check successfully uninstalled.") + assert.Contains(t, buffer.String(), color.Green+"commit-message-check successfully uninstalled.") }) }) @@ -54,10 +58,12 @@ func TestUninstall(t *testing.T) { errPath := t.TempDir() err := os.Mkdir(fmt.Sprintf("%s/hooks", errPath), 0000) assert.Nil(t, err) + handler := NewHandler(model.Config{GitPath: errPath}) + handler.Writer = buffer - status := Uninstall(errPath) + status := handler.uninstall() assert.Equal(t, 1, status) - assert.Contains(t, buffer.String(), "[ERROR]\t Could not delete commit-msg hook.") + assert.Contains(t, buffer.String(), color.Red+"Could not delete commit-msg hook.") }) } diff --git a/cmd/update.go b/cmd/update.go index e7b6800..a20ec8b 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -3,8 +3,8 @@ package cmd import ( "encoding/json" "fmt" + "github.com/TwiN/go-color" "io" - "log" "net/http" "os" "rockstaedt/commit-message-check/internal/model" @@ -15,19 +15,27 @@ type responseData struct { TagName string `json:"tag_name"` } -func Update(config *model.UpdateConfig) int { - config.LatestVersion = getLatestTag(config.TagUrl) - if config.LatestVersion == "" { - log.Println("Error at retrieving latest version.") +func (h *Handler) update() int { + h.Config.LatestVersion = getLatestTag(h.Config.TagUrl) + if h.Config.LatestVersion == "" { + h.notify("Error at retrieving latest version.", "red") return 1 } - if config.Version == config.LatestVersion { - log.Println("Current version is latest version.") + if h.Config.Version == h.Config.LatestVersion { + h.notify("Current version is latest version.") return 0 } - return downloadScript(config) + statusMsg := downloadScript(&h.Config) + if statusMsg == "" { + h.notify("Error while downloading binary.", "red") + return 1 + } + + h.notify(color.Green + statusMsg) + + return 0 } func getLatestTag(url string) string { @@ -49,27 +57,27 @@ func getLatestTag(url string) string { return data.TagName } -func downloadScript(config *model.UpdateConfig) int { +func downloadScript(config *model.Config) string { file, err := os.Create(config.DownloadPath + "/commit-message-check") if err != nil { - return 1 + return "" } res, err := http.Get(getBinaryUrl(config)) if err != nil { - return 2 + return "" } if res.StatusCode != 200 { - return 3 + return "" } _, _ = io.Copy(file, res.Body) - return 0 + return "commit-message-check updated successfully to " + config.LatestVersion } -func getBinaryUrl(config *model.UpdateConfig) string { +func getBinaryUrl(config *model.Config) string { return fmt.Sprintf( "%s/commit-message-check-%s-%s-%s", config.BinaryBaseUrl, diff --git a/cmd/update_test.go b/cmd/update_test.go index 8bc85ae..aab35e8 100644 --- a/cmd/update_test.go +++ b/cmd/update_test.go @@ -3,8 +3,8 @@ package cmd import ( "bytes" "fmt" + "github.com/TwiN/go-color" "github.com/stretchr/testify/assert" - "log" "net/http" "net/http/httptest" "os" @@ -15,7 +15,6 @@ import ( func TestUpdate(t *testing.T) { buffer := &bytes.Buffer{} - log.SetOutput(buffer) t.Run("returns 0 and", func(t *testing.T) { @@ -23,36 +22,73 @@ func TestUpdate(t *testing.T) { buffer.Reset() ts := httptest.NewServer(getHandlerFor(`{"tag_name":"v1.0.0"}`)) defer ts.Close() - config := &model.UpdateConfig{Version: "v1.0.0", TagUrl: ts.URL} + handler := NewHandler(model.Config{Version: "v1.0.0", TagUrl: ts.URL}) + handler.Writer = buffer - status := Update(config) + status := handler.update() assert.Equal(t, 0, status) assert.Contains(t, buffer.String(), "Current version is latest version.") }) t.Run("downloads install script if newer version available", func(t *testing.T) { - ts := httptest.NewServer(getHandlerFor(`{"tag_name":"v1.1.0"}`)) - defer ts.Close() + buffer.Reset() + tsTag := httptest.NewServer(getHandlerFor(`{"tag_name":"v1.1.0"}`)) + defer tsTag.Close() + tsBinary := httptest.NewServer(getHandlerFor("i am a binary")) + defer tsBinary.Close() tempDir := t.TempDir() - config := &model.UpdateConfig{Version: "v1.0.0", TagUrl: ts.URL, DownloadPath: tempDir} + handler := NewHandler(model.Config{ + Version: "v1.0.0", + BinaryBaseUrl: tsBinary.URL, + TagUrl: tsTag.URL, + DownloadPath: tempDir, + }) + handler.Writer = buffer - _ = Update(config) + status := handler.update() assert.FileExists(t, tempDir+"/commit-message-check") + assert.Equal(t, 0, status) + assert.Contains(t, buffer.String(), "updated successfully to") }) }) t.Run("returns 1 and message when error at request", func(t *testing.T) { - buffer.Reset() - ts := httptest.NewServer(getHandlerFor("", 500)) - defer ts.Close() - config := &model.UpdateConfig{Version: "v1.0.0", TagUrl: ts.URL, DownloadPath: ""} - status := Update(config) + t.Run("for tag", func(t *testing.T) { + buffer.Reset() + ts := httptest.NewServer(getHandlerFor("", 500)) + defer ts.Close() + handler := NewHandler(model.Config{Version: "v1.0.0", TagUrl: ts.URL, DownloadPath: ""}) + handler.Writer = buffer + + status := handler.update() + + assert.Equal(t, 1, status) + assert.Contains(t, buffer.String(), color.Red+"Error at retrieving latest version.") + }) - assert.Equal(t, 1, status) - assert.Contains(t, buffer.String(), "Error at retrieving latest version.") + t.Run("for binary", func(t *testing.T) { + buffer.Reset() + tsTag := httptest.NewServer(getHandlerFor(`{"tag_name":"v1.1.0"}`)) + defer tsTag.Close() + tsBinary := httptest.NewServer(getHandlerFor("", 500)) + defer tsBinary.Close() + tempDir := t.TempDir() + handler := NewHandler(model.Config{ + Version: "v1.0.0", + BinaryBaseUrl: tsBinary.URL, + TagUrl: tsTag.URL, + DownloadPath: tempDir, + }) + handler.Writer = buffer + + status := handler.update() + + assert.Equal(t, 1, status) + assert.Contains(t, buffer.String(), color.Red+"Error while downloading binary.") + }) }) } @@ -118,7 +154,7 @@ func TestDownloadScript(t *testing.T) { return protectedPath } - t.Run("returns 0 and writes downloaded binary content to file", func(t *testing.T) { + t.Run("returns success message and writes downloaded binary content to file", func(t *testing.T) { tempDir := t.TempDir() err := os.WriteFile(tempDir+"/dummy", []byte("i am a go binary"), os.ModePerm) assert.Nil(t, err) @@ -129,43 +165,47 @@ func TestDownloadScript(t *testing.T) { } })) defer ts.Close() - config := &model.UpdateConfig{LatestVersion: "v1.1.1", DownloadPath: tempDir, BinaryBaseUrl: ts.URL} + config := &model.Config{LatestVersion: "v1.1.1", DownloadPath: tempDir, BinaryBaseUrl: ts.URL} - status := downloadScript(config) + msg := downloadScript(config) - assert.Equal(t, 0, status) contentBytes, err := os.ReadFile(tempDir + "/commit-message-check") assert.Nil(t, err) assert.Contains(t, string(contentBytes), "i am a go binary") + wantedUpdateMsg := "commit-message-check updated successfully to v1.1.1" + assert.Contains(t, msg, wantedUpdateMsg) }) - t.Run("returns 1 when error at creating file", func(t *testing.T) { - config := &model.UpdateConfig{DownloadPath: getProtectedPath(t)} + t.Run("returns empty string when", func(t *testing.T) { - status := downloadScript(config) + t.Run("error at creating file", func(t *testing.T) { + config := &model.Config{DownloadPath: getProtectedPath(t)} - assert.Equal(t, 1, status) - }) + msg := downloadScript(config) - t.Run("return 2 when http protocol error", func(t *testing.T) { - tempDir := t.TempDir() - config := &model.UpdateConfig{DownloadPath: tempDir, BinaryBaseUrl: "/xxx"} + assert.Equal(t, "", msg) + }) - status := downloadScript(config) + t.Run("http protocol error", func(t *testing.T) { + tempDir := t.TempDir() + config := &model.Config{DownloadPath: tempDir, BinaryBaseUrl: "/xxx"} - assert.Equal(t, 2, status) - }) + msg := downloadScript(config) - t.Run("return 3 when request not successfully", func(t *testing.T) { - tempDir := t.TempDir() - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(500) - })) - defer ts.Close() - config := &model.UpdateConfig{DownloadPath: tempDir, BinaryBaseUrl: ts.URL} + assert.Equal(t, "", msg) + }) + + t.Run("request not successfully", func(t *testing.T) { + tempDir := t.TempDir() + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(500) + })) + defer ts.Close() + config := &model.Config{DownloadPath: tempDir, BinaryBaseUrl: ts.URL} - status := downloadScript(config) + msg := downloadScript(config) - assert.Equal(t, 3, status) + assert.Equal(t, "", msg) + }) }) } diff --git a/cmd/validate.go b/cmd/validate.go index 071642c..3690b2d 100644 --- a/cmd/validate.go +++ b/cmd/validate.go @@ -1,7 +1,9 @@ package cmd import ( - "log" + "fmt" + "github.com/TwiN/go-color" + "github.com/rockstaedt/txtreader" "rockstaedt/commit-message-check/internal/model" ) @@ -10,23 +12,28 @@ const ( hardLimit = 72 ) -func Validate(commitLines []string) int { - log.Println("[INFO]\t Validate commit message.") +func (h *Handler) validate() int { + commitLines, err := txtreader.GetLinesFromTextFile(h.Config.CommitMsgFile) + if err != nil { + h.notify(fmt.Sprintf("Could not read commit message: %q", err.Error()), "red") + return 1 + } cm := model.CreateCommitMessageFrom(commitLines) numOfExceedingChars := cm.ValidateSubject() if numOfExceedingChars == 0 { - log.Println("[SUCCESS]\t Valid commit message.") return 0 } if numOfExceedingChars > (hardLimit - softLimit) { - log.Println("[ERROR]\t Abort commit. Subject line too long. Please fix.") + h.notify("Abort commit. Subject line too long. Please fix.", "red") return 1 } - log.Printf("[WARN]\t Your subject exceeds the soft limit of 50 chars by %d chars.", numOfExceedingChars) + message := fmt.Sprintf("Your subject exceeds the soft limit of 50 chars by %d chars.", numOfExceedingChars) + h.notify(message, "yellow") + h.notify(cm.Subject[:softLimit] + color.InYellow(cm.Subject[softLimit:])) return 0 } diff --git a/cmd/validate_test.go b/cmd/validate_test.go index a47461a..3b54a86 100644 --- a/cmd/validate_test.go +++ b/cmd/validate_test.go @@ -2,43 +2,70 @@ package cmd import ( "bytes" + "github.com/TwiN/go-color" "github.com/stretchr/testify/assert" - "log" + "os" + "rockstaedt/commit-message-check/internal/model" "testing" ) func TestValidate(t *testing.T) { buffer := &bytes.Buffer{} - log.SetOutput(buffer) - t.Run("returns 0 if valid and logs a success", func(t *testing.T) { + t.Run("returns 0 on success", func(t *testing.T) { buffer.Reset() - commitLines := []string{"i am shorter than 50 characters"} + testFile := t.TempDir() + "/text.txt" + err := os.WriteFile(testFile, []byte("i am a short commit msg"), 0666) + assert.Nil(t, err) + handler := NewHandler(model.Config{CommitMsgFile: testFile}) + handler.Writer = buffer - status := Validate(commitLines) + handler.Run("validate") - assert.Equal(t, status, 0) - assert.Contains(t, buffer.String(), "[INFO]\t Validate commit message.") - assert.Contains(t, buffer.String(), "[SUCCESS]\t Valid commit message") + assert.Equal(t, 0, buffer.Len()) }) - t.Run("returns 0 if soft limit exceeds and logs a warning", func(t *testing.T) { + t.Run("returns 0 when soft limit exceeds and logs a warning", func(t *testing.T) { buffer.Reset() - commitLines := []string{"i am two characters more thaaaaaaaaaaaaaaaaaaaaan 50"} + testFile := t.TempDir() + "/text.txt" + err := os.WriteFile(testFile, []byte("i am two characters more thaaaaaaaaaaaaaaaaaaaaan 50"), 0666) + assert.Nil(t, err) + handler := NewHandler(model.Config{CommitMsgFile: testFile}) + handler.Writer = buffer - status := Validate(commitLines) + status := handler.validate() assert.Equal(t, status, 0) - assert.Contains(t, buffer.String(), "[WARN]\t Your subject exceeds the soft limit of 50 chars by 2 chars.") + assert.Contains(t, buffer.String(), color.Yellow+"Your subject exceeds the soft limit of 50 chars by 2 chars.") + assert.Contains(t, buffer.String(), "i am two characters more thaaaaaaaaaaaaaaaaaaaaan "+color.Yellow+"50") + }) + + t.Run("returns 1 when commit message too long", func(t *testing.T) { + buffer.Reset() + testFile := t.TempDir() + "/text.txt" + content := "waaaaaaaaaaaaaaaaaaaaaaaaaay tooooooooooooooooooo" + + "looooooooooooooooooooooong" + err := os.WriteFile(testFile, []byte(content), 0666) + assert.Nil(t, err) + handler := NewHandler(model.Config{CommitMsgFile: testFile}) + handler.Writer = buffer + + status := handler.Run("validate") + + assert.Contains(t, buffer.String(), color.Red+"Abort commit") + assert.Equal(t, 1, status) }) - t.Run("returns 1 if length > 70 and logs an error", func(t *testing.T) { + t.Run("returns 1 when error at reading file", func(t *testing.T) { buffer.Reset() - commitLines := []string{"i am way toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long"} + handler := NewHandler(model.Config{CommitMsgFile: "/no_file"}) + handler.Writer = buffer - status := Validate(commitLines) + status := handler.Run("validate") - assert.Equal(t, status, 1) - assert.Contains(t, buffer.String(), "[ERROR]\t Abort commit. Subject line too long. Please fix.") + want := `Could not read commit message: "file not found"` + assert.Contains(t, buffer.String(), want) + assert.NotContains(t, buffer.String(), "Valid commit") + assert.Equal(t, 1, status) }) } diff --git a/go.mod b/go.mod index 3077e45..722c02a 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,13 @@ go 1.19 require ( github.com/rockstaedt/txtreader v1.0.1 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 ) require ( + github.com/TwiN/go-color v1.4.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f59502a..347d162 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/TwiN/go-color v1.4.0 h1:fNbOwOrvup5oj934UragnW0B1WKaAkkB85q19Y7h4ng= +github.com/TwiN/go-color v1.4.0/go.mod h1:0QTVEPlu+AoCyTrho7bXbVkrCkVpdQr7YF7PYWEtSxM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -7,11 +9,14 @@ github.com/rockstaedt/txtreader v1.0.1 h1:2FlMPrFEOGdw8CizWnuPe+1be3i7o+ErNhZzwe github.com/rockstaedt/txtreader v1.0.1/go.mod h1:5U0AithdsiR/v3kSTg1z0AbTUZaTy/AhdiDN8wJl9F4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/model/update_config.go b/internal/model/config.go similarity index 66% rename from internal/model/update_config.go rename to internal/model/config.go index 6fd24e8..384de28 100644 --- a/internal/model/update_config.go +++ b/internal/model/config.go @@ -1,6 +1,8 @@ package model -type UpdateConfig struct { +type Config struct { + CommitMsgFile string + GitPath string Version string LatestVersion string TagUrl string diff --git a/main.go b/main.go index 94eb842..dbc743d 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,7 @@ package main import ( "flag" "fmt" - "github.com/rockstaedt/txtreader" - "log" + "github.com/TwiN/go-color" "os" "rockstaedt/commit-message-check/cmd" "rockstaedt/commit-message-check/internal/model" @@ -29,56 +28,39 @@ func main() { } if len(os.Args) == 1 { - fmt.Println("No subcommands given. Please check manual.") + fmt.Println(color.InRed("No subcommands given. Please check manual.")) os.Exit(1) } cwd, err := os.Getwd() if err != nil { - log.Printf("[ERROR]\t Could not determine working directory: %q", err.Error()) + fmt.Println(color.InRed("Could not determine working directory: ") + err.Error()) os.Exit(1) } gitPath := fmt.Sprintf("%s/.git", cwd) _, err = os.Stat(gitPath) if err != nil { - log.Println("[ERROR]\t No git repository could be found.") - os.Exit(2) + fmt.Println(color.InRed("No git repository could be found.")) + os.Exit(1) } - var status int - switch os.Args[1] { - case "setup": - status = cmd.Setup(gitPath) - case "uninstall": - status = cmd.Uninstall(gitPath) - case "update": - config := &model.UpdateConfig{ - Version: version, - TagUrl: "https://api.github.com/repos/rockstaedt/commit-message-check/releases/latest", - BinaryBaseUrl: "https://github.com/rockstaedt/commit-message-check/releases/latest/download/", - DownloadPath: cwd, - } - - status = cmd.Update(config) - - if status > 0 { - log.Println("[ERROR]\t Could not update commit-message-check.") - break - } - log.Printf("[SUCCESS]\t Updated commit-message-check successfully to %s", config.LatestVersion) - case "validate": - commitLines, err := txtreader.GetLinesFromTextFile(os.Args[2]) - if err != nil { - log.Printf("[ERROR]\t Could not read commit message lines: %q", err.Error()) - status = 3 - } + var commitMsgFile string + if len(os.Args) == 3 { + commitMsgFile = os.Args[2] + } - status = cmd.Validate(commitLines) - default: - fmt.Printf("Unknown subcommand %q. Please check manual with -h flag.\n", os.Args[1]) - status = 4 + config := model.Config{ + CommitMsgFile: commitMsgFile, + GitPath: gitPath, + Version: version, + TagUrl: "https://api.github.com/repos/rockstaedt/commit-message-check/releases/latest", + BinaryBaseUrl: "https://github.com/rockstaedt/commit-message-check/releases/latest/download/", + DownloadPath: cwd, } - os.Exit(status) + handler := cmd.NewHandler(config) + handler.Writer = os.Stdout + + os.Exit(handler.Run(os.Args[1])) } diff --git a/testdata/mocks/writer.go b/testdata/mocks/writer.go index 23f9eef..f973266 100644 --- a/testdata/mocks/writer.go +++ b/testdata/mocks/writer.go @@ -1,10 +1,20 @@ package mocks -import "errors" +import ( + "github.com/stretchr/testify/mock" +) -type FakeWriter struct { +type FakeWriterMock struct { + mock.Mock } -func (fw FakeWriter) Write(p []byte) (int, error) { - return 0, errors.New("error at writing") +func (fwm *FakeWriterMock) ResetCalls() { + fwm.Calls = []mock.Call{} + fwm.ExpectedCalls = []*mock.Call{} +} + +func (fwm *FakeWriterMock) Write(p []byte) (int, error) { + args := fwm.Called(p) + + return 0, args.Error(1) } diff --git a/util/hook_test.go b/util/hook_test.go index fda7c7a..df994dd 100644 --- a/util/hook_test.go +++ b/util/hook_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "log" "os" "rockstaedt/commit-message-check/testdata/mocks" @@ -155,9 +156,10 @@ func TestWriteContent(t *testing.T) { t.Run("logs any error", func(t *testing.T) { log.SetOutput(buffer) - errBuffer := mocks.FakeWriter{} + fwm := &mocks.FakeWriterMock{} + fwm.On("Write", mock.Anything).Return(0, errors.New("error at writing")) - writeContent(errBuffer, "usr/tmp") + writeContent(fwm, "usr/tmp") assert.Contains(t, buffer.String(), "[ERROR]\t Could not write commit-msg script: error at writing") })