From 6e0d7c57f2fba3ca8c59c146f661bd7872748e19 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 19:58:43 +0200 Subject: [PATCH 01/32] refactor: rewrite parts of the commit function to be a bit more sane, removed the jump as well --- src/cmd/utils/commit.go | 65 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/cmd/utils/commit.go b/src/cmd/utils/commit.go index 06f5c6b..1b316fe 100644 --- a/src/cmd/utils/commit.go +++ b/src/cmd/utils/commit.go @@ -10,54 +10,51 @@ import ( // This util file is used to create a commit message using a string builder -// string builder for the commit message -var sb strings.Builder - -// list of excluded authors based on the author file -var excludeMode = []string{} - // Regex pattern used to create temp users to add to the commit message var reg, _ = regexp.Compile("([^:]+):([^:]+)") func Commit(message string, authors []string) string { + // string builder for the commit message + var sb strings.Builder + excludeMode := []string{} + // write the commit message to the string builder sb.WriteString(message + "\n") fst := authors[0] if fst == "all" || fst == "All" { - add_x_users(excludeMode) - goto skip_loop + add_x_users(excludeMode, &sb) + return sb.String() } else if Groups[fst] != nil { excludeMode = group_selection(Groups[fst], excludeMode) - add_x_users(excludeMode) - goto skip_loop + add_x_users(excludeMode, &sb) + return sb.String() } - // Loop that adds users - for _, committer := range authors { - if _, ok := Users[committer]; ok { - sb_author(committer) - } else if match := reg.MatchString(committer); match { - str := strings.Split(committer, ":") +// Loop that adds users +for _, committer := range authors { + if _, ok := Users[committer]; ok { + sb_author(committer, &sb) + } else if match := reg.MatchString(committer); match { + str := strings.Split(committer, ":") - sb.WriteString("\nCo-authored-by: ") - sb.WriteString(str[0]) - sb.WriteString(" <") - sb.WriteString(str[1]) - sb.WriteRune('>') + sb.WriteString("\nCo-authored-by: ") + sb.WriteString(str[0]) + sb.WriteString(" <") + sb.WriteString(str[1]) + sb.WriteRune('>') - } else if committer[0] == '^' { // Negations - excludeMode = append(excludeMode, Users[committer[1:]].Username) - } else { - println(committer, " was unknown. User either not defined or name typed wrong") - } - } - if len(excludeMode) > 0 { - add_x_users(excludeMode) + } else if committer[0] == '^' { // Negations + excludeMode = append(excludeMode, Users[committer[1:]].Username) + } else { + println(committer, " was unknown. User either not defined or name typed wrong") } +} - // Skip label for edge cases at top of function -skip_loop: +// Add excluded users after processing all authors +if len(excludeMode) > 0 { + add_x_users(excludeMode, &sb) +} return sb.String() } @@ -95,7 +92,7 @@ func GitPush() { } // helper function to add an author to the commit message -func sb_author(committer string) { +func sb_author(committer string, sb *strings.Builder) { sb.WriteString("\nCo-authored-by: ") sb.WriteString(Users[committer].Username) sb.WriteString(" <") @@ -104,13 +101,13 @@ func sb_author(committer string) { } // helper function to add x amount of users to the commit message -func add_x_users(excludeMode []string) { +func add_x_users(excludeMode []string, sb *strings.Builder) { if len(DefExclude) > 0 { excludeMode = append(excludeMode, DefExclude...) } for key, user := range Users { if !slices.Contains(excludeMode, user.Username) { - sb_author(key) + sb_author(key, sb) excludeMode = append(excludeMode, user.Username) } } From d81e13bbc5baeecd75cedebffe96ac4166d35ea1 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 20:00:00 +0200 Subject: [PATCH 02/32] refactor(gh_fetcher): integreate the gh-cli using its api access to authenticate Helps reduce rate limits and in some cases automates email fetching if the user has one public on their account --- src/cmd/utils/gh_p_fetcher.go | 80 +++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/src/cmd/utils/gh_p_fetcher.go b/src/cmd/utils/gh_p_fetcher.go index 96f3d96..bf6699a 100644 --- a/src/cmd/utils/gh_p_fetcher.go +++ b/src/cmd/utils/gh_p_fetcher.go @@ -4,32 +4,88 @@ import ( "encoding/json" "fmt" "net/http" + "os/exec" "strings" + ) type GithubProfile struct { Login string `json:"login"` Name string `json:"name"` + Email string `json:"email"` +} + +func checkGHCLI() bool { + // Check if the gh command line tool is installed + cmd := exec.Command("gh", "auth", "status") + out ,err := cmd.CombinedOutput() + if err == nil { + if strings.Contains(string(out), "Logged in to") { + return true + } + } else { + return false + } + + return false + +} + +func useGHCLI(username string) []byte { + cmd := exec.Command("gh", "api", fmt.Sprintf("/users/%s", username)) + + out, err := cmd.CombinedOutput() + if err != nil { + panic(fmt.Sprint("Error fetching github profile",err)) + } + return out + } func FetchGithubProfile(username string) User { // Fetch the github profile and create a user with everything except the email - url := fmt.Sprintf("https://api.github.com/users/%s", username) - - resp, err := http.Get(url) - if err != nil { - panic(fmt.Sprint("Error fetching github profile: ", err)) - } - defer resp.Body.Close() - - // Parse the response and create a user var profile GithubProfile - err = json.NewDecoder(resp.Body).Decode(&profile) - if err != nil { - panic(fmt.Sprint("Error parsing github profile: ", err)) + + check := checkGHCLI() + + if check { + // If the gh command line tool is installed, use it to fetch the github profile + fmt.Println("Using gh-cli to fetch github profile") + data := useGHCLI(username) + + err := json.Unmarshal(data, &profile) + if err != nil { + panic(fmt.Sprint("Error parsing github profile: ", err)) + } + if profile.Name == "" { + panic(fmt.Sprint("Error: No name found in github profile something went wrong whilst fetching using gh-cli \n(output from cmd:)", string(data))) + } + } else { + + fmt.Println("Using http request to fetch github profile") + // If the gh command line tool is not installed, use the http request + url := fmt.Sprintf("https://api.github.com/users/%s", username) + + resp, err := http.Get(url) + if err != nil { + panic(fmt.Sprint("Error fetching github profile: ", err)) + } + defer resp.Body.Close() + + // Parse the response and create a user + err = json.NewDecoder(resp.Body).Decode(&profile) + if err != nil { + panic(fmt.Sprint("Error parsing github profile: ", err)) + } + + if profile.Name == "" { + panic(fmt.Sprintf("Error: No name found in github profile something went wrong whilst fetching \n(http response): %s", resp.Status)) + } } + + // Create a user with the github profile return User{ Shortname: strings.ToLower(profile.Name[:2]), From b7729c319426fa8a7de80be43ff4c95a4ea35da7 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 20:00:18 +0200 Subject: [PATCH 03/32] refactor: panic not print --- src/cmd/utils/user_util.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cmd/utils/user_util.go b/src/cmd/utils/user_util.go index 1ae8eea..8bfa797 100644 --- a/src/cmd/utils/user_util.go +++ b/src/cmd/utils/user_util.go @@ -58,13 +58,11 @@ func Define_users(author_file string) { data, err := os.ReadFile(author_file) if err != nil { - fmt.Println("Error reading author file: ", err) - os.Exit(2) + panic(fmt.Sprintf("Error reading author file: %v", err)) } err = json.Unmarshal(data, &auth) if err != nil { - fmt.Println("Error unmarshalling json: ", err) - os.Exit(2) + panic(fmt.Sprintf("Error unmarshalling json: %v", err)) } Authors = auth From 3db2ca2566cdd2bcfa9dbeab94ea14051f5b9c92 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 20:00:37 +0200 Subject: [PATCH 04/32] test: extend test coverage by adding more utils tests --- src/cmd/utils/util_test.go | 269 +++++++++++++++++++++++++++++++++++-- 1 file changed, 258 insertions(+), 11 deletions(-) diff --git a/src/cmd/utils/util_test.go b/src/cmd/utils/util_test.go index 2494836..532c371 100644 --- a/src/cmd/utils/util_test.go +++ b/src/cmd/utils/util_test.go @@ -2,7 +2,11 @@ package utils_test import ( "encoding/json" + "fmt" + "io" + "net/http" "os" + "strings" "testing" "github.com/Slug-Boi/cocommit/src/cmd/utils" @@ -47,7 +51,7 @@ func teardown() { } // Author tests BEGIN -func Test_FindAuthorFile(t* testing.T) { +func Test_FindAuthorFile(t *testing.T) { setup() defer teardown() // Test Find_authorfile @@ -88,9 +92,9 @@ func Test_CreateAuthor(t *testing.T) { Shortname: "epic", Longname: "Test", Username: "TestUser", - Email: "bestemailever@github.io", - Ex: false, - Groups: []string{"test"}, + Email: "bestemailever@github.io", + Ex: false, + Groups: []string{"test"}, } utils.CreateAuthor(author) // Check if author was added @@ -105,7 +109,7 @@ func Test_CreateAuthor(t *testing.T) { if err != nil { t.Errorf("Error reading file: %v", err) } - + //unmarshal the data var authors utils.Author err = json.Unmarshal(author_data, &authors) @@ -117,7 +121,6 @@ func Test_CreateAuthor(t *testing.T) { } } - // Author tests END // User tests BEGIN @@ -131,6 +134,56 @@ func Test_DefineUsers(t *testing.T) { } } +func Test_DefineUsersMultipleGroups(t *testing.T) { + setup() + defer teardown() + + utils.Define_users("author_file_test") + utils.CreateAuthor(utils.User{ + Shortname: "epic", + Longname: "Test", + Username: "TestUser", + Email: "dontcare", + Ex: false, + Groups: []string{"gr1"}, + }) + + if len(utils.Users) != 6 { + t.Errorf("Define_users() = %v; want 6", len(utils.Users)) + } + if len(utils.Groups["gr1"]) != 2 { + t.Errorf("Define_users() = %v; want 2", len(utils.Groups["gr1"])) + } +} + +func Test_DefineUsersPanicOnMissingFile(t *testing.T) { + // Test Define_users panic on missing file + defer func() { + if r := recover(); r == nil { + t.Errorf("Define_users() did not panic on missing file") + } + }() + utils.Define_users("non_existent_file") +} + +func Test_DefineUsersPanicOnInvalidJSON(t *testing.T) { + setup() + defer teardown() + + // Create a file with invalid JSON + invalidJSON := `{"Authors": { "invalid": "data"` + os.WriteFile("invalid_author_file_test", []byte(invalidJSON), 0644) + defer os.Remove("invalid_author_file_test") + + // Test Define_users panic on invalid JSON + defer func() { + if r := recover(); r == nil { + t.Errorf("Define_users() did not panic on invalid JSON") + } + }() + utils.Define_users("invalid_author_file_test") +} + func Test_RemoveUser(t *testing.T) { setup() defer teardown() @@ -138,7 +191,7 @@ func Test_RemoveUser(t *testing.T) { utils.Define_users("author_file_test") utils.RemoveUser("te") - + if len(utils.Users) != 2 { t.Errorf("RemoveUser() = %v; want 2", len(utils.Users)) } @@ -158,17 +211,53 @@ func Test_TempAddUser(t *testing.T) { if len(utils.Users) != 5 { t.Errorf("TempAddUser() = %v; want 5", len(utils.Users)) } - + if _, ok := utils.Users["temp"]; !ok { t.Errorf("TempAddUser() did not add user") } - + } + +func Test_ContainsUser(t *testing.T) { + setup() + defer teardown() + // Test ContainsUser + utils.Define_users("author_file_test") + user := utils.Users["te"] + userList := make([]utils.User, 0, len(utils.Users)) + for _, u := range utils.Users { + userList = append(userList, u) + } + if !utils.ContainsUser(userList, user) { + t.Errorf("ContainsUser() = %v; want true", false) + } + + if utils.ContainsUser(userList, utils.User{}) { + t.Errorf("ContainsUser() = %v; want false", true) + } +} + +func Test_CheckUserFields(t *testing.T) { + setup() + defer teardown() + // Test CheckUserFields + utils.Define_users("author_file_test") + user := utils.Users["te"] + if !utils.CheckUserFields(user) { + t.Errorf("CheckUserFields() = %v; want true", false) + } + + emptyUser := utils.User{} + if utils.CheckUserFields(emptyUser) { + t.Errorf("CheckUserFields() = %v; want false", true) + } +} + // User tests END // Commit tests BEGIN -func Test_Commit(t* testing.T) { +func Test_Commit(t *testing.T) { setup() defer teardown() utils.Define_users("author_file_test") @@ -180,6 +269,66 @@ func Test_Commit(t* testing.T) { t.Errorf("Commit() = %v; want Test commit message\n", commit) } } + +func Test_CommitWithAllAuthors(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + // Test Commit with "all" authors + authors := []string{"all"} + message := "Test commit message with all authors" + commit := utils.Commit(message, authors) + + // Verify that all authors are included in the commit message + for _, user := range utils.Users { + coAuthorLine := fmt.Sprintf("Co-authored-by: %s <%s>", user.Username, user.Email) + if !strings.Contains(commit, coAuthorLine) { + t.Errorf("Commit() missing co-author line: %v", coAuthorLine) + } + } +} + +func Test_CommitWithGroupAuthors(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + // Test Commit with a group of authors + authors := []string{"gr1"} + message := "Test commit message with group authors" + commit := utils.Commit(message, authors) + + // Verify that all group members are included in the commit message + for _, user := range utils.Groups["gr1"] { + coAuthorLine := fmt.Sprintf("Co-authored-by: %s <%s>", user.Username, user.Email) + if !strings.Contains(commit, coAuthorLine) { + t.Errorf("Commit() missing co-author line for group member: %v", coAuthorLine) + } + } +} + +func Test_CommitWithInvalidGroup(t *testing.T) { + setup() + defer teardown() + + // Reset utils.Users and utils.Groups to avoid interference from other tests + utils.Users = make(map[string]utils.User) + utils.Groups = make(map[string][]utils.User) + + utils.Define_users("author_file_test") + + // Test Commit with an invalid group + authors := []string{"invalid_group"} + message := "Test commit message with invalid group" + commit := utils.Commit(message, authors) + + // Verify that no co-author lines are added for the invalid group + if strings.Contains(commit, "Co-authored-by:") { + t.Errorf("Commit() should not include co-author lines for an invalid group msg: %s ", commit) + } +} + // Commit tests END // Github tests BEGIN @@ -207,5 +356,103 @@ func Test_FetchGHProfile(t *testing.T) { t.Errorf("FetchGithubProfile() = %v; want 0", len(profile.Groups)) } } -// Github tests END +func Test_FetchGHProfilePanicOnRequestError(t *testing.T) { + // Test FetchGithubProfile panic on HTTP request error + defer func() { + if r := recover(); r == nil { + t.Errorf("FetchGithubProfile() did not panic on HTTP request error") + } + }() + + // Simulate an invalid URL by using an invalid username + utils.FetchGithubProfile("invalid_username_with_special_characters_@#$") +} + +func Test_FetchGHProfilePanicOnInvalidJSON(t *testing.T) { + // Test FetchGithubProfile panic on invalid JSON response + defer func() { + if r := recover(); r == nil { + t.Errorf("FetchGithubProfile() did not panic on invalid JSON response") + } + }() + + // Mock the HTTP response to return invalid JSON + http.DefaultClient = &http.Client{ + Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(strings.NewReader(`{"invalid_json":`)), + }, nil + }), + } + + utils.FetchGithubProfile("valid_username") +} + +func Test_FetchGHProfilePanicOnHTTPGetError(t *testing.T) { + // Test FetchGithubProfile panic on HTTP GET error + defer func() { + if r := recover(); r == nil { + t.Errorf("FetchGithubProfile() did not panic on HTTP GET error") + } + }() + + // Mock the HTTP client to simulate an error during the GET request + http.DefaultClient = &http.Client{ + Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) { + return nil, fmt.Errorf("simulated HTTP GET error") + }), + } + + utils.FetchGithubProfile("any_username") +} + +type roundTripperFunc func(req *http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func Test_FetchGHProfileHTTP(t *testing.T) { + setup() + defer teardown() + + // Mock the HTTP client to simulate a successful response + mockResponse := `{ + "login": "Slug-Boi", + "name": "Theis", + "email": "", + "bio": "Test bio" + }` + http.DefaultClient = &http.Client{ + Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) { + if req.URL.String() != "https://api.github.com/users/Slug-Boi" { + t.Errorf("Unexpected URL: %v", req.URL.String()) + } + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(strings.NewReader(mockResponse)), + }, nil + }), + } + + // Alias the `gh` command to an error to ensure the GitHub CLI is not used + os.Setenv("PATH", "/nonexistent") + + // Test FetchGithubProfile using HTTP request + profile := utils.FetchGithubProfile("Slug-Boi") + if profile.Username != "Slug-Boi" { + t.Errorf("FetchGithubProfile() = %v; want Slug-Boi", profile.Username) + } + if profile.Longname != "Theis" { + t.Errorf("FetchGithubProfile() = %v; want Theis", profile.Longname) + } + if profile.Email != "" { + t.Errorf("FetchGithubProfile() = %v; want empty email", profile.Email) + } +} + + + +// Github tests END From 33d93c834d622719a158cbbfcf2e008cf814d7e0 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:00:30 +0200 Subject: [PATCH 05/32] refactor: panic and rename variable plus move an error so it can actually trigger --- src/cmd/utils/author_file_utils.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/cmd/utils/author_file_utils.go b/src/cmd/utils/author_file_utils.go index 0cc4d8a..2d3986d 100644 --- a/src/cmd/utils/author_file_utils.go +++ b/src/cmd/utils/author_file_utils.go @@ -13,12 +13,11 @@ import ( // An example of the author file can be found in the examples folder of the repo func Find_authorfile() string { if os.Getenv("author_file") == "" { - authors, err := os.UserConfigDir() + dirs, err := os.UserConfigDir() if err != nil { - fmt.Println("Error getting user config directory") - os.Exit(2) + panic(fmt.Sprintf("Error getting user config directory: %v", err)) } - return (authors + "/cocommit/authors.json") + return (dirs + "/cocommit/authors.json") } else { return os.Getenv("author_file") } @@ -106,6 +105,12 @@ func CreateAuthor(user User) { } func DeleteOneAuthor(author string) { + // check that users aren't empty + if len(Users) < 1 { + fmt.Println("No users to remove") + return + } + author_file := Find_authorfile() if _, exists := Users[author]; !exists { @@ -121,12 +126,6 @@ func DeleteOneAuthor(author string) { } defer file.Close() - // check that users aren't empty - if len(Users) < 1 { - fmt.Println("No users to remove") - return - } - usr := Users[author] // Remove the user from the Author struct (try both short and long name) From 4696f58bf5cb79d8bb591f3b2ba0971885284ffa Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:00:51 +0200 Subject: [PATCH 06/32] refactor: add error returns and flags --- src/cmd/utils/commit.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cmd/utils/commit.go b/src/cmd/utils/commit.go index 1b316fe..8e5b029 100644 --- a/src/cmd/utils/commit.go +++ b/src/cmd/utils/commit.go @@ -58,7 +58,7 @@ if len(excludeMode) > 0 { return sb.String() } -func GitWrapper(commit string, flags []string) { +func GitWrapper(commit string, flags []string) error { // commit shell command // specify git command input := []string{"commit"} @@ -73,22 +73,27 @@ func GitWrapper(commit string, flags []string) { cmd_output, err := cmd.CombinedOutput() if err != nil { - println(fmt.Sprint(err) + " : " + string(cmd_output)) + return fmt.Errorf("error: %s : %s", err, string(cmd_output)) } else { println(string(cmd_output)) } + return nil } -func GitPush() { - cmd := exec.Command("git", "push") +func GitPush(flags []string) error { + + input := []string{"push"} + input = append(input, flags...) + cmd := exec.Command("git", input...) cmd_output, err := cmd.CombinedOutput() if err != nil { - println(fmt.Sprint(err) + " : " + string(cmd_output)) + return fmt.Errorf("error: %s : %s", err, string(cmd_output)) } else { println(string(cmd_output)) } + return nil } // helper function to add an author to the commit message From 81adc7e2c32352705b915a951888e06557a03108 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:01:00 +0200 Subject: [PATCH 07/32] refactor: move error handling --- src/cmd/utils/gh_p_fetcher.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/cmd/utils/gh_p_fetcher.go b/src/cmd/utils/gh_p_fetcher.go index bf6699a..02fb77f 100644 --- a/src/cmd/utils/gh_p_fetcher.go +++ b/src/cmd/utils/gh_p_fetcher.go @@ -48,19 +48,15 @@ func FetchGithubProfile(username string) User { var profile GithubProfile check := checkGHCLI() - + + var err error if check { // If the gh command line tool is installed, use it to fetch the github profile fmt.Println("Using gh-cli to fetch github profile") data := useGHCLI(username) - err := json.Unmarshal(data, &profile) - if err != nil { - panic(fmt.Sprint("Error parsing github profile: ", err)) - } - if profile.Name == "" { - panic(fmt.Sprint("Error: No name found in github profile something went wrong whilst fetching using gh-cli \n(output from cmd:)", string(data))) - } + err = json.Unmarshal(data, &profile) + } else { fmt.Println("Using http request to fetch github profile") @@ -74,17 +70,19 @@ func FetchGithubProfile(username string) User { defer resp.Body.Close() // Parse the response and create a user - err = json.NewDecoder(resp.Body).Decode(&profile) - if err != nil { - panic(fmt.Sprint("Error parsing github profile: ", err)) - } - - if profile.Name == "" { - panic(fmt.Sprintf("Error: No name found in github profile something went wrong whilst fetching \n(http response): %s", resp.Status)) + if err = json.NewDecoder(resp.Body).Decode(&profile); err != nil { + panic(fmt.Sprint("Error decoding github profile: ", err)) } } + // Check error + if err != nil { + panic(fmt.Sprint("Error parsing github profile: ", err)) + } - + // Check if the profile has a name + if profile.Name == "" { + panic(fmt.Sprint("Error: No name found in github profile something went wrong whilst fetching the profile: ", err)) + } // Create a user with the github profile return User{ From aafba935c31fea2d296b8a90eecfd6d6c4597dbb Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:01:19 +0200 Subject: [PATCH 08/32] refactor: error handling and add flags to git push command --- src/cmd/cz.go | 17 +++++++++++++++-- src/cmd/root.go | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/cmd/cz.go b/src/cmd/cz.go index 7c33774..31faff0 100644 --- a/src/cmd/cz.go +++ b/src/cmd/cz.go @@ -27,6 +27,7 @@ This will require the user to have commitizen installed on their system.`, cflag, _ := cmd.Flags().GetBool("cli") gflag, _ := cmd.Flags().GetString("git") gpflag, _ := cmd.Flags().GetBool("git-push") + gpflagsflag, _ := cmd.Flags().GetString("git-push-flags") // run execute commands again as root run will not call this part message = utils.Cz_Call() @@ -53,7 +54,10 @@ This will require the user to have commitizen installed on their system.`, if gflag != "" { git_flags = strings.Split(gflag, " ") } - utils.GitWrapper(message, git_flags) + err := utils.GitWrapper(message, git_flags) + if err != nil { + fmt.Println("Error committing:", err) + } if update { update_msg() @@ -63,8 +67,16 @@ This will require the user to have commitizen installed on their system.`, fmt.Println(message) } + var gp_flags []string + if gpflagsflag != "" { + gp_flags = strings.Split(gpflagsflag, " ") + } + if gpflag { - utils.GitPush() + err := utils.GitPush(gp_flags) + if err != nil { + fmt.Println("Error pushing to git:", err) + } } }, } @@ -75,4 +87,5 @@ func init() { czCmd.Flags().BoolP("print-output", "o", false, "Print the commit message") czCmd.Flags().BoolP("cli", "c", false, "[co-author1] [co-author2] ...") czCmd.Flags().BoolP("git-push", "p", false, "Runs the git push command after the commit") + czCmd.Flags().StringP("git-push-flags", "f", "", "Passes the flags specified to the git push command") } diff --git a/src/cmd/root.go b/src/cmd/root.go index 631d37d..3737e60 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -56,6 +56,7 @@ var rootCmd = &cobra.Command{ vflag, _ := cmd.Flags().GetBool("version") gflag, _ := cmd.Flags().GetString("git") gpflag, _ := cmd.Flags().GetBool("git-push") + gpflagsflag, _ := cmd.Flags().GetString("git-push-flags") if vflag { fmt.Println("Cocommit version:", Coco_Version) @@ -109,13 +110,24 @@ var rootCmd = &cobra.Command{ return } - utils.GitWrapper(message, git_flags) + err := utils.GitWrapper(message, git_flags) + if err != nil { + fmt.Println("Error committing:", err) + } // prints the commit message to the console if the print flag is set if pflag { fmt.Println(message) } + var gp_flags []string + if gpflagsflag != "" { + gp_flags = strings.Split(gpflagsflag, " ") + } + if gpflag { - utils.GitPush() + err := utils.GitPush(gp_flags) + if err != nil { + fmt.Println("Error pushing to remote:", err) + } } }, } @@ -185,4 +197,5 @@ func init() { rootCmd.Flags().BoolP("version", "v", false, "Prints the version of the cocommit cli tool") rootCmd.Flags().StringP("git", "g", "", "Adds the given flags to the git command") rootCmd.Flags().BoolP("git-push", "p", false, "Runs git push after the commit") + rootCmd.Flags().StringP("git-push-flags", "f", "", "Adds the given flags to the git push command") } From 5123e63d9f8ee907802089de0ce5c16e787878f5 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:01:44 +0200 Subject: [PATCH 09/32] test: even more extended test coverage --- src/cmd/utils/util_test.go | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/src/cmd/utils/util_test.go b/src/cmd/utils/util_test.go index 532c371..6626e4f 100644 --- a/src/cmd/utils/util_test.go +++ b/src/cmd/utils/util_test.go @@ -121,6 +121,108 @@ func Test_CreateAuthor(t *testing.T) { } } +func Test_FindAuthorFilePanic(t *testing.T) { + // Save original environment variables + originalAuthorFile := os.Getenv("author_file") + originalHome := os.Getenv("HOME") + + // Test Find_authorfile panic + defer func() { + // Reset environment variables + os.Setenv("author_file", originalAuthorFile) + os.Setenv("HOME", originalHome) + + if r := recover(); r == nil { + t.Errorf("Find_authorfile() did not panic") + } + }() + + os.Setenv("author_file", "") + os.Setenv("HOME", "") + utils.Find_authorfile() +} + +func Test_FindAuthorFileEnv(t *testing.T) { + // Test Find_authorfile with env var + setup() + defer teardown() + os.Setenv("author_file", "") + authorfile := utils.Find_authorfile() + configdir, err := os.UserConfigDir() + if err != nil { + t.Fatalf("Failed to get user config directory: %v", err) + } + if authorfile != configdir+"/cocommit/authors.json" { + t.Errorf("Find_authorfile() = %v; want %v", authorfile, configdir+"/cocommit/authors.json") + } + +} + +func Test_CreateAuthorPanicOnFileError(t *testing.T) { + setup() + defer teardown() + + // Set an invalid author file path to trigger file open error + os.Setenv("author_file", "/invalid/path/author_file_test") + + defer func() { + if r := recover(); r == nil { + t.Errorf("CreateAuthor() did not panic on file open error") + } + }() + + validUser := utils.User{ + Shortname: "valid", + Longname: "ValidUser", + Username: "ValidUser", + Email: "valid@test.io", + Ex: false, + Groups: []string{}, + } + + utils.CreateAuthor(validUser) +} + +func Test_DeleteOneAuthorPrints(t *testing.T) { + setup() + defer teardown() + + // Redirect stdout to capture fmt.Println outputs + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Test case: User not found + utils.Define_users("author_file_test") + utils.DeleteOneAuthor("nonexistent_user") + w.Close() + out, _ := io.ReadAll(r) + os.Stdout = oldStdout + + if !strings.Contains(string(out), "User not found") { + t.Errorf("Expected 'User not found' message, got: %s", string(out)) + } + + // Test case: Error opening file + + // Test case: No users to remove + setup() + defer teardown() + utils.Define_users("author_file_test") + utils.Users = make(map[string]utils.User) // Clear users + r, w, _ = os.Pipe() + os.Stdout = w + + utils.DeleteOneAuthor("te") + w.Close() + out, _ = io.ReadAll(r) + os.Stdout = oldStdout + + if !strings.Contains(string(out), "No users to remove") { + t.Errorf("Expected 'No users to remove' message, got: %s", string(out)) + } +} + // Author tests END // User tests BEGIN @@ -329,6 +431,73 @@ func Test_CommitWithInvalidGroup(t *testing.T) { } } +func Test_CommitWithInlineAdd(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + // Test Commit with inline addition of authors + authors := []string{"te:testtest"} + message := "Test commit message with inline addition" + commit := utils.Commit(message, authors) + + // Verify that the commit message includes the inline addition + splitAuthors := strings.Split(authors[0], ":") + + if !strings.Contains(commit, fmt.Sprintf("Co-authored-by: %s <%s>", splitAuthors[0], splitAuthors[1])) { + t.Errorf("Commit() missing co-author line for inline addition: %v:%v\n%s", splitAuthors[0],splitAuthors[1] ,commit) + } +} + +func Test_CommitWithNegation(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + // Test Commit with negation + authors := []string{"^testtest"} + message := "Test commit message with negation" + commit := utils.Commit(message, authors) + + // Verify that the commit message does not include the negated author + if strings.Contains(commit, "Co-authored-by: testtest") { + t.Errorf("Commit() should not include co-author line for negated author") + } +} + +func Test_GitWrapper(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + + // Test GitWrapper with --dry-run flag + authors := []string{"te"} + message := "Test commit message for GitWrapper" + + commit := utils.Commit(message, authors) + flags := []string{"-a","--dry-run"} + + err := utils.GitWrapper(commit, flags) + if err != nil { + t.Errorf("GitWrapper() returned error: %v", err) + } +} + +func Test_GitPush(t *testing.T) { + setup() + defer teardown() + utils.Define_users("author_file_test") + + // Test GitPush with --dry-run flag + flags := []string{"--dry-run"} + + err := utils.GitPush(flags) + if err != nil { + t.Errorf("GitPush() returned error: %v", err) + } +} + // Commit tests END // Github tests BEGIN From 73020870a17310b1ce3206b76930b2d116173c2a Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 21:17:47 +0200 Subject: [PATCH 10/32] test: add all flag to hopefully fix ci workflow --- src/cmd/utils/util_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/utils/util_test.go b/src/cmd/utils/util_test.go index 6626e4f..3bce2f8 100644 --- a/src/cmd/utils/util_test.go +++ b/src/cmd/utils/util_test.go @@ -490,7 +490,7 @@ func Test_GitPush(t *testing.T) { utils.Define_users("author_file_test") // Test GitPush with --dry-run flag - flags := []string{"--dry-run"} + flags := []string{"--all","--dry-run"} err := utils.GitPush(flags) if err != nil { From c8923525ea3804c682302047dbc91a00c9aae50f Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 22:35:19 +0200 Subject: [PATCH 11/32] refactor(depen_injec): add dependency injection to CheckAuthorFile and change to panics remove comment --- src/cmd/utils/author_file_utils.go | 89 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/cmd/utils/author_file_utils.go b/src/cmd/utils/author_file_utils.go index 2d3986d..0fdd93b 100644 --- a/src/cmd/utils/author_file_utils.go +++ b/src/cmd/utils/author_file_utils.go @@ -3,6 +3,7 @@ package utils import ( "encoding/json" "fmt" + "io" "os" "strings" ) @@ -23,53 +24,55 @@ func Find_authorfile() string { } } -func CheckAuthorFile() string { - var cocommit_folder string - authorfile := Find_authorfile() - if _, err := os.Stat(authorfile); os.IsNotExist(err) { - println("Author file not found at: ", authorfile) - println("Would you like to create one? (y/n)") - var response string - _, err := fmt.Scanln(&response) - if err != nil { - println("Error reading response") - } - if response == "y" { - parts := strings.Split(authorfile, "/") - cocommit_folder = strings.Join(parts[:len(parts)-1], "/") - - // create the author file - if _, dirErr := os.Stat(cocommit_folder); os.IsNotExist(dirErr) { - err := os.Mkdir(cocommit_folder, 0766) - if err != nil { - fmt.Println("Error creating directory: ", err, cocommit_folder) - os.Exit(1) - } - } - file, err := os.Create(authorfile) - if err != nil { - fmt.Println("Error creating file: ", err) - os.Exit(1) +func CheckAuthorFile(input io.Reader, output io.Writer) (string,error) { + var cocommit_folder string + authorfile := Find_authorfile() + + if _, err := os.Stat(authorfile); os.IsNotExist(err) { + fmt.Fprintf(output, "Author file not found at: %s\n", authorfile) + fmt.Fprintf(output, "Would you like to create one? (y/n)\n") + + var response string + _, err := fmt.Fscanln(input, &response) + if err != nil { + fmt.Fprintln(output, "Error reading response") + } + + if response == "y" { + parts := strings.Split(authorfile, "/") + if len(parts) > 1 { + // remove the last part of the path + cocommit_folder = strings.Join(parts[:len(parts)-1], "/") + } else { + cocommit_folder = "." } - defer file.Close() + // create the author file + if _, dirErr := os.Stat(cocommit_folder); os.IsNotExist(dirErr) { + err := os.Mkdir(cocommit_folder, 0766) + if err != nil { + return "", fmt.Errorf("error creating directory: %v %s", err, cocommit_folder) + } + } + + file, err := os.Create(authorfile) + if err != nil { + return "", fmt.Errorf("error creating file: %v", err) + } + defer file.Close() - // write the header to the file - json_string := - `{ - "Authors": { - } + // write the header to the file + json_string := `{ + "Authors": { + } }` - - file.Write([]byte(json_string)) - - fmt.Println("Author file created. To add authors please launch the TUI with -a and press 'C'") - } else { - os.Exit(1) - } - } - // This string output is mostly for convenience can mostly be ignored - return authorfile + file.Write([]byte(json_string)) + fmt.Fprintln(output, "Author file created. To add authors please launch the TUI with -a and press 'C'") + } else { + os.Exit(0) + } + } + return authorfile, nil } func CreateAuthor(user User) { From ee14a9f1413669cf7a07613665a9ccee2499a5d3 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 22:35:52 +0200 Subject: [PATCH 12/32] refactor: add error handler --- src/cmd/root.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/root.go b/src/cmd/root.go index 3737e60..56cd9f4 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -139,11 +139,14 @@ func Execute() { check_update() // author file check - author_file := utils.CheckAuthorFile() + author_file, err := utils.CheckAuthorFile(os.Stdin, os.Stdout) + if err != nil { + panic(fmt.Sprintf("Error checking author file: %v", err)) + } // define users utils.Define_users(author_file) - err := rootCmd.Execute() + err = rootCmd.Execute() if err != nil { os.Exit(1) } From 7cededcdab3a1455594500a645e8315c4e0fed5a Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Wed, 9 Apr 2025 22:36:05 +0200 Subject: [PATCH 13/32] test: final extend to utils test coverage --- src/cmd/utils/util_test.go | 81 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/cmd/utils/util_test.go b/src/cmd/utils/util_test.go index 3bce2f8..8136de6 100644 --- a/src/cmd/utils/util_test.go +++ b/src/cmd/utils/util_test.go @@ -1,6 +1,7 @@ package utils_test import ( + "bytes" "encoding/json" "fmt" "io" @@ -223,6 +224,86 @@ func Test_DeleteOneAuthorPrints(t *testing.T) { } } +func Test_CheckAuthorFile_FileExists(t *testing.T) { + setup() + defer teardown() + + // Ensure the author file exists + authorfile := utils.Find_authorfile() + if _, err := os.Stat(authorfile); os.IsNotExist(err) { + t.Fatalf("Author file does not exist: %v", authorfile) + } + + // Mock user input to simulate "y" response + input := strings.NewReader("y\n") + output := new(bytes.Buffer) // capture output + + // Test CheckAuthorFile when the file exists + result, err := utils.CheckAuthorFile(input, output) + if err != nil { + t.Fatalf("CheckAuthorFile() returned error: %v", err) + } + if result != authorfile { + t.Errorf("CheckAuthorFile() = %v; want %v", result, authorfile) + } +} + +func Test_CheckAuthorFile_FileNotExists_CreateFile(t *testing.T) { + setup() + defer teardown() + + originalEnv := os.Getenv("author_file") + defer os.Setenv("author_file", originalEnv) + + os.Setenv("author_file", "author_file_test") + // Remove the author file to simulate non-existence + authorfile := utils.Find_authorfile() + os.Remove(authorfile) + + // Mock user input to simulate "y" response + input := strings.NewReader("y\n") + output := new(bytes.Buffer) // capture output + + + + // Test CheckAuthorFile when the file does not exist and user agrees to create it + result, err := utils.CheckAuthorFile(input, output) + if err != nil { + t.Fatalf("CheckAuthorFile() returned error: %v", err) + } + + if result != authorfile { + panic(fmt.Sprintf("CheckAuthorFile() = %v; want %v", result, authorfile)) + } +} + +func Test_CheckAuthorFile_FileNotExists_DeclineCreate(t *testing.T) { + setup() + defer teardown() + + // Remove the author file to simulate non-existence + authorfile := utils.Find_authorfile() + os.Remove(authorfile) + + // Mock user input to simulate "n" response + input := strings.NewReader("n\n") + output := new(bytes.Buffer) // capture output + + + + // Test CheckAuthorFile when the file does not exist and user declines to create it + defer func() { + if r := recover(); r == nil { + t.Errorf("CheckAuthorFile() did not exit when user declined to create the file") + } + }() + utils.CheckAuthorFile(input, output) + // Check if the output contains the expected message + if !strings.Contains(output.String(), "") { + t.Errorf("Expected no message found output: %s", output.String()) + } +} + // Author tests END // User tests BEGIN From 1d432f61ed1a6050fee2b8e7388c7d959978c881 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:16:48 +0200 Subject: [PATCH 14/32] refactor: longname and remove emptystring on errors --- src/cmd/tui/tui_author.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/tui/tui_author.go b/src/cmd/tui/tui_author.go index ff84351..1d16075 100644 --- a/src/cmd/tui/tui_author.go +++ b/src/cmd/tui/tui_author.go @@ -50,9 +50,9 @@ func errorGetMissingFields(m model_ca) { } if len(m.inputs) > 0 { - for i := 0; i < inpLen; i++ { + for i := 0; i < inpLen-1; i++ { if m.inputs[i].Value() == "" { - m.errorModel.missing = append(m.errorModel.missing, "- "+strings.Split(m.inputs[i].Placeholder,"(")[0]) + m.errorModel.missing = append(m.errorModel.missing, "- "+strings.Split(m.inputs[i].Placeholder," (")[0]) } } } else { @@ -115,7 +115,7 @@ func createAuthorModel(old_m *model) model_ca { t.PromptStyle = focusedStyle t.TextStyle = focusedStyle case 1: - t.Placeholder = "Long name (e.g. JohnDoe)" + t.Placeholder = "Longname (e.g. JohnDoe)" case 2: t.Placeholder = "Username (e.g. JohnDoe-gh)" case 3: @@ -158,7 +158,7 @@ func createGHAuthorModel(old_m *model, user utils.User) model_ca { t.PromptStyle = focusedStyle t.TextStyle = focusedStyle case 1: - t.Placeholder = "Long name (e.g. JohnDoe)" + t.Placeholder = "Longname (e.g. JohnDoe)" t.SetValue(user.Longname) case 2: t.Placeholder = "Username (e.g. JohnDoe-gh)" From e8933bc764ca62b9e706a83bd069a31f7c00dcfe Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:16:57 +0200 Subject: [PATCH 15/32] refactor: use panic --- src/cmd/tui/tui_show_users.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cmd/tui/tui_show_users.go b/src/cmd/tui/tui_show_users.go index 7269d43..c850657 100644 --- a/src/cmd/tui/tui_show_users.go +++ b/src/cmd/tui/tui_show_users.go @@ -87,8 +87,7 @@ func intialModel_US(author_file string) tea.Model { model, err := newExample() if err != nil { - fmt.Println("Could not initialize Bubble Tea model:", err) - os.Exit(1) + panic(fmt.Sprintf("Could not initialize Bubble Tea model: %v", err)) } return model } @@ -96,8 +95,7 @@ func intialModel_US(author_file string) tea.Model { func loadData(author_file string) { file, err := os.Open(author_file) if err != nil { - fmt.Println("Could not open file:", err) - os.Exit(1) + panic(fmt.Sprintf("Could not open author file: %v", err)) } scanner := bufio.NewScanner(file) From e7656ae4e0b01b0a2e3ac786343dc9a5dc447e5b Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:17:08 +0200 Subject: [PATCH 16/32] test: extend tui test coverage --- src/cmd/tui/tui_test.go | 192 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 6 deletions(-) diff --git a/src/cmd/tui/tui_test.go b/src/cmd/tui/tui_test.go index 2889ff1..54aaa62 100644 --- a/src/cmd/tui/tui_test.go +++ b/src/cmd/tui/tui_test.go @@ -2,6 +2,7 @@ package tui import ( "bytes" + "fmt" "os" "strings" "testing" @@ -77,12 +78,47 @@ func TestShowUser(t *testing.T) { return bytes.Contains(bts, []byte("\"Authors\": {")) }, teatest.WithCheckInterval(time.Millisecond*100), teatest.WithDuration(time.Second*2)) + keyPress(tm, "enter") + keyPress(tm, "q") tm.WaitFinished(t, teatest.WithFinalTimeout(time.Second)) } +func TestShowUserPanicFileNotFound(t *testing.T) { + setup() + defer teardown() + + // Use defer with recover to catch panics + defer func() { + if r := recover(); r != nil { + t.Logf("Recovered from expected panic: %v", r) + // You can optionally verify the panic message here + if !strings.Contains(fmt.Sprint(r), "Could not open author file:") { + t.Errorf("Unexpected panic message: %v", r) + } + } + }() + + m := intialModel_US("non_existent_file") + tm := teatest.NewTestModel( + t, m, + teatest.WithInitialTermSize(300, 300), + ) + + // Verify error message appears in output + teatest.WaitFor(t, tm.Output(), func(bts []byte) bool { + return bytes.Contains(bts, []byte("could not open author file")) + }, teatest.WithCheckInterval(time.Millisecond*100), teatest.WithDuration(time.Second*2)) + + // Send quit command + keyPress(tm, "q") + + // Wait for clean shutdown + tm.WaitFinished(t, teatest.WithFinalTimeout(time.Second)) +} + // tui_show_users TESTS END // tui_author TESTS BEGIN @@ -132,6 +168,90 @@ func TestEntryTA(t *testing.T) { } } +func TestErrorGetMissingFields(t *testing.T) { + setup() + defer teardown() + + + // Test case 1: No inputs + m := createAuthorModel(nil) + errorGetMissingFields(m) + if len(m.errorModel.missing) != 4 { + t.Errorf("Expected 4 missing fields, got %d\n%v", len(m.errorModel.missing), m.errorModel.missing) + } + + m = createAuthorModel(nil) + + m.inputs[0].SetValue("") + m.inputs[1].SetValue("value") + m.inputs[2].SetValue("") + m.inputs[3].SetValue("value") + + tempAuthorToggle = false + errorGetMissingFields(m) + expectedMissing := []string{"- Shortname", "- Username"} + if len(m.errorModel.missing) != len(expectedMissing) { + t.Errorf("Expected %d missing fields, got %d", len(expectedMissing), len(m.errorModel.missing)) + } + for i, missing := range expectedMissing { + if m.errorModel.missing[i] != missing { + t.Errorf("Expected '%s', got '%s'", missing, m.errorModel.missing[i]) + } + } + + m = createAuthorModel(nil) + + m.inputs[0].SetValue("value1") + m.inputs[1].SetValue("value2") + m.inputs[2].SetValue("value3") + m.inputs[3].SetValue("value4") + m.inputs[4].SetValue("value5") + + tempAuthorToggle = true + errorGetMissingFields(m) + if len(m.errorModel.missing) != 0 { + t.Errorf("Expected no missing fields, got %v", m.errorModel.missing) + } +} + +func Test_EntryCA_TriggerError(t *testing.T) { + setup() + defer teardown() + + m := listModel() + + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + keyPress(tm, "C") + + keyPress(tm, "enter") + + tm.Type("test") + + keyPress(tm, "enter") + + tm.Type("testing2") + keyPress(tm, "enter") + + keyPress(tm, "enter") + keyPress(tm, "tab") + keyPress(tm, "enter") + keyPress(tm, "esc") + keyPress(tm, "esc") + keyPress(tm, "esc") + + fm := tm.FinalModel(t) + mm, ok := fm.(model) + if !ok { + t.Errorf("Expected model_ca, got %T", fm) + } + + if len(mm.list.Items()) != 2 { + t.Errorf("Expected 2 inputs, got %d\n%v", len(mm.list.Items()), mm.list.Items()) + } +} + func Test_EntryCA(t *testing.T) { setup() defer teardown() @@ -208,6 +328,8 @@ func Test_EntryCM(t *testing.T) { t, m, teatest.WithInitialTermSize(300, 300), ) tm.Type("test commit message") + keyPress(tm, "shift+tab") + tm.Type("new line") keyPress(tm, "enter") @@ -217,11 +339,56 @@ func Test_EntryCM(t *testing.T) { t.Errorf("Expected model_cm, got %T", fm) } - if m.textarea.Value() != "test commit message" { + if m.textarea.Value() != "test commit message\nnew line" { t.Errorf("Expected 'test commit message', got %s", m.textarea.Value()) } } +func Test_EntryCM_Quit(t *testing.T) { + setup() + defer teardown() + + m := initialModel_cm() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + keyPress(tm, "esc") + + fm := tm.FinalModel(t) + m, ok := fm.(model_cm) + if !ok { + t.Errorf("Expected model_cm, got %T", fm) + } + + if m.textarea.Value() != "" { + t.Errorf("Expected empty textarea, got %s", m.textarea.Value()) + } +} +// cannot test sigkill as it does not play nicely with these types of tests :( + +func Test_EntryCM_Unfocuse(t *testing.T) { + setup() + defer teardown() + + m := initialModel_cm() + tm := teatest.NewTestModel( + t, m, teatest.WithInitialTermSize(300, 300), + ) + keyPress(tm, "down") + + keyPress(tm, "esc") + + fm := tm.FinalModel(t) + m, ok := fm.(model_cm) + if !ok { + t.Errorf("Expected model_cm, got %T", fm) + } + + if m.textarea.Value() != "" { + t.Errorf("Expected empty textarea, got %s", m.textarea.Value()) + } +} + // tui_commit_message TESTS END // tui_list TESTS BEGIN @@ -363,7 +530,7 @@ func Test_GroupSelection(t *testing.T) { keyPress(tm, "enter") fm := tm.FinalModel(t) - m, ok := fm.(model) + _, ok := fm.(model) if !ok { t.Errorf("Expected model, got %T", fm) } @@ -377,7 +544,19 @@ func Test_pagination(t *testing.T) { setup() defer teardown() - m := mainModel{} + // Add 20 authors to the test data + for i := 0; i < 20; i++ { + utils.Users[fmt.Sprintf("author%d", i)] = utils.User{ + Shortname: fmt.Sprintf("a%d", i), + Longname: fmt.Sprintf("Author %d", i), + Username: fmt.Sprintf("AuthorUser%d", i), + Email: fmt.Sprintf("author%d@test.com", i), + Ex: false, + Groups: []string{}, + } + } + + m := listModel() tm := teatest.NewTestModel( t, m, teatest.WithInitialTermSize(25, 25), @@ -387,14 +566,15 @@ func Test_pagination(t *testing.T) { tm.Quit() fm := tm.FinalModel(t) - m, ok := fm.(mainModel) + m, ok := fm.(model) if !ok { t.Errorf("Expected model, got %T", fm) } - if m.paginator.Page != 1 { - t.Errorf("Expected page 1, got %d", m.paginator.Page) + if m.list.Paginator.Page != 1 { + t.Errorf("Expected page 1, got %d", m.list.Paginator.Page) } } + // tui_groups TESTS END From 5cd8ee63b6ce9f6202365a41d174898899bfca65 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:43:24 +0200 Subject: [PATCH 17/32] test: increase test coverage of tui to around 70% --- src/cmd/tui/tui_test.go | 123 ++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 31 deletions(-) diff --git a/src/cmd/tui/tui_test.go b/src/cmd/tui/tui_test.go index 54aaa62..ff2302a 100644 --- a/src/cmd/tui/tui_test.go +++ b/src/cmd/tui/tui_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/Slug-Boi/cocommit/src/cmd/utils" + "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/x/exp/teatest" ) @@ -87,36 +88,36 @@ func TestShowUser(t *testing.T) { } func TestShowUserPanicFileNotFound(t *testing.T) { - setup() - defer teardown() + setup() + defer teardown() - // Use defer with recover to catch panics - defer func() { - if r := recover(); r != nil { - t.Logf("Recovered from expected panic: %v", r) - // You can optionally verify the panic message here - if !strings.Contains(fmt.Sprint(r), "Could not open author file:") { - t.Errorf("Unexpected panic message: %v", r) - } - } - }() + // Use defer with recover to catch panics + defer func() { + if r := recover(); r != nil { + t.Logf("Recovered from expected panic: %v", r) + // You can optionally verify the panic message here + if !strings.Contains(fmt.Sprint(r), "Could not open author file:") { + t.Errorf("Unexpected panic message: %v", r) + } + } + }() - m := intialModel_US("non_existent_file") - tm := teatest.NewTestModel( - t, m, - teatest.WithInitialTermSize(300, 300), - ) - - // Verify error message appears in output - teatest.WaitFor(t, tm.Output(), func(bts []byte) bool { - return bytes.Contains(bts, []byte("could not open author file")) - }, teatest.WithCheckInterval(time.Millisecond*100), teatest.WithDuration(time.Second*2)) + m := intialModel_US("non_existent_file") + tm := teatest.NewTestModel( + t, m, + teatest.WithInitialTermSize(300, 300), + ) - // Send quit command - keyPress(tm, "q") + // Verify error message appears in output + teatest.WaitFor(t, tm.Output(), func(bts []byte) bool { + return bytes.Contains(bts, []byte("could not open author file")) + }, teatest.WithCheckInterval(time.Millisecond*100), teatest.WithDuration(time.Second*2)) - // Wait for clean shutdown - tm.WaitFinished(t, teatest.WithFinalTimeout(time.Second)) + // Send quit command + keyPress(tm, "q") + + // Wait for clean shutdown + tm.WaitFinished(t, teatest.WithFinalTimeout(time.Second)) } // tui_show_users TESTS END @@ -172,7 +173,6 @@ func TestErrorGetMissingFields(t *testing.T) { setup() defer teardown() - // Test case 1: No inputs m := createAuthorModel(nil) errorGetMissingFields(m) @@ -316,6 +316,67 @@ func Test_EntryCA(t *testing.T) { } +func TestModelCAInit(t *testing.T) { + setup() + defer teardown() + + m := model_ca{} + cmd := m.Init() + + if cmd == nil { + t.Errorf("Expected a non-nil command, got nil") + } + + if cmd() != textinput.Blink() { + t.Errorf("Expected textinput.Blink command, got a different command") + } +} + + +func TestCreateGHAuthorModel(t *testing.T) { + setup() + defer teardown() + + // Define a test user + testUser := utils.User{ + Shortname: "gh", + Longname: "GitHubUser", + Username: "GitHubUser-gh", + Email: "github@user.com", + Groups: []string{"grp1", "grp2"}, + } + + // Create the model using the test user + m := createGHAuthorModel(nil, testUser) + + // Verify the inputs are correctly initialized + if m.inputs[0].Value() != testUser.Shortname { + t.Errorf("Expected Shortname '%s', got '%s'", testUser.Shortname, m.inputs[0].Value()) + } + + if m.inputs[1].Value() != testUser.Longname { + t.Errorf("Expected Longname '%s', got '%s'", testUser.Longname, m.inputs[1].Value()) + } + + if m.inputs[2].Value() != testUser.Username { + t.Errorf("Expected Username '%s', got '%s'", testUser.Username, m.inputs[2].Value()) + } + + if m.inputs[3].Value() != "" { + t.Errorf("Expected Email to be empty, got '%s'", m.inputs[3].Value()) + } + + expectedGroups := strings.Join(testUser.Groups, "|") + if m.inputs[4].Value() != expectedGroups { + t.Errorf("Expected Groups '%s', got '%s'", expectedGroups, m.inputs[4].Value()) + } + + // Verify the first input is focused + if !m.inputs[0].Focused() { + t.Errorf("Expected first input to be focused") + } +} + // tui_author TESTS END // tui_commit_message TESTS BEGIN @@ -364,7 +425,8 @@ func Test_EntryCM_Quit(t *testing.T) { t.Errorf("Expected empty textarea, got %s", m.textarea.Value()) } } -// cannot test sigkill as it does not play nicely with these types of tests :( + +// cannot test sigkill as it does not play nicely with these types of tests :( func Test_EntryCM_Unfocuse(t *testing.T) { setup() @@ -375,7 +437,7 @@ func Test_EntryCM_Unfocuse(t *testing.T) { t, m, teatest.WithInitialTermSize(300, 300), ) keyPress(tm, "down") - + keyPress(tm, "esc") fm := tm.FinalModel(t) @@ -557,7 +619,7 @@ func Test_pagination(t *testing.T) { } m := listModel() - + tm := teatest.NewTestModel( t, m, teatest.WithInitialTermSize(25, 25), ) @@ -576,5 +638,4 @@ func Test_pagination(t *testing.T) { } } - // tui_groups TESTS END From cf392035d32f65572e78357631281bbb2f42d26b Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:43:46 +0200 Subject: [PATCH 18/32] ci: export cover report and add it to page wiki for badge --- .github/workflows/test_push.yml | 14 +++++++++++++- ci/test_on_push.go | 8 +++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index da15206..8be4c54 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -20,4 +20,16 @@ jobs: - name: Get Dagger run: cd ci && go get dagger.io/dagger@latest && cd .. - name: Run Dagger Test Workflow - run: go run ci/test_on_push.go \ No newline at end of file + run: go run ci/test_on_push.go + + - name: Update coverage report + uses: ncruces/go-coverage-report@v0 + with: + coverage-file: cover.out + report: true + chart: true + amend: true + if: | + matrix.os == 'ubuntu-latest' && + github.event_name == 'push' + continue-on-error: true \ No newline at end of file diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 17edfd5..30b4f8d 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -35,10 +35,16 @@ func main() { WithExec([]string{"go", "mod", "tidy"}).WithEnvVariable("CI", "true") // run application tests - out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./..."}). + out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile cover.out"}). Stderr(ctx) if err != nil { panic(err) } fmt.Println(out) + + // export the coverage report + _, err = client.Host().Directory(".").WithFile("cover.out", runner.File("/src_d/src/cover.out")).Export(ctx, ".") + if err != nil { + panic(err) + } } \ No newline at end of file From fdf5dc51d7c32a9cdeccde6dcb698427f6d702fa Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:46:40 +0200 Subject: [PATCH 19/32] ci: split flag into 2 inputs --- ci/test_on_push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 30b4f8d..d38b178 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -35,7 +35,7 @@ func main() { WithExec([]string{"go", "mod", "tidy"}).WithEnvVariable("CI", "true") // run application tests - out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile cover.out"}). + out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile", "cover.out"}). Stderr(ctx) if err != nil { panic(err) From a769e8e9abb58927dc2b0694879f19281e98280d Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:49:42 +0200 Subject: [PATCH 20/32] ci: change location of cover.out search --- ci/test_on_push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index d38b178..c18ef3d 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -43,7 +43,7 @@ func main() { fmt.Println(out) // export the coverage report - _, err = client.Host().Directory(".").WithFile("cover.out", runner.File("/src_d/src/cover.out")).Export(ctx, ".") + _, err = client.Host().Directory(".").WithFile("cover.out", runner.File("./cover.out")).Export(ctx, ".") if err != nil { panic(err) } From 1df68cb8015b2c77fa13e924e8c5a15e82a614a5 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 12:49:42 +0200 Subject: [PATCH 21/32] ci: change location of cover.out search ci: same --- ci/test_on_push.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index d38b178..75d62f4 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -43,8 +43,8 @@ func main() { fmt.Println(out) // export the coverage report - _, err = client.Host().Directory(".").WithFile("cover.out", runner.File("/src_d/src/cover.out")).Export(ctx, ".") - if err != nil { - panic(err) - } + _, err = runner.File("/src_d/src/cover.out").Export(ctx, "./cover.out") +if err != nil { + panic(err) +} } \ No newline at end of file From 198a86e80388dbae51cb5326e5593194f93da8f4 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:00:55 +0200 Subject: [PATCH 22/32] ci: try to find cover.out ci: mismatch return --- ci/test_on_push.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 75d62f4..84bbfd4 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -42,6 +42,9 @@ func main() { } fmt.Println(out) + out, err = runner.WithExec([]string{"find", "-name", "cover.out"}).Stdout(ctx) + fmt.Println(out) + // export the coverage report _, err = runner.File("/src_d/src/cover.out").Export(ctx, "./cover.out") if err != nil { From cb0658fa6f9a395a2af9becb1f8a867b7ac7a10c Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:11:45 +0200 Subject: [PATCH 23/32] ci: try to move workdir --- ci/test_on_push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 84bbfd4..c560046 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -46,7 +46,7 @@ func main() { fmt.Println(out) // export the coverage report - _, err = runner.File("/src_d/src/cover.out").Export(ctx, "./cover.out") + _, err = runner.WithWorkdir("/").File("/src_d/src/cover.out").Export(ctx, "./cover.out") if err != nil { panic(err) } From 940576eb1dacdb3f81b328a017435db6aadbb575 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:15:30 +0200 Subject: [PATCH 24/32] ci: ls --- ci/test_on_push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index c560046..01d96de 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -42,7 +42,7 @@ func main() { } fmt.Println(out) - out, err = runner.WithExec([]string{"find", "-name", "cover.out"}).Stdout(ctx) + out, err = runner.WithExec([]string{"ls"}).Stdout(ctx) fmt.Println(out) // export the coverage report From 7c2f67e39b8bcbf61f371ecc257521de310f4e8a Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:22:44 +0200 Subject: [PATCH 25/32] ci: try to = name and find file from root --- ci/test_on_push.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 01d96de..3ea22a0 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -35,14 +35,14 @@ func main() { WithExec([]string{"go", "mod", "tidy"}).WithEnvVariable("CI", "true") // run application tests - out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile", "cover.out"}). + out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile=cover.out"}). Stderr(ctx) if err != nil { panic(err) } fmt.Println(out) - out, err = runner.WithExec([]string{"ls"}).Stdout(ctx) + out, err = runner.WithExec([]string{"find", "/", "-name", "cover.out"}).Stdout(ctx) fmt.Println(out) // export the coverage report From 6153ab95e657e770a2f29e4668bd6a1b65a36426 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:26:32 +0200 Subject: [PATCH 26/32] ci: apparently dagger cannot generate a coverage report lol --- .github/workflows/test_push.yml | 3 ++- ci/test_on_push.go | 11 +---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index 8be4c54..82645c6 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -21,7 +21,8 @@ jobs: run: cd ci && go get dagger.io/dagger@latest && cd .. - name: Run Dagger Test Workflow run: go run ci/test_on_push.go - + - name: Generate Coverage Report + run: go test -coverprofile=cover.out ./src/cmd/utils ./src/cmd/tui - name: Update coverage report uses: ncruces/go-coverage-report@v0 with: diff --git a/ci/test_on_push.go b/ci/test_on_push.go index 3ea22a0..17edfd5 100644 --- a/ci/test_on_push.go +++ b/ci/test_on_push.go @@ -35,19 +35,10 @@ func main() { WithExec([]string{"go", "mod", "tidy"}).WithEnvVariable("CI", "true") // run application tests - out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./cmd/utils", "./cmd/tui", "-coverprofile=cover.out"}). + out, err := runner.WithWorkdir("/src_d/src").WithExec([]string{"go", "test", "./..."}). Stderr(ctx) if err != nil { panic(err) } fmt.Println(out) - - out, err = runner.WithExec([]string{"find", "/", "-name", "cover.out"}).Stdout(ctx) - fmt.Println(out) - - // export the coverage report - _, err = runner.WithWorkdir("/").File("/src_d/src/cover.out").Export(ctx, "./cover.out") -if err != nil { - panic(err) -} } \ No newline at end of file From 3e4c01c8bdfd1e66ff6e04b4efba83d7ed21bbd5 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:31:01 +0200 Subject: [PATCH 27/32] test: fix linux not panic on authorfile test --- src/cmd/utils/util_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/utils/util_test.go b/src/cmd/utils/util_test.go index 8136de6..a3431e0 100644 --- a/src/cmd/utils/util_test.go +++ b/src/cmd/utils/util_test.go @@ -126,20 +126,25 @@ func Test_FindAuthorFilePanic(t *testing.T) { // Save original environment variables originalAuthorFile := os.Getenv("author_file") originalHome := os.Getenv("HOME") + orignalXDG := os.Getenv("XDG_CONFIG_HOME") // Test Find_authorfile panic defer func() { // Reset environment variables os.Setenv("author_file", originalAuthorFile) os.Setenv("HOME", originalHome) + os.Setenv("XDG_CONFIG_HOME", orignalXDG) if r := recover(); r == nil { t.Errorf("Find_authorfile() did not panic") } }() + // Set environment variables to empty strings + // to trigger the panic os.Setenv("author_file", "") os.Setenv("HOME", "") + os.Setenv("XDG_CONFIG_HOME", "") utils.Find_authorfile() } From c78f72bf47920b0f95bbcc8000c94eb33058a0a0 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 13:36:44 +0200 Subject: [PATCH 28/32] ci: check error --- .github/workflows/test_push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index 82645c6..cb28c70 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -26,11 +26,11 @@ jobs: - name: Update coverage report uses: ncruces/go-coverage-report@v0 with: - coverage-file: cover.out + coverage-file: ./cover.out report: true chart: true amend: true if: | matrix.os == 'ubuntu-latest' && github.event_name == 'push' - continue-on-error: true \ No newline at end of file + #continue-on-error: true \ No newline at end of file From e6df1344e9ffd05bdbc4ea97a7c1308858d8ad1f Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 18:08:28 +0200 Subject: [PATCH 29/32] ci: try to remove file path --- .github/workflows/test_push.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index cb28c70..be0a79b 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -21,16 +21,15 @@ jobs: run: cd ci && go get dagger.io/dagger@latest && cd .. - name: Run Dagger Test Workflow run: go run ci/test_on_push.go - - name: Generate Coverage Report - run: go test -coverprofile=cover.out ./src/cmd/utils ./src/cmd/tui + # - name: Generate Coverage Report + # run: go test -v ./... - name: Update coverage report uses: ncruces/go-coverage-report@v0 with: - coverage-file: ./cover.out report: true chart: true amend: true if: | matrix.os == 'ubuntu-latest' && github.event_name == 'push' - #continue-on-error: true \ No newline at end of file + continue-on-error: true \ No newline at end of file From 3587998d6625de94e05cb992c777ba9d33765718 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 18:19:17 +0200 Subject: [PATCH 30/32] ci: fix version of ci plugin --- .github/workflows/test_push.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index da15206..00745b5 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -20,4 +20,17 @@ jobs: - name: Get Dagger run: cd ci && go get dagger.io/dagger@latest && cd .. - name: Run Dagger Test Workflow - run: go run ci/test_on_push.go \ No newline at end of file + run: go run ci/test_on_push.go + - name: Generate Coverage Report + run: CI=true go test -coverprofile=coverage.out ./... + - name: Update coverage report + uses: ncruces/go-coverage-report@v0.3.0 + with: + coverage-file: coverage.out + report: true + chart: true + amend: true + if: | + matrix.os == 'ubuntu-latest' && + github.event_name == 'push' + continue-on-error: true From e327621bcb58fc5e218b605332c68e1112d9b52e Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 18:28:19 +0200 Subject: [PATCH 31/32] ci: change to codecov instead --- .github/workflows/test_push.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index 00745b5..e1c3d19 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -22,15 +22,9 @@ jobs: - name: Run Dagger Test Workflow run: go run ci/test_on_push.go - name: Generate Coverage Report - run: CI=true go test -coverprofile=coverage.out ./... - - name: Update coverage report - uses: ncruces/go-coverage-report@v0.3.0 + run: CI=true go test -coverprofile=coverage.txt ./... + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 with: - coverage-file: coverage.out - report: true - chart: true - amend: true - if: | - matrix.os == 'ubuntu-latest' && - github.event_name == 'push' + token: ${{ secrets.CODECOV_TOKEN }} continue-on-error: true From 4167f2916381f11d76bc9164dbcbc49115e96df1 Mon Sep 17 00:00:00 2001 From: Slug-Boi Date: Thu, 10 Apr 2025 18:34:49 +0200 Subject: [PATCH 32/32] docs: add coverage badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 16a05f3..0902eda 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@

Github Latest Release Github Actions Tests - Github Actions Build + Github Actions Build + Go Reference Co-Author Docs Github Page