Skip to content

Commit 83ced25

Browse files
authored
Modernize Go code per use-modern-go guidelines (#61)
Apply the gopls modernize analyzer (-fix -test) across all workspace modules, then a hand-reviewed sweep for guideline idioms the analyzer misses. All rewrites are mechanical and behavior-preserving; no public API changes. Analyzer: errors.AsType, range-over-int, slices.Contains/ContainsFunc/ Backward, atomic.Int32, reflect.TypeFor, new(bool) inline. Manual: sync.WaitGroup.Go, min/max clamp in BackoffDelay, strings. CutPrefix in decodeThreadID, strings.FieldsFuncSeq, json omitzero on bool/int wire fields. Validated: mise run vet + GOFLAGS=-race mise run test across all modules; burst/admission suites stressed with -race -count=5.
1 parent 8209f33 commit 83ced25

22 files changed

Lines changed: 64 additions & 110 deletions

‎adapters/linear/harden_capability_test.go‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,7 @@ func TestRateLimitDeadlineReturnsTypedRateLimited(t *testing.T) {
205205

206206
select {
207207
case err := <-done:
208-
var rl *linear.RateLimited
209-
if !errors.As(err, &rl) {
208+
if _, ok := errors.AsType[*linear.RateLimited](err); !ok {
210209
t.Fatalf("err = %v, want *linear.RateLimited (deadline-bounded, not slept off)", err)
211210
}
212211
if elapsed := time.Since(start); elapsed > time.Second {

‎adapters/linear/history.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"slices"
78

89
"github.com/coder/chat"
910
)
@@ -119,8 +120,7 @@ func (a *Adapter) readAgentSessionHistory(ctx context.Context, thread threadPayl
119120
nodes := resp.Data.AgentSession.Activities.Nodes
120121
messages := make([]chat.Message, 0, len(nodes))
121122
// Linear returns the page createdAt-ascending; reverse for newest-first.
122-
for i := len(nodes) - 1; i >= 0; i-- {
123-
node := nodes[i]
123+
for _, node := range slices.Backward(nodes) {
124124
messages = append(messages, chat.Message{
125125
ID: node.ID,
126126
Text: node.Content.Body,
@@ -164,8 +164,8 @@ func (a *Adapter) readCommentThreadHistory(ctx context.Context, thread threadPay
164164
children := resp.Data.Thread.Children.Nodes
165165
messages := make([]chat.Message, 0, len(children)+1)
166166
// Linear returns the page createdAt-ascending; reverse for newest-first.
167-
for i := len(children) - 1; i >= 0; i-- {
168-
messages = append(messages, historyCommentMessage(thread.Organization, children[i]))
167+
for _, c := range slices.Backward(children) {
168+
messages = append(messages, historyCommentMessage(thread.Organization, c))
169169
}
170170
// No older replies remain, so the root comment closes the oldest page.
171171
if !resp.Data.Thread.Children.PageInfo.HasPreviousPage {

‎adapters/linear/history_test.go‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,7 @@ func TestLinearReadHistoryRateLimitObservedAndErrors(t *testing.T) {
623623

624624
id := linear.EncodeAgentSessionThreadIDForTest("ORG1", "ISSUE1", "S1")
625625
msgs, err := hr.ReadHistory(context.Background(), id, chat.HistoryQuery{})
626-
var limited *linear.RateLimited
627-
if !errors.As(err, &limited) {
626+
if _, ok := errors.AsType[*linear.RateLimited](err); !ok {
628627
t.Fatalf("err = %v, want *linear.RateLimited on a throttled read", err)
629628
}
630629
if msgs != nil {

‎adapters/linear/linear.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ func (a *Adapter) Webhook(dispatch chat.DispatchFunc) http.Handler {
246246
}
247247
body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, maxWebhookBodyBytes))
248248
if err != nil {
249-
var maxBytesErr *http.MaxBytesError
250-
if errors.As(err, &maxBytesErr) {
249+
if _, ok := errors.AsType[*http.MaxBytesError](err); ok {
251250
http.Error(w, "linear webhook too large", http.StatusRequestEntityTooLarge)
252251
return
253252
}
@@ -926,10 +925,11 @@ func encodeThreadID(payload threadPayload) (chat.ThreadID, error) {
926925

927926
func decodeThreadID(id chat.ThreadID) (threadPayload, error) {
928927
const prefix = "linear:v1:"
929-
if !strings.HasPrefix(string(id), prefix) {
928+
rest, ok := strings.CutPrefix(string(id), prefix)
929+
if !ok {
930930
return threadPayload{}, fmt.Errorf("linear: malformed thread id %q", id)
931931
}
932-
body, err := base64.RawURLEncoding.DecodeString(strings.TrimPrefix(string(id), prefix))
932+
body, err := base64.RawURLEncoding.DecodeString(rest)
933933
if err != nil {
934934
return threadPayload{}, fmt.Errorf("linear: decode thread id: %w", err)
935935
}
@@ -1179,7 +1179,7 @@ func verifyGrantedScopes(requested []string, granted string) error {
11791179

11801180
func parseGrantedScopes(value string) map[string]struct{} {
11811181
out := map[string]struct{}{}
1182-
for _, scope := range strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' || r == '\t' || r == '\n' || r == '\r' }) {
1182+
for scope := range strings.FieldsFuncSeq(value, func(r rune) bool { return r == ',' || r == ' ' || r == '\t' || r == '\n' || r == '\r' }) {
11831183
scope = strings.TrimSpace(scope)
11841184
if scope != "" {
11851185
out[scope] = struct{}{}

‎adapters/linear/linear_test.go‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"io"
1212
"net/http"
1313
"net/http/httptest"
14+
"slices"
1415
"strings"
1516
"sync"
1617
"testing"
@@ -684,10 +685,8 @@ func containsToken(v any) bool {
684685
}
685686
}
686687
case []any:
687-
for _, val := range t {
688-
if containsToken(val) {
689-
return true
690-
}
688+
if slices.ContainsFunc(t, containsToken) {
689+
return true
691690
}
692691
}
693692
return false

‎adapters/slack/history.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ func (a *Adapter) ReadHistory(ctx context.Context, id chat.ThreadID, q chat.Hist
112112
type conversationsReadPayload struct {
113113
Channel string `json:"channel"`
114114
TS string `json:"ts,omitempty"`
115-
Limit int `json:"limit,omitempty"`
115+
Limit int `json:"limit,omitzero"`
116116
Latest string `json:"latest,omitempty"`
117-
Inclusive bool `json:"inclusive,omitempty"`
117+
Inclusive bool `json:"inclusive,omitzero"`
118118
}
119119

120120
type conversationsHistoryResponse struct {

‎adapters/slack/history_hardening_test.go‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ func TestSlackReadHistoryRateLimitObservedAndErrors(t *testing.T) {
123123

124124
id := slack.EncodeThreadReplyThreadIDForTest("T1", "C1", "111.000")
125125
msgs, err := hr.ReadHistory(context.Background(), id, chat.HistoryQuery{Limit: 5})
126-
var limited *slack.RateLimited
127-
if !errors.As(err, &limited) {
126+
if _, ok := errors.AsType[*slack.RateLimited](err); !ok {
128127
t.Fatalf("err = %v, want *slack.RateLimited on a throttled read", err)
129128
}
130129
if msgs != nil {

‎adapters/slack/interactive_hardening_test.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func TestSlackCommandDedupedByEventIdentity(t *testing.T) {
5757
}
5858

5959
form := signedCommandForm()
60-
for i := 0; i < 3; i++ {
60+
for i := range 3 {
6161
rec := serveSignedSlackForm(t, handler, now, form)
6262
if rec.Code != http.StatusOK {
6363
t.Fatalf("delivery %d status = %d", i, rec.Code)
@@ -100,7 +100,7 @@ func TestSlackInteractionDedupedByEventIdentity(t *testing.T) {
100100
"response_url":"https://hooks.slack.com/actions/T1/999",
101101
"actions":[{"action_id":"approve","block_id":"b1","value":"yes","type":"button"}]
102102
}`
103-
for i := 0; i < 3; i++ {
103+
for i := range 3 {
104104
rec := serveSignedSlackInteractivity(t, handler, now, payload)
105105
if rec.Code != http.StatusOK {
106106
t.Fatalf("delivery %d status = %d", i, rec.Code)
@@ -154,7 +154,7 @@ func TestSlackRepeatInteractionsAreDistinctEvents(t *testing.T) {
154154
for _, actionTS := range []string{"1700000001.000100", "1700000002.000200", "1700000003.000300"} {
155155
payload := activation(actionTS)
156156
// Deliver each activation twice: the original and a redelivery.
157-
for delivery := 0; delivery < 2; delivery++ {
157+
for delivery := range 2 {
158158
rec := serveSignedSlackInteractivity(t, handler, now, payload)
159159
if rec.Code != http.StatusOK {
160160
t.Fatalf("activation %s delivery %d status = %d", actionTS, delivery, rec.Code)

‎adapters/slack/multitenant_test.go‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"net/http"
8+
"slices"
89
"sync"
910
"testing"
1011
"time"
@@ -57,12 +58,7 @@ func (s *fakeInstallStore) callCount() int {
5758
func (s *fakeInstallStore) lookedUp(tenant string) bool {
5859
s.mu.Lock()
5960
defer s.mu.Unlock()
60-
for _, c := range s.calls {
61-
if c == "slack:"+tenant {
62-
return true
63-
}
64-
}
65-
return false
61+
return slices.Contains(s.calls, "slack:"+tenant)
6662
}
6763

6864
func TestSlackConstructionModeSelection(t *testing.T) {
@@ -400,15 +396,13 @@ func TestSlackMultiTenantConcurrentTenantsDoNotCross(t *testing.T) {
400396
}
401397
var wg sync.WaitGroup
402398
for _, team := range []string{"T1", "T2"} {
403-
wg.Add(1)
404-
go func(team string) {
405-
defer wg.Done()
399+
wg.Go(func() {
406400
rec := serveSignedSlackWebhook(t, handler, now,
407401
slackEventBody(team, "Ev"+team, "U"+team, "<@UBOT"+team[1:]+"> hi"), "", "")
408402
if rec.Code != http.StatusOK {
409403
t.Errorf("team %s status = %d", team, rec.Code)
410404
}
411-
}(team)
405+
})
412406
}
413407
wg.Wait()
414408

‎adapters/slack/ratelimit_hardening_test.go‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,7 @@ func TestSlackPostNeverSleepsPastContextDeadline(t *testing.T) {
258258

259259
select {
260260
case err := <-done:
261-
var limited *slack.RateLimited
262-
if !errors.As(err, &limited) {
261+
if _, ok := errors.AsType[*slack.RateLimited](err); !ok {
263262
t.Fatalf("err = %v, want *slack.RateLimited (deadline-bounded, not slept off)", err)
264263
}
265264
case <-time.After(5 * time.Second):
@@ -306,8 +305,7 @@ func TestSlackPostDoesNotRetryNonThrottlingError(t *testing.T) {
306305
if postErr == nil {
307306
t.Fatal("expected an error from a 401 auth failure")
308307
}
309-
var limited *slack.RateLimited
310-
if errors.As(postErr, &limited) {
308+
if _, ok := errors.AsType[*slack.RateLimited](postErr); ok {
311309
t.Fatal("a non-throttling 401 must not surface as RateLimited")
312310
}
313311
mu.Lock()
@@ -337,8 +335,7 @@ func TestSlackDefaultPolicyCeilingUnderAckWindow(t *testing.T) {
337335
_, err := adapter.PostMessage(context.Background(), ref, chat.Text("hi"))
338336
elapsed := time.Since(start)
339337

340-
var limited *slack.RateLimited
341-
if !errors.As(err, &limited) {
338+
if _, ok := errors.AsType[*slack.RateLimited](err); !ok {
342339
t.Fatalf("err = %v, want *slack.RateLimited", err)
343340
}
344341
if elapsed >= 3*time.Second {

0 commit comments

Comments
 (0)