detached 2ac17d0

feat(cli): add config command with status and migrate subcommands

commit
2ac17d03fc5089439e29fa9eed86d5f8c30b5823
author
bnema · · 2025-12-27 18:48 UTC
committer
bnema · · 2025-12-27 18:50 UTC
parent
90e33b5
signature
GPG Unverified2B82207D370127A0 The key is unknown
4 files · +199 -3
M .mockery.yaml +1 -0
@@ -8,6 +8,7 @@ packages:
88 filename: mocks.go
99 pkgname: mocks
1010 interfaces:
11+ ConfigMigrator: {}
1112 SessionLogger: {}
1213 SessionSpawner: {}
1314 TabListProvider: {}
@@ -8,6 +8,7 @@ packages:
8 filename: mocks.go8 filename: mocks.go
9 pkgname: mocks9 pkgname: mocks
10 interfaces:10 interfaces:
11+ ConfigMigrator: {}
11 SessionLogger: {}12 SessionLogger: {}
12 SessionSpawner: {}13 SessionSpawner: {}
13 TabListProvider: {}14 TabListProvider: {}
M go.mod +3 -3
@@ -8,14 +8,17 @@ require (
88 github.com/charmbracelet/bubbletea v1.3.10
99 github.com/charmbracelet/lipgloss v1.1.0
1010 github.com/fsnotify/fsnotify v1.9.0
11+ github.com/godbus/dbus/v5 v5.2.1
1112 github.com/jwijenbergh/puregotk v0.0.0-20251222174431-73930527faa3
1213 github.com/ncruces/go-sqlite3 v0.30.3
14+ github.com/pelletier/go-toml/v2 v2.2.4
1315 github.com/pressly/goose/v3 v3.26.0
1416 github.com/rs/zerolog v1.33.0
1517 github.com/spf13/cobra v1.10.2
1618 github.com/spf13/viper v1.21.0
1719 github.com/stretchr/testify v1.11.1
1820 golang.org/x/image v0.34.0
21+ golang.org/x/sys v0.38.0
1922 )
2023
2124 replace github.com/jwijenbergh/puregotk => github.com/bnema/puregotk v0.0.0-20251222174431-73930527faa3
@@ -30,7 +33,6 @@ require (
3033 github.com/davecgh/go-spew v1.1.1 // indirect
3134 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
3235 github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
33- github.com/godbus/dbus/v5 v5.2.1 // indirect
3436 github.com/inconshreveable/mousetrap v1.1.0 // indirect
3537 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect
3638 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
@@ -43,7 +45,6 @@ require (
4345 github.com/muesli/cancelreader v0.2.2 // indirect
4446 github.com/muesli/termenv v0.16.0 // indirect
4547 github.com/ncruces/julianday v1.0.0 // indirect
46- github.com/pelletier/go-toml/v2 v2.2.4 // indirect
4748 github.com/pmezard/go-difflib v1.0.0 // indirect
4849 github.com/rivo/uniseg v0.4.7 // indirect
4950 github.com/sagikazarmark/locafero v0.11.0 // indirect
@@ -60,7 +61,6 @@ require (
6061 go.uber.org/multierr v1.11.0 // indirect
6162 go.yaml.in/yaml/v3 v3.0.4 // indirect
6263 golang.org/x/sync v0.19.0 // indirect
63- golang.org/x/sys v0.38.0 // indirect
6464 golang.org/x/text v0.32.0 // indirect
6565 gopkg.in/yaml.v3 v3.0.1 // indirect
6666 )
@@ -8,14 +8,17 @@ require (
8 github.com/charmbracelet/bubbletea v1.3.108 github.com/charmbracelet/bubbletea v1.3.10
9 github.com/charmbracelet/lipgloss v1.1.09 github.com/charmbracelet/lipgloss v1.1.0
10 github.com/fsnotify/fsnotify v1.9.010 github.com/fsnotify/fsnotify v1.9.0
11+ github.com/godbus/dbus/v5 v5.2.1
11 github.com/jwijenbergh/puregotk v0.0.0-20251222174431-73930527faa312 github.com/jwijenbergh/puregotk v0.0.0-20251222174431-73930527faa3
12 github.com/ncruces/go-sqlite3 v0.30.313 github.com/ncruces/go-sqlite3 v0.30.3
14+ github.com/pelletier/go-toml/v2 v2.2.4
13 github.com/pressly/goose/v3 v3.26.015 github.com/pressly/goose/v3 v3.26.0
14 github.com/rs/zerolog v1.33.016 github.com/rs/zerolog v1.33.0
15 github.com/spf13/cobra v1.10.217 github.com/spf13/cobra v1.10.2
16 github.com/spf13/viper v1.21.018 github.com/spf13/viper v1.21.0
17 github.com/stretchr/testify v1.11.119 github.com/stretchr/testify v1.11.1
18 golang.org/x/image v0.34.020 golang.org/x/image v0.34.0
21+ golang.org/x/sys v0.38.0
19 )22 )
20 23
21 replace github.com/jwijenbergh/puregotk => github.com/bnema/puregotk v0.0.0-20251222174431-73930527faa324 replace github.com/jwijenbergh/puregotk => github.com/bnema/puregotk v0.0.0-20251222174431-73930527faa3
@@ -30,7 +33,6 @@ require (
30 github.com/davecgh/go-spew v1.1.1 // indirect33 github.com/davecgh/go-spew v1.1.1 // indirect
31 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect34 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
32 github.com/go-viper/mapstructure/v2 v2.4.0 // indirect35 github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
33- github.com/godbus/dbus/v5 v5.2.1 // indirect
34 github.com/inconshreveable/mousetrap v1.1.0 // indirect36 github.com/inconshreveable/mousetrap v1.1.0 // indirect
35 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect37 github.com/jwijenbergh/purego v0.0.0-20251017112123-b71757b9ba42 // indirect
36 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect38 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
@@ -43,7 +45,6 @@ require (
43 github.com/muesli/cancelreader v0.2.2 // indirect45 github.com/muesli/cancelreader v0.2.2 // indirect
44 github.com/muesli/termenv v0.16.0 // indirect46 github.com/muesli/termenv v0.16.0 // indirect
45 github.com/ncruces/julianday v1.0.0 // indirect47 github.com/ncruces/julianday v1.0.0 // indirect
46- github.com/pelletier/go-toml/v2 v2.2.4 // indirect
47 github.com/pmezard/go-difflib v1.0.0 // indirect48 github.com/pmezard/go-difflib v1.0.0 // indirect
48 github.com/rivo/uniseg v0.4.7 // indirect49 github.com/rivo/uniseg v0.4.7 // indirect
49 github.com/sagikazarmark/locafero v0.11.0 // indirect50 github.com/sagikazarmark/locafero v0.11.0 // indirect
@@ -60,7 +61,6 @@ require (
60 go.uber.org/multierr v1.11.0 // indirect61 go.uber.org/multierr v1.11.0 // indirect
61 go.yaml.in/yaml/v3 v3.0.4 // indirect62 go.yaml.in/yaml/v3 v3.0.4 // indirect
62 golang.org/x/sync v0.19.0 // indirect63 golang.org/x/sync v0.19.0 // indirect
63- golang.org/x/sys v0.38.0 // indirect
64 golang.org/x/text v0.32.0 // indirect64 golang.org/x/text v0.32.0 // indirect
65 gopkg.in/yaml.v3 v3.0.1 // indirect65 gopkg.in/yaml.v3 v3.0.1 // indirect
66 )66 )
M internal/application/port/mocks/mocks.go +188 -0
@@ -13,6 +13,194 @@ import (
1313 mock "github.com/stretchr/testify/mock"
1414 )
1515
16+// NewMockConfigMigrator creates a new instance of MockConfigMigrator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
17+// The first argument is typically a *testing.T value.
18+func NewMockConfigMigrator(t interface {
19+ mock.TestingT
20+ Cleanup(func())
21+}) *MockConfigMigrator {
22+ mock := &MockConfigMigrator{}
23+ mock.Mock.Test(t)
24+
25+ t.Cleanup(func() { mock.AssertExpectations(t) })
26+
27+ return mock
28+}
29+
30+// MockConfigMigrator is an autogenerated mock type for the ConfigMigrator type
31+type MockConfigMigrator struct {
32+ mock.Mock
33+}
34+
35+type MockConfigMigrator_Expecter struct {
36+ mock *mock.Mock
37+}
38+
39+func (_m *MockConfigMigrator) EXPECT() *MockConfigMigrator_Expecter {
40+ return &MockConfigMigrator_Expecter{mock: &_m.Mock}
41+}
42+
43+// CheckMigration provides a mock function for the type MockConfigMigrator
44+func (_mock *MockConfigMigrator) CheckMigration() (*port.MigrationResult, error) {
45+ ret := _mock.Called()
46+
47+ if len(ret) == 0 {
48+ panic("no return value specified for CheckMigration")
49+ }
50+
51+ var r0 *port.MigrationResult
52+ var r1 error
53+ if returnFunc, ok := ret.Get(0).(func() (*port.MigrationResult, error)); ok {
54+ return returnFunc()
55+ }
56+ if returnFunc, ok := ret.Get(0).(func() *port.MigrationResult); ok {
57+ r0 = returnFunc()
58+ } else {
59+ if ret.Get(0) != nil {
60+ r0 = ret.Get(0).(*port.MigrationResult)
61+ }
62+ }
63+ if returnFunc, ok := ret.Get(1).(func() error); ok {
64+ r1 = returnFunc()
65+ } else {
66+ r1 = ret.Error(1)
67+ }
68+ return r0, r1
69+}
70+
71+// MockConfigMigrator_CheckMigration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckMigration'
72+type MockConfigMigrator_CheckMigration_Call struct {
73+ *mock.Call
74+}
75+
76+// CheckMigration is a helper method to define mock.On call
77+func (_e *MockConfigMigrator_Expecter) CheckMigration() *MockConfigMigrator_CheckMigration_Call {
78+ return &MockConfigMigrator_CheckMigration_Call{Call: _e.mock.On("CheckMigration")}
79+}
80+
81+func (_c *MockConfigMigrator_CheckMigration_Call) Run(run func()) *MockConfigMigrator_CheckMigration_Call {
82+ _c.Call.Run(func(args mock.Arguments) {
83+ run()
84+ })
85+ return _c
86+}
87+
88+func (_c *MockConfigMigrator_CheckMigration_Call) Return(migrationResult *port.MigrationResult, err error) *MockConfigMigrator_CheckMigration_Call {
89+ _c.Call.Return(migrationResult, err)
90+ return _c
91+}
92+
93+func (_c *MockConfigMigrator_CheckMigration_Call) RunAndReturn(run func() (*port.MigrationResult, error)) *MockConfigMigrator_CheckMigration_Call {
94+ _c.Call.Return(run)
95+ return _c
96+}
97+
98+// GetKeyInfo provides a mock function for the type MockConfigMigrator
99+func (_mock *MockConfigMigrator) GetKeyInfo(key string) port.KeyInfo {
100+ ret := _mock.Called(key)
101+
102+ if len(ret) == 0 {
103+ panic("no return value specified for GetKeyInfo")
104+ }
105+
106+ var r0 port.KeyInfo
107+ if returnFunc, ok := ret.Get(0).(func(string) port.KeyInfo); ok {
108+ r0 = returnFunc(key)
109+ } else {
110+ r0 = ret.Get(0).(port.KeyInfo)
111+ }
112+ return r0
113+}
114+
115+// MockConfigMigrator_GetKeyInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKeyInfo'
116+type MockConfigMigrator_GetKeyInfo_Call struct {
117+ *mock.Call
118+}
119+
120+// GetKeyInfo is a helper method to define mock.On call
121+// - key string
122+func (_e *MockConfigMigrator_Expecter) GetKeyInfo(key interface{}) *MockConfigMigrator_GetKeyInfo_Call {
123+ return &MockConfigMigrator_GetKeyInfo_Call{Call: _e.mock.On("GetKeyInfo", key)}
124+}
125+
126+func (_c *MockConfigMigrator_GetKeyInfo_Call) Run(run func(key string)) *MockConfigMigrator_GetKeyInfo_Call {
127+ _c.Call.Run(func(args mock.Arguments) {
128+ var arg0 string
129+ if args[0] != nil {
130+ arg0 = args[0].(string)
131+ }
132+ run(
133+ arg0,
134+ )
135+ })
136+ return _c
137+}
138+
139+func (_c *MockConfigMigrator_GetKeyInfo_Call) Return(keyInfo port.KeyInfo) *MockConfigMigrator_GetKeyInfo_Call {
140+ _c.Call.Return(keyInfo)
141+ return _c
142+}
143+
144+func (_c *MockConfigMigrator_GetKeyInfo_Call) RunAndReturn(run func(key string) port.KeyInfo) *MockConfigMigrator_GetKeyInfo_Call {
145+ _c.Call.Return(run)
146+ return _c
147+}
148+
149+// Migrate provides a mock function for the type MockConfigMigrator
150+func (_mock *MockConfigMigrator) Migrate() ([]string, error) {
151+ ret := _mock.Called()
152+
153+ if len(ret) == 0 {
154+ panic("no return value specified for Migrate")
155+ }
156+
157+ var r0 []string
158+ var r1 error
159+ if returnFunc, ok := ret.Get(0).(func() ([]string, error)); ok {
160+ return returnFunc()
161+ }
162+ if returnFunc, ok := ret.Get(0).(func() []string); ok {
163+ r0 = returnFunc()
164+ } else {
165+ if ret.Get(0) != nil {
166+ r0 = ret.Get(0).([]string)
167+ }
168+ }
169+ if returnFunc, ok := ret.Get(1).(func() error); ok {
170+ r1 = returnFunc()
171+ } else {
172+ r1 = ret.Error(1)
173+ }
174+ return r0, r1
175+}
176+
177+// MockConfigMigrator_Migrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Migrate'
178+type MockConfigMigrator_Migrate_Call struct {
179+ *mock.Call
180+}
181+
182+// Migrate is a helper method to define mock.On call
183+func (_e *MockConfigMigrator_Expecter) Migrate() *MockConfigMigrator_Migrate_Call {
184+ return &MockConfigMigrator_Migrate_Call{Call: _e.mock.On("Migrate")}
185+}
186+
187+func (_c *MockConfigMigrator_Migrate_Call) Run(run func()) *MockConfigMigrator_Migrate_Call {
188+ _c.Call.Run(func(args mock.Arguments) {
189+ run()
190+ })
191+ return _c
192+}
193+
194+func (_c *MockConfigMigrator_Migrate_Call) Return(strings []string, err error) *MockConfigMigrator_Migrate_Call {
195+ _c.Call.Return(strings, err)
196+ return _c
197+}
198+
199+func (_c *MockConfigMigrator_Migrate_Call) RunAndReturn(run func() ([]string, error)) *MockConfigMigrator_Migrate_Call {
200+ _c.Call.Return(run)
201+ return _c
202+}
203+
16204 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
17205 // The first argument is typically a *testing.T value.
18206 func NewMockSessionLogger(t interface {
@@ -13,6 +13,194 @@ import (
13 mock "github.com/stretchr/testify/mock"13 mock "github.com/stretchr/testify/mock"
14 )14 )
15 15
16+// NewMockConfigMigrator creates a new instance of MockConfigMigrator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
17+// The first argument is typically a *testing.T value.
18+func NewMockConfigMigrator(t interface {
19+ mock.TestingT
20+ Cleanup(func())
21+}) *MockConfigMigrator {
22+ mock := &MockConfigMigrator{}
23+ mock.Mock.Test(t)
24+
25+ t.Cleanup(func() { mock.AssertExpectations(t) })
26+
27+ return mock
28+}
29+
30+// MockConfigMigrator is an autogenerated mock type for the ConfigMigrator type
31+type MockConfigMigrator struct {
32+ mock.Mock
33+}
34+
35+type MockConfigMigrator_Expecter struct {
36+ mock *mock.Mock
37+}
38+
39+func (_m *MockConfigMigrator) EXPECT() *MockConfigMigrator_Expecter {
40+ return &MockConfigMigrator_Expecter{mock: &_m.Mock}
41+}
42+
43+// CheckMigration provides a mock function for the type MockConfigMigrator
44+func (_mock *MockConfigMigrator) CheckMigration() (*port.MigrationResult, error) {
45+ ret := _mock.Called()
46+
47+ if len(ret) == 0 {
48+ panic("no return value specified for CheckMigration")
49+ }
50+
51+ var r0 *port.MigrationResult
52+ var r1 error
53+ if returnFunc, ok := ret.Get(0).(func() (*port.MigrationResult, error)); ok {
54+ return returnFunc()
55+ }
56+ if returnFunc, ok := ret.Get(0).(func() *port.MigrationResult); ok {
57+ r0 = returnFunc()
58+ } else {
59+ if ret.Get(0) != nil {
60+ r0 = ret.Get(0).(*port.MigrationResult)
61+ }
62+ }
63+ if returnFunc, ok := ret.Get(1).(func() error); ok {
64+ r1 = returnFunc()
65+ } else {
66+ r1 = ret.Error(1)
67+ }
68+ return r0, r1
69+}
70+
71+// MockConfigMigrator_CheckMigration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckMigration'
72+type MockConfigMigrator_CheckMigration_Call struct {
73+ *mock.Call
74+}
75+
76+// CheckMigration is a helper method to define mock.On call
77+func (_e *MockConfigMigrator_Expecter) CheckMigration() *MockConfigMigrator_CheckMigration_Call {
78+ return &MockConfigMigrator_CheckMigration_Call{Call: _e.mock.On("CheckMigration")}
79+}
80+
81+func (_c *MockConfigMigrator_CheckMigration_Call) Run(run func()) *MockConfigMigrator_CheckMigration_Call {
82+ _c.Call.Run(func(args mock.Arguments) {
83+ run()
84+ })
85+ return _c
86+}
87+
88+func (_c *MockConfigMigrator_CheckMigration_Call) Return(migrationResult *port.MigrationResult, err error) *MockConfigMigrator_CheckMigration_Call {
89+ _c.Call.Return(migrationResult, err)
90+ return _c
91+}
92+
93+func (_c *MockConfigMigrator_CheckMigration_Call) RunAndReturn(run func() (*port.MigrationResult, error)) *MockConfigMigrator_CheckMigration_Call {
94+ _c.Call.Return(run)
95+ return _c
96+}
97+
98+// GetKeyInfo provides a mock function for the type MockConfigMigrator
99+func (_mock *MockConfigMigrator) GetKeyInfo(key string) port.KeyInfo {
100+ ret := _mock.Called(key)
101+
102+ if len(ret) == 0 {
103+ panic("no return value specified for GetKeyInfo")
104+ }
105+
106+ var r0 port.KeyInfo
107+ if returnFunc, ok := ret.Get(0).(func(string) port.KeyInfo); ok {
108+ r0 = returnFunc(key)
109+ } else {
110+ r0 = ret.Get(0).(port.KeyInfo)
111+ }
112+ return r0
113+}
114+
115+// MockConfigMigrator_GetKeyInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKeyInfo'
116+type MockConfigMigrator_GetKeyInfo_Call struct {
117+ *mock.Call
118+}
119+
120+// GetKeyInfo is a helper method to define mock.On call
121+// - key string
122+func (_e *MockConfigMigrator_Expecter) GetKeyInfo(key interface{}) *MockConfigMigrator_GetKeyInfo_Call {
123+ return &MockConfigMigrator_GetKeyInfo_Call{Call: _e.mock.On("GetKeyInfo", key)}
124+}
125+
126+func (_c *MockConfigMigrator_GetKeyInfo_Call) Run(run func(key string)) *MockConfigMigrator_GetKeyInfo_Call {
127+ _c.Call.Run(func(args mock.Arguments) {
128+ var arg0 string
129+ if args[0] != nil {
130+ arg0 = args[0].(string)
131+ }
132+ run(
133+ arg0,
134+ )
135+ })
136+ return _c
137+}
138+
139+func (_c *MockConfigMigrator_GetKeyInfo_Call) Return(keyInfo port.KeyInfo) *MockConfigMigrator_GetKeyInfo_Call {
140+ _c.Call.Return(keyInfo)
141+ return _c
142+}
143+
144+func (_c *MockConfigMigrator_GetKeyInfo_Call) RunAndReturn(run func(key string) port.KeyInfo) *MockConfigMigrator_GetKeyInfo_Call {
145+ _c.Call.Return(run)
146+ return _c
147+}
148+
149+// Migrate provides a mock function for the type MockConfigMigrator
150+func (_mock *MockConfigMigrator) Migrate() ([]string, error) {
151+ ret := _mock.Called()
152+
153+ if len(ret) == 0 {
154+ panic("no return value specified for Migrate")
155+ }
156+
157+ var r0 []string
158+ var r1 error
159+ if returnFunc, ok := ret.Get(0).(func() ([]string, error)); ok {
160+ return returnFunc()
161+ }
162+ if returnFunc, ok := ret.Get(0).(func() []string); ok {
163+ r0 = returnFunc()
164+ } else {
165+ if ret.Get(0) != nil {
166+ r0 = ret.Get(0).([]string)
167+ }
168+ }
169+ if returnFunc, ok := ret.Get(1).(func() error); ok {
170+ r1 = returnFunc()
171+ } else {
172+ r1 = ret.Error(1)
173+ }
174+ return r0, r1
175+}
176+
177+// MockConfigMigrator_Migrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Migrate'
178+type MockConfigMigrator_Migrate_Call struct {
179+ *mock.Call
180+}
181+
182+// Migrate is a helper method to define mock.On call
183+func (_e *MockConfigMigrator_Expecter) Migrate() *MockConfigMigrator_Migrate_Call {
184+ return &MockConfigMigrator_Migrate_Call{Call: _e.mock.On("Migrate")}
185+}
186+
187+func (_c *MockConfigMigrator_Migrate_Call) Run(run func()) *MockConfigMigrator_Migrate_Call {
188+ _c.Call.Run(func(args mock.Arguments) {
189+ run()
190+ })
191+ return _c
192+}
193+
194+func (_c *MockConfigMigrator_Migrate_Call) Return(strings []string, err error) *MockConfigMigrator_Migrate_Call {
195+ _c.Call.Return(strings, err)
196+ return _c
197+}
198+
199+func (_c *MockConfigMigrator_Migrate_Call) RunAndReturn(run func() ([]string, error)) *MockConfigMigrator_Migrate_Call {
200+ _c.Call.Return(run)
201+ return _c
202+}
203+
16 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.204 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
17 // The first argument is typically a *testing.T value.205 // The first argument is typically a *testing.T value.
18 func NewMockSessionLogger(t interface {206 func NewMockSessionLogger(t interface {
M internal/cli/cmd/config.go +7 -0
@@ -22,6 +22,12 @@ var configCmd = &cobra.Command{
2222 Use: "config",
2323 Short: "Manage configuration",
2424 Long: `View configuration status and migrate to add new default settings.`,
25+}
26+
27+var configStatusCmd = &cobra.Command{
28+ Use: "status",
29+ Short: "Show config file status and migration availability",
30+ Long: `Display the config file path and check if any new settings are available.`,
2531 RunE: runConfigStatus,
2632 }
2733
@@ -36,6 +42,7 @@ Existing settings are never modified - only missing keys are added with default
3642
3743 func init() {
3844 rootCmd.AddCommand(configCmd)
45+ configCmd.AddCommand(configStatusCmd)
3946 configCmd.AddCommand(configMigrateCmd)
4047 configMigrateCmd.Flags().BoolVarP(&configYes, "yes", "y", false, "skip confirmation prompt")
4148 }
@@ -22,6 +22,12 @@ var configCmd = &cobra.Command{
22 Use: "config",22 Use: "config",
23 Short: "Manage configuration",23 Short: "Manage configuration",
24 Long: `View configuration status and migrate to add new default settings.`,24 Long: `View configuration status and migrate to add new default settings.`,
25+}
26+
27+var configStatusCmd = &cobra.Command{
28+ Use: "status",
29+ Short: "Show config file status and migration availability",
30+ Long: `Display the config file path and check if any new settings are available.`,
25 RunE: runConfigStatus,31 RunE: runConfigStatus,
26 }32 }
27 33
@@ -36,6 +42,7 @@ Existing settings are never modified - only missing keys are added with default
36 42
37 func init() {43 func init() {
38 rootCmd.AddCommand(configCmd)44 rootCmd.AddCommand(configCmd)
45+ configCmd.AddCommand(configStatusCmd)
39 configCmd.AddCommand(configMigrateCmd)46 configCmd.AddCommand(configMigrateCmd)
40 configMigrateCmd.Flags().BoolVarP(&configYes, "yes", "y", false, "skip confirmation prompt")47 configMigrateCmd.Flags().BoolVarP(&configYes, "yes", "y", false, "skip confirmation prompt")
41 }48 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close