mirror of
https://github.com/Slug-Boi/cocommit.git
synced 2026-05-13 20:55:47 +00:00
chore: rename src folder
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Author file utils is a package that contains functions that are used to read
|
||||
// check, and potentially write to the author file. The author file is a file
|
||||
// that contains the names and emails of the users that are allowed to commit
|
||||
// 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()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting user config directory")
|
||||
os.Exit(2)
|
||||
}
|
||||
return (authors + "/cocommit/authors")
|
||||
} else {
|
||||
return os.Getenv("author_file")
|
||||
}
|
||||
}
|
||||
|
||||
func CheckAuthorFile() 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" {
|
||||
if authorfile == "" {
|
||||
fmt.Println("author_file environment variable not set using default location:")
|
||||
config, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
fmt.Println("Error getting user config directory")
|
||||
os.Exit(1)
|
||||
}
|
||||
authorfile = config + "/cocommit/authors"
|
||||
fmt.Println(authorfile)
|
||||
}
|
||||
|
||||
// create the author file
|
||||
file, err := os.Create(authorfile)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file: ", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// write the header to the file
|
||||
file.WriteString("Syntax: name_short|Name|Username|email (opt: |ex) (opt: ;;group1|group2|group3...)\n")
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func DeleteOneAuthor(author string) {
|
||||
author_file := Find_authorfile()
|
||||
|
||||
// open author_file
|
||||
file, err := os.OpenFile(author_file, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
// create regex to capture author line
|
||||
regexp, err := regexp.Compile(fmt.Sprintf("^(.+\\|%s\\|.+|%s\\|.+\\|.+)$", author, author))
|
||||
if err != nil {
|
||||
fmt.Println("Error compiling regex: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
|
||||
// create a scanner for the file
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// write the header to the buffer
|
||||
scanner.Scan()
|
||||
buf.WriteString(scanner.Text() + "\n")
|
||||
|
||||
// check if author matches the regex and skip
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if regexp.MatchString(line) {
|
||||
continue
|
||||
}
|
||||
buf.WriteString(line + "\n")
|
||||
|
||||
}
|
||||
// remove the last newline character
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
|
||||
file.Truncate(0)
|
||||
file.Seek(0, 0)
|
||||
buf.WriteTo(file)
|
||||
|
||||
RemoveUser(author)
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
// 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
|
||||
} else if Groups[fst] != nil {
|
||||
excludeMode = group_selection(Groups[fst], excludeMode)
|
||||
add_x_users(excludeMode)
|
||||
goto skip_loop
|
||||
}
|
||||
|
||||
// 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, ":")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// Skip label for edge cases at top of function
|
||||
skip_loop:
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func GitWrapper(commit string) {
|
||||
// commit shell command
|
||||
cmd := exec.Command("git", "commit", "-m", commit)
|
||||
|
||||
// https://stackoverflow.com/questions/18159704/how-to-debug-exit-status-1-error-when-running-exec-command-in-golang
|
||||
|
||||
cmd_output, err := cmd.CombinedOutput()
|
||||
|
||||
if err != nil {
|
||||
println(fmt.Sprint(err) + " : " + string(cmd_output))
|
||||
} else {
|
||||
println(string(cmd_output))
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to add an author to the commit message
|
||||
func sb_author(committer string) {
|
||||
sb.WriteString("\nCo-authored-by: ")
|
||||
sb.WriteString(Users[committer].Username)
|
||||
sb.WriteString(" <")
|
||||
sb.WriteString(Users[committer].Email)
|
||||
sb.WriteRune('>')
|
||||
}
|
||||
|
||||
// helper function to add x amount of users to the commit message
|
||||
func add_x_users(excludeMode []string) {
|
||||
if len(DefExclude) > 0 {
|
||||
excludeMode = append(excludeMode, DefExclude...)
|
||||
}
|
||||
for key, user := range Users {
|
||||
if !slices.Contains(excludeMode, user.Username) {
|
||||
sb_author(key)
|
||||
excludeMode = append(excludeMode, user.Username)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to select groups of users to exclude in the commit message
|
||||
func group_selection(group []User, excludeMode []string) []string {
|
||||
for _, user := range Users {
|
||||
if !(slices.Contains(group, user)) {
|
||||
excludeMode = append(excludeMode, user.Username)
|
||||
}
|
||||
}
|
||||
|
||||
return excludeMode
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Cz_Call() string {
|
||||
|
||||
// create commitizen command
|
||||
cmd := exec.Command("cz", "commit", "--dry-run", "--write-message-to-file", "msg")
|
||||
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
// if the user exits the commitizen command, exit the program
|
||||
if strings.Contains(err.Error(), "exit status 8") {
|
||||
os.Exit(0)
|
||||
}
|
||||
panic(fmt.Sprint(err))
|
||||
}
|
||||
|
||||
file, err := os.OpenFile("msg", os.O_RDONLY, 0644)
|
||||
defer os.Remove("msg")
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
panic(fmt.Sprint(err))
|
||||
}
|
||||
msg, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
panic(fmt.Sprint(err))
|
||||
}
|
||||
|
||||
return string(msg)
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// This util file is used to handle users and their information
|
||||
type User struct {
|
||||
Username string
|
||||
Email string
|
||||
Names string
|
||||
}
|
||||
|
||||
var Users = map[string]User{}
|
||||
var DefExclude = []string{}
|
||||
var Groups = map[string][]User{}
|
||||
|
||||
func Define_users(author_file string) {
|
||||
file, err := os.Open(author_file)
|
||||
if err != nil {
|
||||
print("File not found")
|
||||
os.Exit(2)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
// eat a single input
|
||||
scanner.Scan()
|
||||
|
||||
// reads the input of authors file and formats accordingly
|
||||
for scanner.Scan() {
|
||||
input_str := scanner.Text()
|
||||
group_info := []string{}
|
||||
if strings.Contains(input_str, ";;") {
|
||||
input := strings.Split(input_str, ";;")
|
||||
input_str = input[0]
|
||||
group_info = append(group_info, strings.Split(input[1], "|")...)
|
||||
}
|
||||
info := strings.Split(input_str, "|")
|
||||
if len(info) < 4 {
|
||||
if len(info) > 0 {
|
||||
println("Error: User ", info[0], " is missing information")
|
||||
} else {
|
||||
println("Error: Some user is missing information")
|
||||
}
|
||||
println("Please check the author file for proper syntax")
|
||||
os.Exit(1)
|
||||
}
|
||||
usr := User{Username: info[2], Email: info[3], Names: info[0] + "/" + info[1]}
|
||||
Users[info[0]] = usr
|
||||
Users[info[1]] = usr
|
||||
// Adds users with the ex tag to the defExclude list
|
||||
if len(info) == 5 {
|
||||
if info[4] == "ex" {
|
||||
DefExclude = append(DefExclude, info[2])
|
||||
}
|
||||
} else if len(group_info) > 0 {
|
||||
// Group assignment
|
||||
for _, group := range group_info {
|
||||
if Groups[group] == nil {
|
||||
Groups[group] = []User{usr}
|
||||
} else {
|
||||
//TODO: Try and find a cleaner way of doing this
|
||||
usr_lst := Groups[group]
|
||||
usr_lst = append(usr_lst, usr)
|
||||
Groups[group] = usr_lst
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveUser(short string) {
|
||||
usr := Users[short]
|
||||
split := strings.Split(usr.Names, "/")
|
||||
delete(Users, split[0])
|
||||
delete(Users, split[1])
|
||||
}
|
||||
|
||||
func TempAddUser(username, email string) {
|
||||
usr := User{Username: username, Email: email}
|
||||
|
||||
Users[username] = usr
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package utils_test
|
||||
|
||||
import (
|
||||
"github.com/Slug-Boi/cocommit/src_code/go_src/cmd/utils"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const author_data = `syntax for the test file
|
||||
te|testing|TestUser|test@test.test|ex
|
||||
ti|testtest|UserName2|testing@user.io;;gr1`
|
||||
|
||||
var envVar = os.Getenv("author_file")
|
||||
|
||||
func setup() {
|
||||
// setup test data
|
||||
os.WriteFile("author_file_test", []byte(author_data), 0644)
|
||||
os.Setenv("author_file", "author_file_test")
|
||||
}
|
||||
|
||||
func teardown() {
|
||||
// remove test data
|
||||
os.Remove("author_file_test")
|
||||
os.Setenv("author_file", envVar)
|
||||
}
|
||||
|
||||
// Author tests BEGIN
|
||||
func Test_FindAuthorFile(t* testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
// Test Find_authorfile
|
||||
authorfile := utils.Find_authorfile()
|
||||
if authorfile != "author_file_test" {
|
||||
t.Errorf("Find_authorfile() = %v; want authors_file_test", authorfile)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DeleteAuthor(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
utils.Define_users("author_file_test")
|
||||
// Test DeleteOneAuthor
|
||||
og_bytes, err := os.ReadFile("author_file_test")
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
|
||||
utils.DeleteOneAuthor("te")
|
||||
deleted_bytes, err := os.ReadFile("author_file_test")
|
||||
if err != nil {
|
||||
t.Errorf("Error reading file: %v", err)
|
||||
}
|
||||
|
||||
if string(og_bytes) == string(deleted_bytes) {
|
||||
t.Errorf("DeleteOneAuthor() did not delete author")
|
||||
}
|
||||
}
|
||||
|
||||
// Author tests END
|
||||
|
||||
// User tests BEGIN
|
||||
func Test_DefineUsers(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
// Test Define_users
|
||||
utils.Define_users("author_file_test")
|
||||
if len(utils.Users) != 4 {
|
||||
t.Errorf("Define_users() = %v; want 4", len(utils.Users))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_RemoveUser(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
// Test RemoveUser
|
||||
utils.Define_users("author_file_test")
|
||||
|
||||
utils.RemoveUser("te")
|
||||
|
||||
if len(utils.Users) != 2 {
|
||||
t.Errorf("RemoveUser() = %v; want 2", len(utils.Users))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_TempAddUser(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
// Test TempAddUser
|
||||
utils.Define_users("author_file_test")
|
||||
if len(utils.Users) != 4 {
|
||||
t.Errorf("Define_users() = %v; want 4", len(utils.Users))
|
||||
}
|
||||
|
||||
utils.TempAddUser("temp", "temp@test.io")
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
}
|
||||
// User tests END
|
||||
|
||||
// Commit tests BEGIN
|
||||
|
||||
func Test_Commit(t* testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
utils.Define_users("author_file_test")
|
||||
// Test Commit
|
||||
authors := []string{"te"}
|
||||
message := "Test commit message"
|
||||
commit := utils.Commit(message, authors)
|
||||
if commit != "Test commit message\n\nCo-authored-by: TestUser <test@test.test>" {
|
||||
t.Errorf("Commit() = %v; want Test commit message\n", commit)
|
||||
}
|
||||
}
|
||||
// Commit tests END
|
||||
Reference in New Issue
Block a user