From 298d5153b028f75bc01eb6428f3829d3f98a749c Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Mon, 7 Sep 2026 14:35:23 +0100 Subject: [PATCH 1/3] fix: replace deprecated Dial and DialTLS with *Context alternatives Signed-off-by: Babak K. Shandiz --- pkg/api/http_client.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/api/http_client.go b/pkg/api/http_client.go index 4319373..3e69ac0 100644 --- a/pkg/api/http_client.go +++ b/pkg/api/http_client.go @@ -1,6 +1,7 @@ package api import ( + "context" "fmt" "io" "net" @@ -235,13 +236,13 @@ func (hrt headerRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro } func newUnixDomainSocketRoundTripper(socketPath string) http.RoundTripper { - dial := func(network, addr string) (net.Conn, error) { + dial := func(_ context.Context, network, addr string) (net.Conn, error) { return net.Dial("unix", socketPath) } return &http.Transport{ - Dial: dial, - DialTLS: dial, + DialContext: dial, + DialTLSContext: dial, DisableKeepAlives: true, } } From 03fea7518c1e27da210f4546878ee9e958d504a3 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Mon, 7 Sep 2026 14:35:52 +0100 Subject: [PATCH 2/3] fix: replace reflect.Ptr with reflect.Pointer Signed-off-by: Babak K. Shandiz --- pkg/x/markdown/accessibility_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/x/markdown/accessibility_test.go b/pkg/x/markdown/accessibility_test.go index 5e0ccc4..95294b8 100644 --- a/pkg/x/markdown/accessibility_test.go +++ b/pkg/x/markdown/accessibility_test.go @@ -192,7 +192,7 @@ func TestAccessibleLightStyleConfigIs4Bit(t *testing.T) { // that are downsampled to 4-bit colors unlike Glamour, which are 8-bit colors. // For more information, https://github.com/alecthomas/chroma/blob/0bf0e9f9ae2a81d463afe769cce01ff821bee3ba/formatters/tty_indexed.go#L32-L44 func validateColors(t *testing.T, v reflect.Value, path string) { - if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Pointer { if v.IsNil() { return } @@ -212,7 +212,7 @@ func validateColors(t *testing.T, v reflect.Value, path string) { if fieldType.Name == "Chroma" { continue } else if (fieldType.Name == "Color" || fieldType.Name == "BackgroundColor") && - fieldType.Type.Kind() == reflect.Ptr && fieldType.Type.Elem().Kind() == reflect.String { + fieldType.Type.Kind() == reflect.Pointer && fieldType.Type.Elem().Kind() == reflect.String { if field.IsNil() { continue From 2ce792192e434672d6605707215b2ca04bdd2450 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Tue, 15 Sep 2026 00:32:34 +0100 Subject: [PATCH 3/3] feat(config): add in-place Reload for refreshed reads Add Reload, which re-reads the gh config files from disk and refreshes the config returned by Read in place. Keeping the cached *Config pointer stable lets every existing holder observe the new values, which keeps auth host and token resolution (which reads through Read) consistent with callers that reload under a lock. Reload is a package-level var, like Read, so consumers and tests can replace it. Lock deepCopy so the in-place entries swap cannot race a concurrent read. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5c79efc-51d8-4913-8961-701522797f9e --- pkg/config/config.go | 24 +++++++++++++++++++++ pkg/config/config_test.go | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 9789a06..1cddc1f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -130,6 +130,8 @@ func (c *Config) Set(keys []string, value string) { } func (c *Config) deepCopy() *Config { + c.mu.RLock() + defer c.mu.RUnlock() return ReadFromString(c.entries.String()) } @@ -145,6 +147,28 @@ var Read = func(fallback *Config) (*Config, error) { return cfg, loadErr } +// Reload re-reads the gh configuration files from disk and refreshes the +// configuration returned by Read in place. The cached *Config keeps the same +// pointer, so every existing holder of it observes the new values. +// +// Any in-memory configuration changes that have not been written to disk are +// discarded by the refresh. Callers that need such changes preserved must Write +// them before calling Reload. +var Reload = func(fallback *Config) error { + cached, err := Read(fallback) + if err != nil { + return err + } + fresh, err := load(generalConfigFile(), hostsConfigFile(), fallback) + if err != nil { + return err + } + cached.mu.Lock() + defer cached.mu.Unlock() + cached.entries = fresh.entries + return nil +} + // ReadFromString takes a yaml string and returns a Config. func ReadFromString(str string) *Config { m, _ := mapFromString(str) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 01cb61b..08436e3 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "runtime" + "sync" "testing" "github.com/stretchr/testify/assert" @@ -290,6 +291,50 @@ func TestCacheDir(t *testing.T) { } +func TestReadAndReload(t *testing.T) { + once = sync.Once{} + cfg, loadErr = nil, nil + t.Cleanup(func() { + once = sync.Once{} + cfg, loadErr = nil, nil + }) + + dir := t.TempDir() + t.Setenv("GH_CONFIG_DIR", dir) + path := filepath.Join(dir, "config.yml") + require.NoError(t, os.WriteFile(path, []byte("editor: vim\n"), 0o600)) + + c, err := Read(nil) + require.NoError(t, err) + editor, err := c.Get([]string{"editor"}) + require.NoError(t, err) + assert.Equal(t, "vim", editor) + + require.NoError(t, os.WriteFile(path, []byte("editor: nano\n"), 0o600)) + + // Read still serves the cached value until an explicit Reload. + c, err = Read(nil) + require.NoError(t, err) + editor, err = c.Get([]string{"editor"}) + require.NoError(t, err) + assert.Equal(t, "vim", editor) + + require.NoError(t, Reload(nil)) + + // The previously obtained pointer observes the refreshed value in place. + editor, err = c.Get([]string{"editor"}) + require.NoError(t, err) + assert.Equal(t, "nano", editor) + + // Read returns the same, refreshed *Config pointer. + reread, err := Read(nil) + require.NoError(t, err) + assert.Same(t, c, reread) + editor, err = reread.Get([]string{"editor"}) + require.NoError(t, err) + assert.Equal(t, "nano", editor) +} + func TestLoad(t *testing.T) { tempDir := t.TempDir() globalFilePath := filepath.Join(tempDir, "config.yml")