detached 026789a

refactor(remote): delete legacy resolution functions and [client] config

ResolveRemote, ResolveRemoteFull, resolveRemoteURL, resolveToken,
activeRemoteEntry, LoadClientConfig, ClientSettings all removed.
Single Resolve() replaces them.
commit
026789a0c08e6833f6a12f4e63522d06e98d7e51
author
brice · · 2026-04-04 11:30 UTC
parent
2197faa
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +3 -198
M internal/adapters/in/cli/remote/config.go +3 -167
@@ -14,20 +14,10 @@ import (
1414
1515 // ClientConfig represents the client-mode configuration.
1616 type ClientConfig struct {
17- Client ClientSettings `toml:"client"`
1817 Remotes map[string]RemoteEntry `toml:"remotes"`
1918 Active string `toml:"active"` // Active remote name
2019 }
2120
22-// ClientSettings represents the [client] section.
23-type ClientSettings struct {
24- Mode string `toml:"mode"` // "local" (default) or "remote"
25- Remote string `toml:"remote"` // Remote Gordon URL
26- Token string `toml:"token"` // Auth token
27- TokenEnv string `toml:"token_env"` // Env var name for token
28- InsecureTLS bool `toml:"insecure_tls"` // Skip TLS verification for remote admin API
29-}
30-
3121 // RemoteEntry represents a saved remote in [remotes.*].
3222 type RemoteEntry struct {
3323 URL string `toml:"url"`
@@ -36,15 +26,6 @@ type RemoteEntry struct {
3626 InsecureTLS bool `toml:"insecure_tls,omitempty"`
3727 }
3828
39-// DefaultClientConfigPath returns the default client config path.
40-func DefaultClientConfigPath() string {
41- configDir, err := os.UserConfigDir()
42- if err != nil {
43- configDir = os.Getenv("HOME")
44- }
45- return filepath.Join(configDir, "gordon", "gordon.toml")
46-}
47-
4829 // DefaultRemotesPath returns the default remotes config path.
4930 func DefaultRemotesPath() string {
5031 configDir, err := os.UserConfigDir()
@@ -54,38 +35,6 @@ func DefaultRemotesPath() string {
5435 return filepath.Join(configDir, "gordon", "remotes.toml")
5536 }
5637
57-// LoadClientConfig loads the client configuration.
58-func LoadClientConfig(path string) (*ClientConfig, error) {
59- if path == "" {
60- path = DefaultClientConfigPath()
61- }
62-
63- data, err := os.ReadFile(path)
64- if err != nil {
65- if os.IsNotExist(err) {
66- // Return default config
67- return &ClientConfig{
68- Client: ClientSettings{
69- Mode: "local",
70- },
71- Remotes: make(map[string]RemoteEntry),
72- }, nil
73- }
74- return nil, fmt.Errorf("failed to read config: %w", err)
75- }
76-
77- var config ClientConfig
78- if err := toml.Unmarshal(data, &config); err != nil {
79- return nil, fmt.Errorf("failed to parse config: %w", err)
80- }
81-
82- if config.Remotes == nil {
83- config.Remotes = make(map[string]RemoteEntry)
84- }
85-
86- return &config, nil
87-}
88-
8938 // LoadRemotes loads the remotes configuration.
9039 func LoadRemotes(path string) (*ClientConfig, error) {
9140 if path == "" {
@@ -138,114 +87,6 @@ func SaveRemotes(path string, config *ClientConfig) error {
13887 return nil
13988 }
14089
141-// ResolveRemote resolves the remote URL and token from configuration.
142-// Precedence: flag > env > config > active remote
143-func ResolveRemote(flagRemote, flagToken string, flagInsecure bool) (url, token string, insecureTLS, isRemote bool) {
144- url, token, insecureTLS, _, isRemote = ResolveRemoteFull(flagRemote, flagToken, flagInsecure)
145- return url, token, insecureTLS, isRemote
146-}
147-
148-// ResolveRemoteFull resolves the remote URL, token, and named remote from configuration.
149-// It also returns the remote name for use in token persistence callbacks.
150-// Precedence: flag > env > config > active remote
151-func ResolveRemoteFull(flagRemote, flagToken string, flagInsecure bool) (url, token string, insecureTLS bool, remoteName string, isRemote bool) {
152- config, _ := LoadClientConfig("")
153- remotes, _ := LoadRemotes("")
154-
155- var name string
156- url, name, isRemote = resolveRemoteURL(flagRemote, config, remotes)
157- if isRemote {
158- // resolveToken looks up remotes.Active internally; name == remotes.Active here
159- // because resolveRemoteURL only sets name when it finds the active remote entry.
160- token = resolveToken(flagToken, config, remotes)
161- insecureTLS = resolveInsecureTLS(flagInsecure, config, remotes, name)
162- remoteName = name
163- }
164-
165- return url, token, insecureTLS, remoteName, isRemote
166-}
167-
168-// resolveRemoteURL resolves the remote URL from various sources.
169-func resolveRemoteURL(flagRemote string, config *ClientConfig, remotes *ClientConfig) (url, remoteName string, isRemote bool) {
170- // 1. Check flag
171- if flagRemote != "" {
172- return flagRemote, "", true
173- }
174-
175- // 2. Check environment variable
176- if envRemote := os.Getenv("GORDON_REMOTE"); envRemote != "" {
177- return envRemote, "", true
178- }
179-
180- // 3. Check client config
181- if config != nil && config.Client.Mode == "remote" && config.Client.Remote != "" {
182- return config.Client.Remote, "", true
183- }
184-
185- // 4. Check active remote
186- if remotes != nil && remotes.Active != "" {
187- if remote, ok := remotes.Remotes[remotes.Active]; ok {
188- return remote.URL, remotes.Active, true
189- }
190- }
191-
192- return "", "", false
193-}
194-
195-// resolveToken resolves the authentication token from various sources.
196-func resolveToken(flagToken string, config *ClientConfig, remotes *ClientConfig) string {
197- activeRemote := activeRemoteEntry(remotes)
198-
199- // 1. Flag token takes precedence
200- if flagToken != "" {
201- return flagToken
202- }
203-
204- // 2. Environment variable
205- if envToken := os.Getenv("GORDON_TOKEN"); envToken != "" {
206- return envToken
207- }
208-
209- // 3. Config token
210- if config != nil {
211- if config.Client.Token != "" {
212- return config.Client.Token
213- }
214- if config.Client.TokenEnv != "" {
215- if envToken := os.Getenv(config.Client.TokenEnv); envToken != "" {
216- return envToken
217- }
218- }
219- }
220-
221- // 4. Try pass store for active remote
222- if remotes != nil && remotes.Active != "" && passAvailable() {
223- if token, err := passReadToken(remotes.Active); err == nil && token != "" {
224- return token
225- }
226- }
227-
228- // 5. Active remote token
229- if token := resolveRemoteEntryToken(activeRemote); token != "" {
230- return token
231- }
232-
233- return ""
234-}
235-
236-func activeRemoteEntry(remotes *ClientConfig) *RemoteEntry {
237- if remotes == nil || remotes.Active == "" {
238- return nil
239- }
240-
241- remote, ok := remotes.Remotes[remotes.Active]
242- if !ok {
243- return nil
244- }
245-
246- return &remote
247-}
248-
24990 func resolveRemoteEntryToken(remote *RemoteEntry) string {
25091 if remote == nil {
25192 return ""
@@ -274,14 +115,13 @@ func ResolveTokenForRemote(name string, entry RemoteEntry) string {
274115 }
275116
276117 // ResolveInsecureTLSForRemote resolves insecure TLS behavior for a named remote.
277-// Precedence: flag > env > client config > specific remote config.
118+// Precedence: flag > env > specific remote config.
278119 func ResolveInsecureTLSForRemote(flagInsecure bool, remoteName string) bool {
279- config, _ := LoadClientConfig("")
280120 remotes, _ := LoadRemotes("")
281- return resolveInsecureTLS(flagInsecure, config, remotes, remoteName)
121+ return resolveInsecureTLS(flagInsecure, remotes, remoteName)
282122 }
283123
284-func resolveInsecureTLS(flagInsecure bool, config *ClientConfig, remotes *ClientConfig, remoteName string) bool {
124+func resolveInsecureTLS(flagInsecure bool, remotes *ClientConfig, remoteName string) bool {
285125 if flagInsecure {
286126 return true
287127 }
@@ -293,10 +133,6 @@ func resolveInsecureTLS(flagInsecure bool, config *ClientConfig, remotes *Client
293133 fmt.Fprintf(os.Stderr, "WARNING: invalid GORDON_INSECURE value %q, ignoring\n", env)
294134 }
295135
296- if config != nil && config.Client.InsecureTLS {
297- return true
298- }
299-
300136 if remoteName != "" && remotes != nil {
301137 if remote, ok := remotes.Remotes[remoteName]; ok && remote.InsecureTLS {
302138 return true
@@ -14,20 +14,10 @@ import (
14 14
15 // ClientConfig represents the client-mode configuration.15 // ClientConfig represents the client-mode configuration.
16 type ClientConfig struct {16 type ClientConfig struct {
17- Client ClientSettings `toml:"client"`
18 Remotes map[string]RemoteEntry `toml:"remotes"`17 Remotes map[string]RemoteEntry `toml:"remotes"`
19 Active string `toml:"active"` // Active remote name18 Active string `toml:"active"` // Active remote name
20 }19 }
21 20
22-// ClientSettings represents the [client] section.
23-type ClientSettings struct {
24- Mode string `toml:"mode"` // "local" (default) or "remote"
25- Remote string `toml:"remote"` // Remote Gordon URL
26- Token string `toml:"token"` // Auth token
27- TokenEnv string `toml:"token_env"` // Env var name for token
28- InsecureTLS bool `toml:"insecure_tls"` // Skip TLS verification for remote admin API
29-}
30-
31 // RemoteEntry represents a saved remote in [remotes.*].21 // RemoteEntry represents a saved remote in [remotes.*].
32 type RemoteEntry struct {22 type RemoteEntry struct {
33 URL string `toml:"url"`23 URL string `toml:"url"`
@@ -36,15 +26,6 @@ type RemoteEntry struct {
36 InsecureTLS bool `toml:"insecure_tls,omitempty"`26 InsecureTLS bool `toml:"insecure_tls,omitempty"`
37 }27 }
38 28
39-// DefaultClientConfigPath returns the default client config path.
40-func DefaultClientConfigPath() string {
41- configDir, err := os.UserConfigDir()
42- if err != nil {
43- configDir = os.Getenv("HOME")
44- }
45- return filepath.Join(configDir, "gordon", "gordon.toml")
46-}
47-
48 // DefaultRemotesPath returns the default remotes config path.29 // DefaultRemotesPath returns the default remotes config path.
49 func DefaultRemotesPath() string {30 func DefaultRemotesPath() string {
50 configDir, err := os.UserConfigDir()31 configDir, err := os.UserConfigDir()
@@ -54,38 +35,6 @@ func DefaultRemotesPath() string {
54 return filepath.Join(configDir, "gordon", "remotes.toml")35 return filepath.Join(configDir, "gordon", "remotes.toml")
55 }36 }
56 37
57-// LoadClientConfig loads the client configuration.
58-func LoadClientConfig(path string) (*ClientConfig, error) {
59- if path == "" {
60- path = DefaultClientConfigPath()
61- }
62-
63- data, err := os.ReadFile(path)
64- if err != nil {
65- if os.IsNotExist(err) {
66- // Return default config
67- return &ClientConfig{
68- Client: ClientSettings{
69- Mode: "local",
70- },
71- Remotes: make(map[string]RemoteEntry),
72- }, nil
73- }
74- return nil, fmt.Errorf("failed to read config: %w", err)
75- }
76-
77- var config ClientConfig
78- if err := toml.Unmarshal(data, &config); err != nil {
79- return nil, fmt.Errorf("failed to parse config: %w", err)
80- }
81-
82- if config.Remotes == nil {
83- config.Remotes = make(map[string]RemoteEntry)
84- }
85-
86- return &config, nil
87-}
88-
89 // LoadRemotes loads the remotes configuration.38 // LoadRemotes loads the remotes configuration.
90 func LoadRemotes(path string) (*ClientConfig, error) {39 func LoadRemotes(path string) (*ClientConfig, error) {
91 if path == "" {40 if path == "" {
@@ -138,114 +87,6 @@ func SaveRemotes(path string, config *ClientConfig) error {
138 return nil87 return nil
139 }88 }
140 89
141-// ResolveRemote resolves the remote URL and token from configuration.
142-// Precedence: flag > env > config > active remote
143-func ResolveRemote(flagRemote, flagToken string, flagInsecure bool) (url, token string, insecureTLS, isRemote bool) {
144- url, token, insecureTLS, _, isRemote = ResolveRemoteFull(flagRemote, flagToken, flagInsecure)
145- return url, token, insecureTLS, isRemote
146-}
147-
148-// ResolveRemoteFull resolves the remote URL, token, and named remote from configuration.
149-// It also returns the remote name for use in token persistence callbacks.
150-// Precedence: flag > env > config > active remote
151-func ResolveRemoteFull(flagRemote, flagToken string, flagInsecure bool) (url, token string, insecureTLS bool, remoteName string, isRemote bool) {
152- config, _ := LoadClientConfig("")
153- remotes, _ := LoadRemotes("")
154-
155- var name string
156- url, name, isRemote = resolveRemoteURL(flagRemote, config, remotes)
157- if isRemote {
158- // resolveToken looks up remotes.Active internally; name == remotes.Active here
159- // because resolveRemoteURL only sets name when it finds the active remote entry.
160- token = resolveToken(flagToken, config, remotes)
161- insecureTLS = resolveInsecureTLS(flagInsecure, config, remotes, name)
162- remoteName = name
163- }
164-
165- return url, token, insecureTLS, remoteName, isRemote
166-}
167-
168-// resolveRemoteURL resolves the remote URL from various sources.
169-func resolveRemoteURL(flagRemote string, config *ClientConfig, remotes *ClientConfig) (url, remoteName string, isRemote bool) {
170- // 1. Check flag
171- if flagRemote != "" {
172- return flagRemote, "", true
173- }
174-
175- // 2. Check environment variable
176- if envRemote := os.Getenv("GORDON_REMOTE"); envRemote != "" {
177- return envRemote, "", true
178- }
179-
180- // 3. Check client config
181- if config != nil && config.Client.Mode == "remote" && config.Client.Remote != "" {
182- return config.Client.Remote, "", true
183- }
184-
185- // 4. Check active remote
186- if remotes != nil && remotes.Active != "" {
187- if remote, ok := remotes.Remotes[remotes.Active]; ok {
188- return remote.URL, remotes.Active, true
189- }
190- }
191-
192- return "", "", false
193-}
194-
195-// resolveToken resolves the authentication token from various sources.
196-func resolveToken(flagToken string, config *ClientConfig, remotes *ClientConfig) string {
197- activeRemote := activeRemoteEntry(remotes)
198-
199- // 1. Flag token takes precedence
200- if flagToken != "" {
201- return flagToken
202- }
203-
204- // 2. Environment variable
205- if envToken := os.Getenv("GORDON_TOKEN"); envToken != "" {
206- return envToken
207- }
208-
209- // 3. Config token
210- if config != nil {
211- if config.Client.Token != "" {
212- return config.Client.Token
213- }
214- if config.Client.TokenEnv != "" {
215- if envToken := os.Getenv(config.Client.TokenEnv); envToken != "" {
216- return envToken
217- }
218- }
219- }
220-
221- // 4. Try pass store for active remote
222- if remotes != nil && remotes.Active != "" && passAvailable() {
223- if token, err := passReadToken(remotes.Active); err == nil && token != "" {
224- return token
225- }
226- }
227-
228- // 5. Active remote token
229- if token := resolveRemoteEntryToken(activeRemote); token != "" {
230- return token
231- }
232-
233- return ""
234-}
235-
236-func activeRemoteEntry(remotes *ClientConfig) *RemoteEntry {
237- if remotes == nil || remotes.Active == "" {
238- return nil
239- }
240-
241- remote, ok := remotes.Remotes[remotes.Active]
242- if !ok {
243- return nil
244- }
245-
246- return &remote
247-}
248-
249 func resolveRemoteEntryToken(remote *RemoteEntry) string {90 func resolveRemoteEntryToken(remote *RemoteEntry) string {
250 if remote == nil {91 if remote == nil {
251 return ""92 return ""
@@ -274,14 +115,13 @@ func ResolveTokenForRemote(name string, entry RemoteEntry) string {
274 }115 }
275 116
276 // ResolveInsecureTLSForRemote resolves insecure TLS behavior for a named remote.117 // ResolveInsecureTLSForRemote resolves insecure TLS behavior for a named remote.
277-// Precedence: flag > env > client config > specific remote config.118+// Precedence: flag > env > specific remote config.
278 func ResolveInsecureTLSForRemote(flagInsecure bool, remoteName string) bool {119 func ResolveInsecureTLSForRemote(flagInsecure bool, remoteName string) bool {
279- config, _ := LoadClientConfig("")
280 remotes, _ := LoadRemotes("")120 remotes, _ := LoadRemotes("")
281- return resolveInsecureTLS(flagInsecure, config, remotes, remoteName)121+ return resolveInsecureTLS(flagInsecure, remotes, remoteName)
282 }122 }
283 123
284-func resolveInsecureTLS(flagInsecure bool, config *ClientConfig, remotes *ClientConfig, remoteName string) bool {124+func resolveInsecureTLS(flagInsecure bool, remotes *ClientConfig, remoteName string) bool {
285 if flagInsecure {125 if flagInsecure {
286 return true126 return true
287 }127 }
@@ -293,10 +133,6 @@ func resolveInsecureTLS(flagInsecure bool, config *ClientConfig, remotes *Client
293 fmt.Fprintf(os.Stderr, "WARNING: invalid GORDON_INSECURE value %q, ignoring\n", env)133 fmt.Fprintf(os.Stderr, "WARNING: invalid GORDON_INSECURE value %q, ignoring\n", env)
294 }134 }
295 135
296- if config != nil && config.Client.InsecureTLS {
297- return true
298- }
299-
300 if remoteName != "" && remotes != nil {136 if remoteName != "" && remotes != nil {
301 if remote, ok := remotes.Remotes[remoteName]; ok && remote.InsecureTLS {137 if remote, ok := remotes.Remotes[remoteName]; ok && remote.InsecureTLS {
302 return true138 return true
M internal/adapters/in/cli/remote/config_test.go +0 -31
@@ -1,40 +1,9 @@
11 package remote
22
33 import (
4- "os"
5- "path/filepath"
64 "testing"
75 )
86
9-func TestResolveRemote_InsecureTLSFromClientConfig(t *testing.T) {
10- t.Setenv("XDG_CONFIG_HOME", t.TempDir())
11-
12- cfg := []byte(`
13-[client]
14-mode = "remote"
15-remote = "https://gordon.example.com"
16-insecure_tls = true
17-`)
18- path := DefaultClientConfigPath()
19- if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
20- t.Fatalf("mkdir config dir: %v", err)
21- }
22- if err := os.WriteFile(path, cfg, 0o600); err != nil {
23- t.Fatalf("write config: %v", err)
24- }
25-
26- url, _, insecure, isRemote := ResolveRemote("", "", false)
27- if !isRemote {
28- t.Fatalf("expected remote mode")
29- }
30- if url != "https://gordon.example.com" {
31- t.Fatalf("unexpected url: %s", url)
32- }
33- if !insecure {
34- t.Fatalf("expected insecure TLS true from client config")
35- }
36-}
37-
387 func TestResolveInsecureTLSForRemote_FromRemoteEntry(t *testing.T) {
398 t.Setenv("XDG_CONFIG_HOME", t.TempDir())
409
@@ -1,40 +1,9 @@
1 package remote1 package remote
2 2
3 import (3 import (
4- "os"
5- "path/filepath"
6 "testing"4 "testing"
7 )5 )
8 6
9-func TestResolveRemote_InsecureTLSFromClientConfig(t *testing.T) {
10- t.Setenv("XDG_CONFIG_HOME", t.TempDir())
11-
12- cfg := []byte(`
13-[client]
14-mode = "remote"
15-remote = "https://gordon.example.com"
16-insecure_tls = true
17-`)
18- path := DefaultClientConfigPath()
19- if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
20- t.Fatalf("mkdir config dir: %v", err)
21- }
22- if err := os.WriteFile(path, cfg, 0o600); err != nil {
23- t.Fatalf("write config: %v", err)
24- }
25-
26- url, _, insecure, isRemote := ResolveRemote("", "", false)
27- if !isRemote {
28- t.Fatalf("expected remote mode")
29- }
30- if url != "https://gordon.example.com" {
31- t.Fatalf("unexpected url: %s", url)
32- }
33- if !insecure {
34- t.Fatalf("expected insecure TLS true from client config")
35- }
36-}
37-
38 func TestResolveInsecureTLSForRemote_FromRemoteEntry(t *testing.T) {7 func TestResolveInsecureTLSForRemote_FromRemoteEntry(t *testing.T) {
39 t.Setenv("XDG_CONFIG_HOME", t.TempDir())8 t.Setenv("XDG_CONFIG_HOME", t.TempDir())
40 9

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 7

Tags 106

↑↓ moveenter openesc close