From 97dc92e32c88d56c65689cd92dece8f890bcb118 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Thu, 21 May 2026 10:19:21 +0300 Subject: [PATCH 01/10] Implement --show-config flag --- cmd/commit/main.go | 28 +++++++++++++++++++++++----- internal/config/config.go | 15 +++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/cmd/commit/main.go b/cmd/commit/main.go index 411054c..a041689 100644 --- a/cmd/commit/main.go +++ b/cmd/commit/main.go @@ -26,6 +26,14 @@ func main() { "Path to the config json file", ) + var showConfig bool + flag.BoolVar( + &showConfig, + "show-config", + false, + "Prints out the current config", + ) + var dryRun bool flag.BoolVar( &dryRun, @@ -36,7 +44,6 @@ func main() { flag.Parse() - commitMessage := getCommitMessage() repo := openRepo() worktree := openWorktree(repo) @@ -47,14 +54,27 @@ func main() { ) } + fileReader := config.FileReader{} + + if showConfig { + configJSON, err := config.MarshalConfigAtPath(fileReader, configFilePath) + if err == nil { + fmt.Fprintf(os.Stdout, "%s\n", configJSON) + os.Exit(0) + } else { + fmt.Fprintf(os.Stderr, helpers.Red("Failed to parse config: %v\n"), err) + os.Exit(1) + } + } + + commitMessage := getCommitMessage() + headFilePath := filepath.Join( worktree.Filesystem.Root(), ".git", "HEAD", ) - fileReader := config.FileReader{} - // Read current HEAD from file headFile, _ := fileReader.ReadFile(headFilePath) headFileText := string(headFile) @@ -101,7 +121,6 @@ func getCommitMessage() string { // Opens the current repository func openRepo() *git.Repository { - options := git.PlainOpenOptions{DetectDotGit: true} repo, err := git.PlainOpenWithOptions(".", &options) @@ -137,7 +156,6 @@ func makeCommitOptions(usr user.User) git.CommitOptions { // Commits changes with provided message func commitChanges(repo *git.Repository, worktree *git.Worktree, commitMessage string) { - checkStagedChanges(worktree) usr := user.GetUser(*repo) diff --git a/internal/config/config.go b/internal/config/config.go index 8663208..53e0ba7 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -53,6 +53,21 @@ func ReadCommitConfig(fileReader FileReading, configFilePath string) (CommitConf return cfg, nil } +// Marshals config at the given file path into a JSON +func MarshalConfigAtPath(fileReader FileReading, configFilePath string) ([]byte, error) { + cfg, err := ReadCommitConfig(fileReader, configFilePath) + if err != nil { + return nil, err + } + + configJson, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return nil, err + } + + return configJson, nil +} + // Helper function to create a default config func MakeDefaultConfig() CommitConfig { return CommitConfig{ From 73ce76c5b83220534c680343fe68270e05e55b15 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 07:34:40 +0300 Subject: [PATCH 02/10] Make sure no characters are auto-escaped --- cmd/commit/main.go | 2 +- internal/config/config.go | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/commit/main.go b/cmd/commit/main.go index a041689..25510b5 100644 --- a/cmd/commit/main.go +++ b/cmd/commit/main.go @@ -57,7 +57,7 @@ func main() { fileReader := config.FileReader{} if showConfig { - configJSON, err := config.MarshalConfigAtPath(fileReader, configFilePath) + configJSON, err := config.EncodeConfigAtPath(fileReader, configFilePath) if err == nil { fmt.Fprintf(os.Stdout, "%s\n", configJSON) os.Exit(0) diff --git a/internal/config/config.go b/internal/config/config.go index 53e0ba7..ffe2d0b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,6 +1,7 @@ package config import ( + "bytes" "encoding/json" "errors" "regexp" @@ -53,18 +54,24 @@ func ReadCommitConfig(fileReader FileReading, configFilePath string) (CommitConf return cfg, nil } -// Marshals config at the given file path into a JSON -func MarshalConfigAtPath(fileReader FileReading, configFilePath string) ([]byte, error) { +// Encodes config at the given file path into JSON +func EncodeConfigAtPath(fileReader FileReading, configFilePath string) ([]byte, error) { cfg, err := ReadCommitConfig(fileReader, configFilePath) if err != nil { return nil, err } - configJson, err := json.MarshalIndent(cfg, "", " ") - if err != nil { + var cfgBuffer bytes.Buffer + encoder := json.NewEncoder(&cfgBuffer) + encoder.SetIndent("", " ") + encoder.SetEscapeHTML(false) + + if err := encoder.Encode(cfg); err != nil { return nil, err } + configJson := bytes.TrimSuffix(cfgBuffer.Bytes(), []byte("\n")) + return configJson, nil } From 30bfd311ff8f6d9a176b078d82d2266af2e190ac Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 07:34:50 +0300 Subject: [PATCH 03/10] Add unit tests --- internal/config/config_test.go | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index c64866e..ab7419f 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "reflect" + "strings" "testing" "github.com/artem-y/commit/internal/config" @@ -193,6 +194,59 @@ func Test_MakeDefaultConfig_CreatesConfigWithDefaultValues(t *testing.T) { } } +func Test_EncodeConfigAtPath_WithValidConfig_ReturnsConfigAsJson(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + expectedConfig := `{ + "IssueRegex": "SWE-[0-9]+", + "OutputIssuePrefix": "(", + "OutputIssueSuffix": ")", + "OutputStringPrefix": "(( ", + "OutputStringSuffix": " )) " +}` + + mock.Results.ReadFile.Success = []byte(expectedConfig) + + // Act + cfg, err := config.EncodeConfigAtPath(mock, "some/path") + // Assert + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + if !reflect.DeepEqual(cfg, mock.Results.ReadFile.Success) { + t.Errorf( + "Expected config JSON ('%s'), got '%s'", + string(mock.Results.ReadFile.Success), + string(cfg), + ) + } +} + +func Test_EncodeConfigAtPath_WhenConfigContainsUnicodeEscapableCharacters_DoesNotEscapeCharacter(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + mock.Results.ReadFile.Success = []byte(`{ + "IssueRegex": "CORE_[0-9]+", + "OutputIssuePrefix": "<", + "OutputIssueSuffix": ">", + "OutputStringPrefix": "<< ", + "OutputStringSuffix": " >> " +}`) + + // Act + cfg, err := config.EncodeConfigAtPath(mock, "some/path/to/config") + + // Assert + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + if strings.Contains(string(cfg), "\\u003c") || strings.Contains(string(cfg), "\\u003e") { + t.Errorf("Expected '<' to stay unescaped, got '%s'", string(cfg)) + } +} + // Helper function to create a JSON string from a config func makeJSON(cfg config.CommitConfig) string { return fmt.Sprintf( From 4ab1fca0572390654c0fabe46844afe5c981f639 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 08:19:51 +0300 Subject: [PATCH 04/10] Add tests for expected failures of EncodeConfigPath --- internal/config/config_test.go | 39 +++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index ab7419f..e6aad9b 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -152,7 +152,6 @@ func Test_ReadCommitConfig_WhenIssueRegexIsEmpty_ReturnsError(t *testing.T) { if err == nil { t.Error("Expected an error, got `nil`") } - } func Test_ReadCommitConfig_WhenIssueRegexIsInvalid_ReturnsError(t *testing.T) { @@ -168,7 +167,6 @@ func Test_ReadCommitConfig_WhenIssueRegexIsInvalid_ReturnsError(t *testing.T) { if err == nil { t.Error("Expected an error, got `nil`") } - } func Test_MakeDefaultConfig_CreatesConfigWithDefaultValues(t *testing.T) { @@ -223,6 +221,41 @@ func Test_EncodeConfigAtPath_WithValidConfig_ReturnsConfigAsJson(t *testing.T) { } } +func Test_EncodeConfigAtPath_WhenFailedToReadFile_ReturnsError(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + mock.Results.ReadFile.Error = errors.New("Error: Failed to read file") + + // Act + cfg, err := config.EncodeConfigAtPath(mock, "a/path") + + // Assert + if cfg != nil { + t.Errorf("Expected no config, got %v", cfg) + } + if err == nil { + t.Error("Expected an error, got `nil`") + } +} + +func Test_EncodeConfigAtPath_WhenFailedToEncodeConfig_ReturnsError(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + configJsonWithInvalidRegex := "{\"issueRegex\":\"(123\"}" + mock.Results.ReadFile.Success = []byte(configJsonWithInvalidRegex) + + // Act + cfg, err := config.EncodeConfigAtPath(mock, "path/to/invalid/config") + + // Assert + if cfg != nil { + t.Errorf("Expected no config, got %v", cfg) + } + if err == nil { + t.Error("Expected an error, got 'nil'") + } +} + func Test_EncodeConfigAtPath_WhenConfigContainsUnicodeEscapableCharacters_DoesNotEscapeCharacter(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} @@ -243,7 +276,7 @@ func Test_EncodeConfigAtPath_WhenConfigContainsUnicodeEscapableCharacters_DoesNo } if strings.Contains(string(cfg), "\\u003c") || strings.Contains(string(cfg), "\\u003e") { - t.Errorf("Expected '<' to stay unescaped, got '%s'", string(cfg)) + t.Errorf("Expected '<' and '>' to stay unescaped, got '%s'", string(cfg)) } } From f58d5b7581e83a23e154889a70db65aba89dcc5a Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 08:30:03 +0300 Subject: [PATCH 05/10] Mention --show-config flag in README --- docs/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/README.md b/docs/README.md index 92a2398..0b1667b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -85,6 +85,11 @@ If you don't want to include the `.commit.json` file at the root of your reposit ```shell commit -config-path=${HOME}/.config/.commit.json "Finally fix everything" ``` +### Show Current Config +To see the config that the tool will apply, use `--show-config`: +```shell +commit --show-config +``` ### Multiple Issue Numbers If the branch has multiple issues in its name, the tool will include them all, comma-separated. For example, the branch named `add-tests-for-CR-127-and-CR-131-features`, the issue regex set to `[A-Z]{2}-[0-9]+`, and the "outputIssuePrefix" and "outputIssueSuffix" settings for the output set to `[` and `]:`, the generated commit message would start with the following: From 9be8712d680ec1dcf0dc7ff3f9ff9498ad45dca4 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 09:00:52 +0300 Subject: [PATCH 06/10] Prevent capitalization when showing config --- internal/config/config.go | 10 +++++++++- internal/config/config_test.go | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index ffe2d0b..42643c9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -61,12 +61,20 @@ func EncodeConfigAtPath(fileReader FileReading, configFilePath string) ([]byte, return nil, err } + cfgDto := commitConfigDTO{ + IssueRegex: &cfg.IssueRegex, + OutputIssuePrefix: &cfg.OutputIssuePrefix, + OutputIssueSuffix: &cfg.OutputIssueSuffix, + OutputStringPrefix: &cfg.OutputStringPrefix, + OutputStringSuffix: &cfg.OutputStringSuffix, + } + var cfgBuffer bytes.Buffer encoder := json.NewEncoder(&cfgBuffer) encoder.SetIndent("", " ") encoder.SetEscapeHTML(false) - if err := encoder.Encode(cfg); err != nil { + if err := encoder.Encode(cfgDto); err != nil { return nil, err } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e6aad9b..14484f4 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -196,11 +196,11 @@ func Test_EncodeConfigAtPath_WithValidConfig_ReturnsConfigAsJson(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} expectedConfig := `{ - "IssueRegex": "SWE-[0-9]+", - "OutputIssuePrefix": "(", - "OutputIssueSuffix": ")", - "OutputStringPrefix": "(( ", - "OutputStringSuffix": " )) " + "issueRegex": "SWE-[0-9]+", + "outputIssuePrefix": "(", + "outputIssueSuffix": ")", + "outputStringPrefix": "(( ", + "outputStringSuffix": " )) " }` mock.Results.ReadFile.Success = []byte(expectedConfig) @@ -260,11 +260,11 @@ func Test_EncodeConfigAtPath_WhenConfigContainsUnicodeEscapableCharacters_DoesNo // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} mock.Results.ReadFile.Success = []byte(`{ - "IssueRegex": "CORE_[0-9]+", - "OutputIssuePrefix": "<", - "OutputIssueSuffix": ">", - "OutputStringPrefix": "<< ", - "OutputStringSuffix": " >> " + "issueRegex": "CORE_[0-9]+", + "outputIssuePrefix": "<", + "outputIssueSuffix": ">", + "outputStringPrefix": "<< ", + "outputStringSuffix": " >> " }`) // Act From 9f5dfb319488278c15390c812687c735a82f8cf7 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Fri, 22 May 2026 09:01:28 +0300 Subject: [PATCH 07/10] Add end-to-end test to show config option --- e2e.sh | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/e2e.sh b/e2e.sh index f169387..dcac3a4 100755 --- a/e2e.sh +++ b/e2e.sh @@ -300,6 +300,46 @@ test_commit_with_detached_head() { pass_test $TESTNAME } +test_show_config() { + TESTNAME="test_show_config" + start_test $TESTNAME + + setup_test_repository &&\ + git checkout -b feature/H22-handle-edge-cases && \ + + # Write a config file + echo ' + { + "issueRegex": "H[0-9]+", + "outputIssuePrefix": "[", + "outputIssueSuffix": "]", + "outputStringPrefix": "", + "outputStringSuffix": " " + } + ' > .commit.json && \ + + # Show the config using the CLI + CONFIG_OUTPUT=$(../bin/commit --show-config) + + EXPECTED_CONFIG='{ + "issueRegex": "H[0-9]+", + "outputIssuePrefix": "[", + "outputIssueSuffix": "]", + "outputStringPrefix": "", + "outputStringSuffix": " " +}' + + if [ "$CONFIG_OUTPUT" != "$EXPECTED_CONFIG" ]; then + echo "Expected config output:" + echo "$EXPECTED_CONFIG" + echo "Actual config output:" + echo "$CONFIG_OUTPUT" + fail_test $TESTNAME + fi + + pass_test $TESTNAME +} + # MARK: - Run Tests build_if_needed @@ -310,3 +350,4 @@ test_commit_from_subdirectory test_set_correct_author test_use_config_with_empty_regex test_commit_with_detached_head +test_show_config From a02786b979508cbeb0fa1efd6aedd5a1ecfb2866 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Sun, 24 May 2026 20:42:58 +0300 Subject: [PATCH 08/10] Show empty config when config file is empty --- cmd/commit/main.go | 3 ++- internal/config/config.go | 21 ++++++++++------ internal/config/config_test.go | 46 ++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/cmd/commit/main.go b/cmd/commit/main.go index 25510b5..4b766bc 100644 --- a/cmd/commit/main.go +++ b/cmd/commit/main.go @@ -86,7 +86,8 @@ func main() { helpers.HEAD_REF_PREFIX, ) - cfg, err := config.ReadCommitConfig(fileReader, configFilePath) + isValidating := true + cfg, err := config.ReadCommitConfig(fileReader, configFilePath, isValidating) if err != nil { fmt.Fprintf(os.Stderr, helpers.Red("Failed to read config: %v\n"), err) os.Exit(1) diff --git a/internal/config/config.go b/internal/config/config.go index 42643c9..87ab659 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -28,7 +28,7 @@ type commitConfigDTO struct { } // Reads config at the file path and unmarshals it into commitConfig struct -func ReadCommitConfig(fileReader FileReading, configFilePath string) (CommitConfig, error) { +func ReadCommitConfig(fileReader FileReading, configFilePath string, isValidating bool) (CommitConfig, error) { var cfgDto commitConfigDTO _, err := fileReader.Stat(configFilePath) @@ -39,16 +39,22 @@ func ReadCommitConfig(fileReader FileReading, configFilePath string) (CommitConf return CommitConfig{}, err } - err = json.Unmarshal(file, &cfgDto) - if err != nil { - return CommitConfig{}, err + if len(file) > 0 { + err = json.Unmarshal(file, &cfgDto) + if err != nil { + return CommitConfig{}, err + } + } else { + return CommitConfig{}, nil } } cfg := makeConfig(cfgDto) - if err := validateRegex(cfg.IssueRegex); err != nil { - return CommitConfig{}, err + if isValidating { + if err := validateRegex(cfg.IssueRegex); err != nil { + return CommitConfig{}, err + } } return cfg, nil @@ -56,7 +62,8 @@ func ReadCommitConfig(fileReader FileReading, configFilePath string) (CommitConf // Encodes config at the given file path into JSON func EncodeConfigAtPath(fileReader FileReading, configFilePath string) ([]byte, error) { - cfg, err := ReadCommitConfig(fileReader, configFilePath) + isValidating := false + cfg, err := ReadCommitConfig(fileReader, configFilePath, isValidating) if err != nil { return nil, err } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 14484f4..e24369a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -22,7 +22,7 @@ func Test_ReadCommitConfig_WhenFileDoesNotExist_ReturnsDefaultConfig(t *testing. defaultConfig := config.MakeDefaultConfig() // Act - cfg, err := config.ReadCommitConfig(mock, "some/path") + cfg, err := config.ReadCommitConfig(mock, "some/path", true) // Assert for _, invocation := range mock.Invocations { @@ -56,7 +56,7 @@ func Test_ReadCommitConfig_WhenFilledWithValidSettings_LoadsAllValuesFromConfig( mock.Results.ReadFile.Success = []byte(configJson) // Act - cfg, err := config.ReadCommitConfig(mock, "some/path") + cfg, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err != nil { @@ -72,13 +72,35 @@ func Test_ReadCommitConfig_WhenFilledWithValidSettings_LoadsAllValuesFromConfig( } } +func Test_ReadCommitConfig_WithoutValidatingEmptyFile_ReturnsEmptyConfig(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + mock.Results.ReadFile.Success = []byte("") + + // Act + cfg, err := config.ReadCommitConfig(mock, "file/path", false) + + // Assert + if err != nil { + t.Errorf("Expected no error, got `%s`", err.Error()) + } + expectedConfig := config.CommitConfig{} + if !reflect.DeepEqual(cfg, expectedConfig) { + t.Errorf( + "Expected `%s', got `%s`", + makeJSON(expectedConfig), + makeJSON(cfg), + ) + } +} + func Test_ReadCommitConfig_WhenInvalidJson_ReturnsError(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} mock.Results.ReadFile.Success = []byte("{invalid json}") // Act - _, err := config.ReadCommitConfig(mock, "some/path") + _, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err == nil { @@ -92,7 +114,7 @@ func Test_ReadCommitConfig_WhenFailedToReadFile_ReturnsError(t *testing.T) { mock.Results.ReadFile.Error = errors.New("failed to read file") // Act - _, err := config.ReadCommitConfig(mock, "some/path") + _, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err == nil { @@ -115,7 +137,7 @@ func Test_ReadCommitConfig_WhenOnlyRegexInConfix_ReturnsConfigWithRegex(t *testi expectedConfig.IssueRegex = expectedRegex // Act - cfg, err := config.ReadCommitConfig(mock, "some/path") + cfg, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err != nil { @@ -146,7 +168,7 @@ func Test_ReadCommitConfig_WhenIssueRegexIsEmpty_ReturnsError(t *testing.T) { mock.Results.ReadFile.Success = []byte(configJson) // Act - _, err := config.ReadCommitConfig(mock, "some/path") + _, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err == nil { @@ -161,7 +183,7 @@ func Test_ReadCommitConfig_WhenIssueRegexIsInvalid_ReturnsError(t *testing.T) { mock.Results.ReadFile.Success = []byte(configJson) // Act - _, err := config.ReadCommitConfig(mock, "some/path") + _, err := config.ReadCommitConfig(mock, "some/path", true) // Assert if err == nil { @@ -224,7 +246,8 @@ func Test_EncodeConfigAtPath_WithValidConfig_ReturnsConfigAsJson(t *testing.T) { func Test_EncodeConfigAtPath_WhenFailedToReadFile_ReturnsError(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} - mock.Results.ReadFile.Error = errors.New("Error: Failed to read file") + expectedErrorMessage := "Error: Failed to read file" + mock.Results.ReadFile.Error = errors.New(expectedErrorMessage) // Act cfg, err := config.EncodeConfigAtPath(mock, "a/path") @@ -236,12 +259,15 @@ func Test_EncodeConfigAtPath_WhenFailedToReadFile_ReturnsError(t *testing.T) { if err == nil { t.Error("Expected an error, got `nil`") } + if err.Error() != expectedErrorMessage { + t.Errorf("Expected error '%s', got '%v'", expectedErrorMessage, err) + } } -func Test_EncodeConfigAtPath_WhenFailedToEncodeConfig_ReturnsError(t *testing.T) { +func Test_EncodeConfigAtPath_WithInvalidJSON_ReturnsError(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} - configJsonWithInvalidRegex := "{\"issueRegex\":\"(123\"}" + configJsonWithInvalidRegex := "{\"issueRegex\":\"abc}" mock.Results.ReadFile.Success = []byte(configJsonWithInvalidRegex) // Act From 83384ea14947929b87cb96d971b8303dbba24df3 Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Mon, 25 May 2026 07:41:17 +0300 Subject: [PATCH 09/10] Clean up leftover merge comment --- cmd/commit/main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/commit/main.go b/cmd/commit/main.go index d85bed9..3724d3f 100644 --- a/cmd/commit/main.go +++ b/cmd/commit/main.go @@ -67,8 +67,6 @@ func main() { } } - // <<<<<<< HEAD - commitMessage := getCommitMessage() head, err := repo.Reference(plumbing.HEAD, false) From a9337ddf9397795a2cbbbe8d2125e889a330020a Mon Sep 17 00:00:00 2001 From: Artem Yelizarov <52959979+artem-y@users.noreply.github.com> Date: Wed, 27 May 2026 01:13:36 +0300 Subject: [PATCH 10/10] Fix validation when doing actual commit --- internal/config/config.go | 4 +++- internal/config/config_test.go | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/config/config.go b/internal/config/config.go index 87ab659..e5359a0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -39,11 +39,13 @@ func ReadCommitConfig(fileReader FileReading, configFilePath string, isValidatin return CommitConfig{}, err } - if len(file) > 0 { + if len(bytes.TrimSpace(file)) > 0 { err = json.Unmarshal(file, &cfgDto) if err != nil { return CommitConfig{}, err } + } else if isValidating { + return CommitConfig{}, validateRegex("") } else { return CommitConfig{}, nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e24369a..a9491b3 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -72,6 +72,28 @@ func Test_ReadCommitConfig_WhenFilledWithValidSettings_LoadsAllValuesFromConfig( } } +func Test_ReadCommitConfig_ValidatingEmptyFile_ReturnsError(t *testing.T) { + // Arrange + var mock *mocks.FileReadingMock = &mocks.FileReadingMock{} + mock.Results.ReadFile.Success = []byte(" ") + + // Act + _, err := config.ReadCommitConfig(mock, "path/to/empty/file", true) + + // Assert + if err == nil { + t.Error("Expected an error, got `nil`") + } + expectedErr := "Issue regex can't be empty. Please update the config file." + if err.Error() != expectedErr { + t.Errorf( + "Expected error '%s', got '%s'", + expectedErr, + err.Error(), + ) + } +} + func Test_ReadCommitConfig_WithoutValidatingEmptyFile_ReturnsEmptyConfig(t *testing.T) { // Arrange var mock *mocks.FileReadingMock = &mocks.FileReadingMock{}