mirror of
https://github.com/Slug-Boi/cocommit.git
synced 2026-05-13 12:45:47 +00:00
Merge pull request #81 from Slug-Boi/feat_config
This commit is contained in:
@@ -23,6 +23,8 @@ require (
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect
|
||||
github.com/dlclark/regexp2 v1.11.0 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
@@ -34,15 +36,25 @@ require (
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.4 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.3 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -31,10 +31,16 @@ github.com/charmbracelet/x/exp/teatest v0.0.0-20241024145942-ad25fd0d5a9e/go.mod
|
||||
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
|
||||
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
@@ -64,22 +70,44 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
|
||||
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
|
||||
github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
@@ -95,4 +123,5 @@ golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
+2
-3
@@ -6,8 +6,6 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Slug-Boi/cocommit/src/cmd/utils"
|
||||
)
|
||||
|
||||
const author_data = `
|
||||
@@ -34,7 +32,7 @@ const author_data = `
|
||||
}
|
||||
}`
|
||||
|
||||
var envVar = utils.Find_authorfile()
|
||||
var envVar string
|
||||
|
||||
func setup() {
|
||||
// setup test data
|
||||
@@ -50,6 +48,7 @@ func teardown() {
|
||||
// remove test data
|
||||
os.Remove("author_file_test")
|
||||
os.Setenv("author_file", envVar)
|
||||
os.Remove("config.toml")
|
||||
}
|
||||
|
||||
// Skip cobra cmd tests on CI causes problems apparenly idk why
|
||||
|
||||
+35
-7
@@ -142,7 +142,7 @@ const (
|
||||
|
||||
type Model struct {
|
||||
list list.Model
|
||||
swap_lists [][]list.Item
|
||||
swap_lists [3][]list.Item
|
||||
keys *listKeyMap
|
||||
quitting bool
|
||||
scope int
|
||||
@@ -255,8 +255,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.scope == git_scope {
|
||||
m.scope = local_scope
|
||||
m.list.Title = title_text + local_scope_style.Render("Scope: LOCAL")
|
||||
if len(m.swap_lists) < 2 {
|
||||
m.swap_lists = append(m.swap_lists, generate_list(local_scope))
|
||||
if len(m.swap_lists[1]) == 0 {
|
||||
m.swap_lists[1] = generate_list(local_scope)
|
||||
}
|
||||
m.list.SetItems(m.swap_lists[1])
|
||||
m.list.ResetFilter()
|
||||
@@ -265,8 +265,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.scope == local_scope {
|
||||
m.scope = mixed_scope
|
||||
m.list.Title = title_text + mixed_scope_style.Render("Scope: MIXED")
|
||||
if len(m.swap_lists) < 3 {
|
||||
m.swap_lists = append(m.swap_lists, generate_list(mixed_scope))
|
||||
if len(m.swap_lists[2]) == 0 {
|
||||
m.swap_lists[2] = generate_list(mixed_scope)
|
||||
}
|
||||
m.list.SetItems(m.swap_lists[2])
|
||||
m.list.ResetFilter()
|
||||
@@ -275,6 +275,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
if m.scope == mixed_scope {
|
||||
m.scope = git_scope
|
||||
m.list.Title = title_text + git_scope_style.Render("Scope: GIT")
|
||||
if len(m.swap_lists[0]) == 0 {
|
||||
m.swap_lists[0] = generate_list(git_scope)
|
||||
}
|
||||
m.list.SetItems(m.swap_lists[0])
|
||||
m.list.ResetFilter()
|
||||
return m, nil
|
||||
@@ -360,6 +363,19 @@ func generate_list(scope int) []list.Item {
|
||||
|
||||
}
|
||||
|
||||
func ConvertStringScopeToIOTA(scope string) int {
|
||||
switch scope {
|
||||
case "git":
|
||||
return git_scope
|
||||
case "local":
|
||||
return local_scope
|
||||
case "mixed":
|
||||
return mixed_scope
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func (m Model) View() string {
|
||||
if sub_model != nil {
|
||||
return sub_model.View()
|
||||
@@ -391,6 +407,7 @@ func listModel(scope ...int) Model {
|
||||
|
||||
// Add items to the list
|
||||
if len(scope) == 0 {
|
||||
git_scope := ConvertStringScopeToIOTA(utils.ConfigVar.Settings.StartingScope)
|
||||
scope = append(scope, git_scope)
|
||||
}
|
||||
items := generate_list(scope[0])
|
||||
@@ -402,7 +419,16 @@ func listModel(scope ...int) Model {
|
||||
const defaultWidth = 20
|
||||
|
||||
l := list.New(items, itemDelegate{}, defaultWidth, listHeight)
|
||||
l.Title = title_text + lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Render("Scope: GIT")
|
||||
|
||||
|
||||
switch scope[0] {
|
||||
case git_scope:
|
||||
l.Title = title_text + git_scope_style.Render("Scope: GIT")
|
||||
case local_scope:
|
||||
l.Title = title_text + local_scope_style.Render("Scope: LOCAL")
|
||||
case mixed_scope:
|
||||
l.Title = title_text + mixed_scope_style.Render("Scope: MIXED")
|
||||
}
|
||||
l.SetShowStatusBar(false)
|
||||
l.SetFilteringEnabled(true) // Enable filtering
|
||||
l.Styles.Title = titleStyle
|
||||
@@ -427,7 +453,9 @@ func listModel(scope ...int) Model {
|
||||
}
|
||||
l.Styles.HelpStyle = helpStyle
|
||||
|
||||
model := Model{list: l, swap_lists: [][]list.Item{items}, keys: listKeys, scope: git_scope}
|
||||
swapLists := [3][]list.Item{}
|
||||
swapLists[scope[0]] = items
|
||||
model := Model{list: l, swap_lists: swapLists, keys: listKeys, scope: scope[0]}
|
||||
|
||||
//TODO: figure out async create
|
||||
// IDEA DO IT WITH CHANNELS
|
||||
|
||||
@@ -47,7 +47,7 @@ func setup() {
|
||||
panic(err)
|
||||
}
|
||||
os.Setenv("author_file", "author_file_test")
|
||||
envVar = os.Getenv("author_file")
|
||||
envVar = os.Getenv("author_file")
|
||||
|
||||
utils.Define_users("author_file_test")
|
||||
}
|
||||
@@ -610,8 +610,8 @@ func Test_ScopesLocal(t *testing.T) {
|
||||
t.Errorf("Expected model, got %T", fm)
|
||||
}
|
||||
|
||||
if m.scope!= local_scope {
|
||||
t.Errorf("Expected scope to be %v, got %v", local_scope, m.scope)
|
||||
if m.scope!= mixed_scope {
|
||||
t.Errorf("Expected scope to be %v, got %v", mixed_scope, m.scope)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,8 +634,8 @@ func Test_ScopesMixed(t *testing.T) {
|
||||
t.Errorf("Expected model, got %T", fm)
|
||||
}
|
||||
|
||||
if m.scope != mixed_scope {
|
||||
t.Errorf("Expected scope to be %v, got %v", mixed_scope, m.scope)
|
||||
if m.scope != local_scope {
|
||||
t.Errorf("Expected scope to be %v, got %v", local_scope, m.scope)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var authorfile = utils.Find_authorfile()
|
||||
var authorfile string
|
||||
|
||||
// usersCmd represents the users command
|
||||
func UsersCmd() *cobra.Command {
|
||||
@@ -21,6 +21,9 @@ func UsersCmd() *cobra.Command {
|
||||
Short: "Displays all users from the author file located at:\n" + authorfile,
|
||||
Long: `Displays all users from the author file located at:` + "\n" + authorfile,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if authorfile == "" {
|
||||
authorfile = utils.Find_authorfile()
|
||||
}
|
||||
if update {
|
||||
update_msg()
|
||||
}
|
||||
|
||||
@@ -13,12 +13,45 @@ import (
|
||||
// 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 {
|
||||
var file string
|
||||
|
||||
if os.Getenv("author_file") == "" {
|
||||
dirs, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error getting user config directory: %v", err))
|
||||
if ConfigVar == nil {
|
||||
cfg, _ := LoadConfig()
|
||||
if cfg == nil {
|
||||
// mimic the default config structure
|
||||
cfg = &Config{
|
||||
Settings: struct {
|
||||
AuthorFile string `mapstructure:"author_file"`
|
||||
StartingScope string `mapstructure:"starting_scope"`
|
||||
Editor string `mapstructure:"editor"`
|
||||
}{
|
||||
AuthorFile: "",
|
||||
StartingScope: "git",
|
||||
Editor: "built-in",
|
||||
},
|
||||
}
|
||||
cfg.SetGlobalConfig()
|
||||
}
|
||||
}
|
||||
return (dirs + "/cocommit/authors.json")
|
||||
|
||||
if ConfigVar.Settings.AuthorFile != "" {
|
||||
file = ConfigVar.Settings.AuthorFile
|
||||
} else if os.Getenv("author_file") != "" {
|
||||
file = os.Getenv("author_file")
|
||||
} else {
|
||||
userconf, err :=os.UserConfigDir()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error getting user config dir: %v", err))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(userconf+"/cocommit/authors.json"); os.IsNotExist(err) {
|
||||
panic(fmt.Sprintf("No author file set, please set the author_file environment variable or create a config file using the command: cocommit config -c"))
|
||||
} else {
|
||||
file = userconf + "/cocommit/authors.json"
|
||||
}
|
||||
}
|
||||
return file
|
||||
} else {
|
||||
return os.Getenv("author_file")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var ConfigVar *Config
|
||||
|
||||
var (
|
||||
defaultConfigLocations = []string{
|
||||
"",
|
||||
os.Getenv("COCOMMIT_CONFIG"),
|
||||
os.Getenv("HOME") + "/.config/cocommit",
|
||||
os.Getenv("HOME") + "/cocommit",
|
||||
"/etc/cocommit",
|
||||
"/usr/local/etc/cocommit",
|
||||
}
|
||||
configName = "config"
|
||||
configType = "toml"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Settings struct {
|
||||
AuthorFile string `mapstructure:"author_file"`
|
||||
StartingScope string `mapstructure:"starting_scope"`
|
||||
Editor string `mapstructure:"editor"`
|
||||
} `mapstructure:"settings"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
defaultConfigLocations[0] = filepath.Join(configDir, "cocommit")
|
||||
}
|
||||
}
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
// TODO: create if and give param as default config location
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigName(configName)
|
||||
v.SetConfigType(configType)
|
||||
|
||||
// Set default values
|
||||
v.SetDefault("settings.author_file", defaultConfigLocations[0]+"/authors.json")
|
||||
v.SetDefault("settings.starting_scope", "git")
|
||||
v.SetDefault("settings.editor", "built-in")
|
||||
|
||||
// Add search paths
|
||||
for _, path := range defaultConfigLocations {
|
||||
if path != "" {
|
||||
v.AddConfigPath(path)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to read config
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
return nil, nil
|
||||
}
|
||||
// if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
// if err := handleMissingConfig(v); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// } else {
|
||||
// return nil, fmt.Errorf("config error: %w", err)
|
||||
// }
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("config unmarshal error: %w", err)
|
||||
}
|
||||
if cfg.Settings.AuthorFile == "" {
|
||||
cfg.Settings.AuthorFile = defaultConfigLocations[0] + "/authors.json"
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func (c *Config) SetGlobalConfig() {
|
||||
if ConfigVar == nil {
|
||||
ConfigVar = c
|
||||
// This doesnt really do much right now but might be useful later
|
||||
viper.WatchConfig()
|
||||
}
|
||||
}
|
||||
|
||||
func handleMissingConfig(v *viper.Viper) error {
|
||||
fmt.Println("Config file not found. Would you like to create one? (y/n)")
|
||||
var response string
|
||||
if _, err := fmt.Scanln(&response); err != nil {
|
||||
return fmt.Errorf("error reading response: %w", err)
|
||||
}
|
||||
|
||||
yesResponses := map[string]bool{"y": true, "Y": true, "yes": true, "Yes": true, "YES": true}
|
||||
if !yesResponses[strings.TrimSpace(response)] {
|
||||
return fmt.Errorf("config file not found")
|
||||
}
|
||||
|
||||
return createConfig(v)
|
||||
}
|
||||
|
||||
func createConfig(v *viper.Viper) error {
|
||||
fmt.Println("Where would you like to create the config file?")
|
||||
for i, path := range defaultConfigLocations {
|
||||
fmt.Printf("%d. %s\n", i, path)
|
||||
}
|
||||
fmt.Println("Please enter the number of the location or a custom path:")
|
||||
|
||||
var response string
|
||||
if _, err := fmt.Scanln(&response); err != nil {
|
||||
return fmt.Errorf("error reading response: %w", err)
|
||||
}
|
||||
|
||||
var configPath string
|
||||
if num, err := strconv.Atoi(response); err == nil && num >= 0 && num < len(defaultConfigLocations) {
|
||||
configPath = defaultConfigLocations[num]
|
||||
} else {
|
||||
configPath = response
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
if err := os.MkdirAll(configPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create config directory: %w", err)
|
||||
}
|
||||
|
||||
// Set the config file path
|
||||
fullPath := filepath.Join(configPath, fmt.Sprintf("%s.%s", configName, configType))
|
||||
v.SetConfigFile(fullPath)
|
||||
|
||||
// Write default config
|
||||
if err := v.SafeWriteConfig(); err != nil {
|
||||
return fmt.Errorf("failed to write config: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Config file created at: %s\n", fullPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) Save() error {
|
||||
v := viper.New()
|
||||
|
||||
// Set all configuration values from the struct
|
||||
v.Set("settings.author_file", c.Settings.AuthorFile)
|
||||
v.Set("settings.starting_scope", c.Settings.StartingScope)
|
||||
v.Set("settings.editor", c.Settings.Editor)
|
||||
|
||||
v.SetConfigName(configName)
|
||||
v.SetConfigType(configType)
|
||||
|
||||
// Try to determine the original config file location
|
||||
if viper.ConfigFileUsed() != "" {
|
||||
v.SetConfigFile(viper.ConfigFileUsed())
|
||||
} else {
|
||||
// Fall back to first default location if no existing config
|
||||
if len(defaultConfigLocations) > 0 && defaultConfigLocations[0] != "" {
|
||||
v.SetConfigFile(filepath.Join(defaultConfigLocations[0], fmt.Sprintf("%s.%s", configName, configType)))
|
||||
} else {
|
||||
return fmt.Errorf("no config file location available")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the directory exists
|
||||
configDir := filepath.Dir(v.ConfigFileUsed())
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create config directory: %w", err)
|
||||
}
|
||||
|
||||
// Write the config file
|
||||
if err := v.WriteConfig(); err != nil {
|
||||
return fmt.Errorf("failed to save config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -38,10 +38,27 @@ const author_data = `
|
||||
}
|
||||
}`
|
||||
|
||||
|
||||
const config_data = `[settings]
|
||||
author_file = "author_file_test"
|
||||
starting_scope = "git"
|
||||
editor = "built-in"
|
||||
`
|
||||
|
||||
var envVar = os.Getenv("author_file")
|
||||
|
||||
func setup() {
|
||||
os.Setenv("author_file", "")
|
||||
|
||||
// setup test data
|
||||
err := os.WriteFile("config.toml", []byte(config_data), 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
os.Setenv("COCOMMIT_CONFIG", "config.toml")
|
||||
|
||||
|
||||
os.WriteFile("author_file_test", []byte(author_data), 0644)
|
||||
os.Setenv("author_file", "author_file_test")
|
||||
}
|
||||
@@ -50,6 +67,7 @@ func teardown() {
|
||||
// remove test data
|
||||
os.Remove("author_file_test")
|
||||
os.Setenv("author_file", envVar)
|
||||
os.Remove("config.toml")
|
||||
}
|
||||
|
||||
// Author tests BEGIN
|
||||
@@ -124,6 +142,8 @@ func Test_CreateAuthor(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_FindAuthorFilePanic(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
// Save original environment variables
|
||||
originalAuthorFile := os.Getenv("author_file")
|
||||
originalHome := os.Getenv("HOME")
|
||||
@@ -153,16 +173,21 @@ func Test_FindAuthorFileEnv(t *testing.T) {
|
||||
// Test Find_authorfile with env var
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
originalAuthorFile := os.Getenv("author_file")
|
||||
|
||||
defer func() {
|
||||
os.Setenv("author_file", originalAuthorFile)
|
||||
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("Find_authorfile() did not panic")
|
||||
}
|
||||
}()
|
||||
|
||||
// Set an invalid environment variable to trigger panic
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
utils.Find_authorfile()
|
||||
}
|
||||
|
||||
func Test_CreateAuthorPanicOnFileError(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user