From b1bfdd52cbab14f6d13634dda08fd58fc48fd8e7 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:04:55 +0200 Subject: [PATCH 1/6] Bump Go toolchain to go1.26.3 Bump Go to `go1.26.0` / `toolchain go1.26.3` across all four modules. This cleans up an inconsistency: `go.mod`, `tools/task/go.mod`, and `bundle/internal/tf/codegen/go.mod` were sitting at `go 1.25.8` while `tools/go.mod` had drifted back to `go 1.25.0`. All four are now in sync. Release notes: https://go.dev/doc/go1.26 Co-authored-by: Isaac --- bundle/internal/tf/codegen/go.mod | 4 ++-- go.mod | 4 ++-- tools/go.mod | 4 ++-- tools/task/go.mod | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bundle/internal/tf/codegen/go.mod b/bundle/internal/tf/codegen/go.mod index 6d3956c8ad6..776c067a604 100644 --- a/bundle/internal/tf/codegen/go.mod +++ b/bundle/internal/tf/codegen/go.mod @@ -1,8 +1,8 @@ module github.com/databricks/cli/bundle/internal/tf/codegen -go 1.25.8 +go 1.26.0 -toolchain go1.25.10 +toolchain go1.26.3 require ( github.com/hashicorp/go-version v1.9.0 diff --git a/go.mod b/go.mod index 0bb3109463e..50c45ad551b 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/databricks/cli -go 1.25.8 +go 1.26.0 -toolchain go1.25.10 +toolchain go1.26.3 require ( dario.cat/mergo v1.0.2 // BSD-3-Clause diff --git a/tools/go.mod b/tools/go.mod index 4b84239abcc..23a03db6721 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,8 +1,8 @@ module github.com/databricks/cli/tools -go 1.25.0 +go 1.26.0 -toolchain go1.25.10 +toolchain go1.26.3 require github.com/stretchr/testify v1.11.1 diff --git a/tools/task/go.mod b/tools/task/go.mod index 623da6fa617..cc3f0201735 100644 --- a/tools/task/go.mod +++ b/tools/task/go.mod @@ -1,8 +1,8 @@ module github.com/databricks/cli/tools/task -go 1.25.8 +go 1.26.0 -toolchain go1.25.10 +toolchain go1.26.3 require ( cel.dev/expr v0.25.1 // indirect From 8893371b4476d55110628d7e2c691675f4b16714 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:25:33 +0200 Subject: [PATCH 2/6] Apply golangci-lint --fix for Go 1.26 modernize Bumping the `go` directive to 1.26.0 unlocks two modernize analyzers that were silent on 1.25: * stditerators - prefer reflect.Type.Fields()/Methods() and reflect.Value.Fields()/Methods() over the classic NumField()/Field(i) loop pattern. * newexpr - replace local `*T` helpers like `func intPtr(v int) *int { return &v }` (and their callers) with Go 1.26's `new(expr)`. This commit is the verbatim output of `golangci-lint run --fix ./...`, applied at the same time as the toolchain bump so CI doesn't fail the moment the bump lands. A few `field := field` style redeclarations the fixer leaves behind are harmless (the loop variable is fresh per-iteration since Go 1.22). Leaving those for a follow-up cleanup rather than expanding the diff here. Co-authored-by: Isaac --- bundle/config/resources/dashboard_test.go | 8 ++++---- bundle/config/resources_test.go | 12 +++++------ .../terraform/tfdyn/convert_job_test.go | 8 ++++---- bundle/direct/dresources/app_test.go | 4 ++-- bundle/direct/dresources/util_test.go | 8 ++++---- bundle/docsgen/nodes_test.go | 11 +++++----- bundle/internal/schema/parser.go | 6 +++--- cmd/pipelines/history_test.go | 4 +++- libs/apps/runlocal/spec_test.go | 20 ++++++++++--------- libs/calladapt/validate.go | 8 ++++---- libs/cmdio/pager_test.go | 6 +++--- libs/jsonschema/from_type.go | 8 ++++---- libs/structs/structaccess/convert_test.go | 20 +++++++++++-------- libs/structs/structaccess/typecheck.go | 8 ++++---- libs/structs/structwalk/walktype.go | 4 ++-- 15 files changed, 72 insertions(+), 63 deletions(-) diff --git a/bundle/config/resources/dashboard_test.go b/bundle/config/resources/dashboard_test.go index c010d949157..0011833896e 100644 --- a/bundle/config/resources/dashboard_test.go +++ b/bundle/config/resources/dashboard_test.go @@ -29,8 +29,8 @@ func TestDashboardConfigIsSupersetOfSDKDashboard(t *testing.T) { // Create a map of SDK fields by name and their JSON tags sdkFields := make(map[string]string) - for i := range sdkType.NumField() { - field := sdkType.Field(i) + for field := range sdkType.Fields() { + field := field jsonTag := field.Tag.Get("json") jsonName := getJSONTagName(jsonTag) if jsonName != "" { @@ -40,8 +40,8 @@ func TestDashboardConfigIsSupersetOfSDKDashboard(t *testing.T) { // Create a map of config fields by name and their JSON tags configFields := make(map[string]string) - for i := range configType.NumField() { - field := configType.Field(i) + for field := range configType.Fields() { + field := field jsonTag := field.Tag.Get("json") jsonName := getJSONTagName(jsonTag) if jsonName != "" { diff --git a/bundle/config/resources_test.go b/bundle/config/resources_test.go index 1be4a84a1f8..a3d47b5b4b7 100644 --- a/bundle/config/resources_test.go +++ b/bundle/config/resources_test.go @@ -53,8 +53,8 @@ import ( func TestCustomMarshallerIsImplemented(t *testing.T) { rt := reflect.TypeFor[Resources]() - for i := range rt.NumField() { - field := rt.Field(i) + for field := range rt.Fields() { + field := field // Fields in Resources are expected be of the form map[string]*resourceStruct assert.Equal(t, reflect.Map, field.Type.Kind(), "Resource %s is not a map", field.Name) @@ -95,8 +95,8 @@ func TestResourcesAllResourcesCompleteness(t *testing.T) { types = append(types, group.Description.PluralName) } - for i := range rt.NumField() { - field := rt.Field(i) + for field := range rt.Fields() { + field := field jsonTag := field.Tag.Get("json") if idx := strings.Index(jsonTag, ","); idx != -1 { @@ -112,8 +112,8 @@ func TestSupportedResources(t *testing.T) { actual := SupportedResources() typ := reflect.TypeFor[Resources]() - for i := range typ.NumField() { - field := typ.Field(i) + for field := range typ.Fields() { + field := field jsonTags := strings.Split(field.Tag.Get("json"), ",") pluralName := jsonTags[0] assert.Equal(t, actual[pluralName].PluralName, pluralName) diff --git a/bundle/deploy/terraform/tfdyn/convert_job_test.go b/bundle/deploy/terraform/tfdyn/convert_job_test.go index 1f67369e916..6624e3e2c6d 100644 --- a/bundle/deploy/terraform/tfdyn/convert_job_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_job_test.go @@ -296,8 +296,8 @@ func TestSupportedTypeTasksComplete(t *testing.T) { taskType := reflect.TypeFor[jobs.Task]() var tasksWithSource []string - for i := range taskType.NumField() { - field := taskType.Field(i) + for field := range taskType.Fields() { + field := field // Skip non-task fields (like DependsOn, Libraries, etc.) if !strings.HasSuffix(field.Name, "Task") { @@ -351,8 +351,8 @@ func findSourceFieldsShallow(t reflect.Type) []string { var paths []string - for i := range t.NumField() { - field := t.Field(i) + for field := range t.Fields() { + field := field // Check if this field is named "Source" if field.Name == "Source" { diff --git a/bundle/direct/dresources/app_test.go b/bundle/direct/dresources/app_test.go index edb99c4cffb..b1a20632550 100644 --- a/bundle/direct/dresources/app_test.go +++ b/bundle/direct/dresources/app_test.go @@ -149,8 +149,8 @@ func TestAppDoUpdate_UpdateMaskHasAllFields(t *testing.T) { fields := reflect.TypeFor[apps.App]() var allFields []string - for i := range fields.NumField() { - field := fields.Field(i) + for field := range fields.Fields() { + field := field jsonTag := field.Tag.Get("json") if jsonTag == "" || jsonTag == "-" { continue diff --git a/bundle/direct/dresources/util_test.go b/bundle/direct/dresources/util_test.go index bf945aa09b5..e1630d0c5f9 100644 --- a/bundle/direct/dresources/util_test.go +++ b/bundle/direct/dresources/util_test.go @@ -12,15 +12,15 @@ import ( func assertFieldsCovered(t *testing.T, sdkType, remoteType reflect.Type, skip map[string]bool) { t.Helper() remoteFields := map[string]bool{} - for i := range remoteType.NumField() { - f := remoteType.Field(i) + for f := range remoteType.Fields() { + f := f if !f.Anonymous { remoteFields[f.Name] = true } } - for i := range sdkType.NumField() { - field := sdkType.Field(i) + for field := range sdkType.Fields() { + field := field if skip[field.Name] { assert.NotContains(t, remoteFields, field.Name, "field %s is in skip list but present in %s; remove it from skip", field.Name, remoteType.Name()) continue diff --git a/bundle/docsgen/nodes_test.go b/bundle/docsgen/nodes_test.go index 028bf1eff62..2b5bd6ca025 100644 --- a/bundle/docsgen/nodes_test.go +++ b/bundle/docsgen/nodes_test.go @@ -25,7 +25,7 @@ func TestBuildNodes_ChildExpansion(t *testing.T) { Items: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ - "listSub": {Reference: strPtr("#/$defs/github.com/listSub")}, + "listSub": {Reference: new("#/$defs/github.com/listSub")}, }, }, }, @@ -61,9 +61,9 @@ func TestBuildNodes_ChildExpansion(t *testing.T) { "myMap": { Type: "object", AdditionalProperties: &jsonschema.Schema{ - Reference: strPtr("#/$defs/github.com/myMap"), + Reference: new("#/$defs/github.com/myMap"), Properties: map[string]*jsonschema.Schema{ - "mapSub": {Type: "object", Reference: strPtr("#/$defs/github.com/mapSub")}, + "mapSub": {Type: "object", Reference: new("#/$defs/github.com/mapSub")}, }, }, }, @@ -73,7 +73,7 @@ func TestBuildNodes_ChildExpansion(t *testing.T) { "github.com/myMap": { Type: "object", Properties: map[string]*jsonschema.Schema{ - "mapSub": {Type: "boolean", Reference: strPtr("#/$defs/github.com/mapSub")}, + "mapSub": {Type: "boolean", Reference: new("#/$defs/github.com/mapSub")}, }, }, "github.com/mapSub": { @@ -171,6 +171,7 @@ func TestDoNotSuggestFields(t *testing.T) { assert.Equal(t, "nestedNotDoNotSuggestField", nodes[0].Attributes[0].Title) } +//go:fix inline func strPtr(s string) *string { - return &s + return new(s) } diff --git a/bundle/internal/schema/parser.go b/bundle/internal/schema/parser.go index d72524dc59c..ba0c8545ce2 100644 --- a/bundle/internal/schema/parser.go +++ b/bundle/internal/schema/parser.go @@ -58,13 +58,13 @@ func (p *openapiParser) findRef(typ reflect.Type) (jsonschema.Schema, bool) { // Check for embedded Databricks Go SDK types. if typ.Kind() == reflect.Struct { - for i := range typ.NumField() { - if !typ.Field(i).Anonymous { + for field := range typ.Fields() { + if !field.Anonymous { continue } // Deference current type if it's a pointer. - ctyp := typ.Field(i).Type + ctyp := field.Type for ctyp.Kind() == reflect.Ptr { ctyp = ctyp.Elem() } diff --git a/cmd/pipelines/history_test.go b/cmd/pipelines/history_test.go index 86d6d7d9d6e..59b9928b034 100644 --- a/cmd/pipelines/history_test.go +++ b/cmd/pipelines/history_test.go @@ -291,4 +291,6 @@ func TestFilterUpdates(t *testing.T) { } // Helper function to create int64 pointers -func int64Ptr(v int64) *int64 { return &v } +// +//go:fix inline +func int64Ptr(v int64) *int64 { return new(v) } diff --git a/libs/apps/runlocal/spec_test.go b/libs/apps/runlocal/spec_test.go index 3b3cfde51aa..7425e9ce778 100644 --- a/libs/apps/runlocal/spec_test.go +++ b/libs/apps/runlocal/spec_test.go @@ -28,11 +28,11 @@ func TestAppSpecLoadEnvVars(t *testing.T) { EnvVars: []AppEnvVar{ { Name: "VAR1", - Value: stringPtr("value1"), + Value: new("value1"), }, { Name: "VAR2", - Value: stringPtr("value2"), + Value: new("value2"), }, }, } @@ -53,11 +53,11 @@ func TestAppSpecLoadEnvVars(t *testing.T) { EnvVars: []AppEnvVar{ { Name: "VAR1", - ValueFrom: stringPtr("VAR1"), + ValueFrom: new("VAR1"), }, { Name: "VAR2", - ValueFrom: stringPtr("VAR2"), + ValueFrom: new("VAR2"), }, }, } @@ -77,11 +77,11 @@ func TestAppSpecLoadEnvVars(t *testing.T) { EnvVars: []AppEnvVar{ { Name: "VAR1", - Value: stringPtr("value1"), + Value: new("value1"), }, { Name: "VAR2", - ValueFrom: stringPtr("VAR2"), + ValueFrom: new("VAR2"), }, }, } @@ -101,7 +101,7 @@ func TestAppSpecLoadEnvVars(t *testing.T) { EnvVars: []AppEnvVar{ { Name: "VAR1", - ValueFrom: stringPtr("VAR1"), + ValueFrom: new("VAR1"), }, }, } @@ -121,7 +121,7 @@ func TestAppSpecLoadEnvVars(t *testing.T) { EnvVars: []AppEnvVar{ { Name: "VAR1", - ValueFrom: stringPtr("MISSING_VAR"), + ValueFrom: new("MISSING_VAR"), }, }, } @@ -151,6 +151,8 @@ func TestAppSpecLoadEnvVars(t *testing.T) { } // Helper function to create a string pointer +// +//go:fix inline func stringPtr(s string) *string { - return &s + return new(s) } diff --git a/libs/calladapt/validate.go b/libs/calladapt/validate.go index 8613d42d906..80b9023dc56 100644 --- a/libs/calladapt/validate.go +++ b/libs/calladapt/validate.go @@ -11,13 +11,13 @@ func EnsureNoExtraMethods(receiver any, ifaceTypes ...reflect.Type) error { allowed := make(map[string]struct{}) for _, ifaceType := range ifaceTypes { - for i := range ifaceType.NumMethod() { - allowed[ifaceType.Method(i).Name] = struct{}{} + for method := range ifaceType.Methods() { + allowed[method.Name] = struct{}{} } } - for i := range rt.NumMethod() { - m := rt.Method(i) + for m := range rt.Methods() { + m := m if _, ok := allowed[m.Name]; !ok { return fmt.Errorf("unexpected method %s on %v; only methods from %v are allowed", m.Name, rt, ifaceTypes) } diff --git a/libs/cmdio/pager_test.go b/libs/cmdio/pager_test.go index 645b26cbd04..3c76c1ee323 100644 --- a/libs/cmdio/pager_test.go +++ b/libs/cmdio/pager_test.go @@ -57,9 +57,9 @@ func printedText(t *testing.T, msg tea.Msg) string { t.Helper() rv := reflect.ValueOf(msg) require.Equal(t, reflect.Struct, rv.Kind(), "expected a struct msg, got %T", msg) - for i := range rv.NumField() { - if rv.Field(i).Kind() == reflect.String { - return rv.Field(i).String() + for _, field := range rv.Fields() { + if field.Kind() == reflect.String { + return field.String() } } t.Fatalf("no string field in %T", msg) diff --git a/libs/jsonschema/from_type.go b/libs/jsonschema/from_type.go index 356db14b6b8..8c6213b07ed 100644 --- a/libs/jsonschema/from_type.go +++ b/libs/jsonschema/from_type.go @@ -224,8 +224,8 @@ func getStructFields(typ reflect.Type) []reflect.StructField { var fields []reflect.StructField bfsQueue := list.New() - for i := range typ.NumField() { - bfsQueue.PushBack(typ.Field(i)) + for field := range typ.Fields() { + bfsQueue.PushBack(field) } for bfsQueue.Len() > 0 { front := bfsQueue.Front() @@ -246,8 +246,8 @@ func getStructFields(typ reflect.Type) []reflect.StructField { fieldType = fieldType.Elem() } - for i := range fieldType.NumField() { - bfsQueue.PushBack(fieldType.Field(i)) + for field := range fieldType.Fields() { + bfsQueue.PushBack(field) } } return fields diff --git a/libs/structs/structaccess/convert_test.go b/libs/structs/structaccess/convert_test.go index 02fcfc700ab..43f5003af12 100644 --- a/libs/structs/structaccess/convert_test.go +++ b/libs/structs/structaccess/convert_test.go @@ -61,22 +61,22 @@ func TestConvertToString(t *testing.T) { // Pointers { name: "string pointer", - value: stringPtr("test"), + value: new("test"), expected: "test", }, { name: "int pointer", - value: intPtr(123), + value: new(123), expected: "123", }, { name: "float64 pointer", - value: float64Ptr(2.5), + value: new(2.5), expected: "2.5", }, { name: "bool pointer", - value: boolPtr(true), + value: new(true), expected: "true", }, { @@ -147,18 +147,22 @@ func TestConvertToString(t *testing.T) { } } +//go:fix inline func stringPtr(s string) *string { - return &s + return new(s) } +//go:fix inline func intPtr(i int) *int { - return &i + return new(i) } +//go:fix inline func float64Ptr(f float64) *float64 { - return &f + return new(f) } +//go:fix inline func boolPtr(b bool) *bool { - return &b + return new(b) } diff --git a/libs/structs/structaccess/typecheck.go b/libs/structs/structaccess/typecheck.go index 2fa9a1f8d44..f2c91e13e5c 100644 --- a/libs/structs/structaccess/typecheck.go +++ b/libs/structs/structaccess/typecheck.go @@ -142,8 +142,8 @@ func FindStructFieldByKeyType(t reflect.Type, key string) (reflect.StructField, } // First pass: direct fields - for i := range t.NumField() { - sf := t.Field(i) + for sf := range t.Fields() { + sf := sf if sf.PkgPath != "" { // unexported continue } @@ -162,8 +162,8 @@ func FindStructFieldByKeyType(t reflect.Type, key string) (reflect.StructField, } // Second pass: search embedded anonymous structs recursively (flattening semantics) - for i := range t.NumField() { - sf := t.Field(i) + for sf := range t.Fields() { + sf := sf if !sf.Anonymous { continue } diff --git a/libs/structs/structwalk/walktype.go b/libs/structs/structwalk/walktype.go index 495a369d64a..dc7e958b600 100644 --- a/libs/structs/structwalk/walktype.go +++ b/libs/structs/structwalk/walktype.go @@ -104,8 +104,8 @@ func walkTypeValue(path *structpath.PatternNode, typ reflect.Type, field *reflec } func walkTypeStruct(path *structpath.PatternNode, st reflect.Type, visit VisitTypeFunc, visitedCount map[reflect.Type]int) { - for i := range st.NumField() { - sf := st.Field(i) + for sf := range st.Fields() { + sf := sf if sf.PkgPath != "" { continue // unexported } From 5313b9fb6a6006de3ada287f49185dfcfc64037d Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:31:58 +0200 Subject: [PATCH 3/6] Clean up modernize fix-up output Follow-up to the previous commit, which the previous commit message deferred. Two cosmetic clean-ups: 1. Remove 14 redundant `x := x` redeclarations the modernize fixer left inside `for x := range t.Fields()` (or `.Methods()`) loops. The loop variable is already fresh per-iteration since Go 1.22, so the shadow was a no-op kept only to preserve the variable name from the old `field := t.Field(i)` pattern. 2. Remove dead `*Ptr` helper functions whose call sites were inlined to `new(expr)`. The fixer added `//go:fix inline` directives and rewrote the bodies to `return new(v)`, leaving the functions themselves with zero callers (except `int64Ptr`, where `new(700)` would yield `*int` instead of `*int64`; here we rewrite the 20 callers to `new(int64(N))` and drop the helper too). * bundle/docsgen/nodes_test.go: drop strPtr * libs/apps/runlocal/spec_test.go: drop stringPtr * libs/structs/structaccess/convert_test.go: drop stringPtr, intPtr, float64Ptr, boolPtr * cmd/pipelines/history_test.go: rewrite int64Ptr callers, drop helper Co-authored-by: Isaac --- bundle/config/resources/dashboard_test.go | 2 - bundle/config/resources_test.go | 4 -- .../terraform/tfdyn/convert_job_test.go | 4 -- bundle/direct/dresources/app_test.go | 1 - bundle/direct/dresources/util_test.go | 2 - bundle/docsgen/nodes_test.go | 5 --- cmd/pipelines/history_test.go | 45 +++++++++---------- libs/apps/runlocal/spec_test.go | 7 --- libs/calladapt/validate.go | 1 - libs/structs/structaccess/convert_test.go | 20 --------- libs/structs/structaccess/typecheck.go | 2 - libs/structs/structwalk/walktype.go | 1 - 12 files changed, 20 insertions(+), 74 deletions(-) diff --git a/bundle/config/resources/dashboard_test.go b/bundle/config/resources/dashboard_test.go index 0011833896e..83c80b17107 100644 --- a/bundle/config/resources/dashboard_test.go +++ b/bundle/config/resources/dashboard_test.go @@ -30,7 +30,6 @@ func TestDashboardConfigIsSupersetOfSDKDashboard(t *testing.T) { // Create a map of SDK fields by name and their JSON tags sdkFields := make(map[string]string) for field := range sdkType.Fields() { - field := field jsonTag := field.Tag.Get("json") jsonName := getJSONTagName(jsonTag) if jsonName != "" { @@ -41,7 +40,6 @@ func TestDashboardConfigIsSupersetOfSDKDashboard(t *testing.T) { // Create a map of config fields by name and their JSON tags configFields := make(map[string]string) for field := range configType.Fields() { - field := field jsonTag := field.Tag.Get("json") jsonName := getJSONTagName(jsonTag) if jsonName != "" { diff --git a/bundle/config/resources_test.go b/bundle/config/resources_test.go index a3d47b5b4b7..a75863d70b5 100644 --- a/bundle/config/resources_test.go +++ b/bundle/config/resources_test.go @@ -54,8 +54,6 @@ func TestCustomMarshallerIsImplemented(t *testing.T) { rt := reflect.TypeFor[Resources]() for field := range rt.Fields() { - field := field - // Fields in Resources are expected be of the form map[string]*resourceStruct assert.Equal(t, reflect.Map, field.Type.Kind(), "Resource %s is not a map", field.Name) kt := field.Type.Key() @@ -96,7 +94,6 @@ func TestResourcesAllResourcesCompleteness(t *testing.T) { } for field := range rt.Fields() { - field := field jsonTag := field.Tag.Get("json") if idx := strings.Index(jsonTag, ","); idx != -1 { @@ -113,7 +110,6 @@ func TestSupportedResources(t *testing.T) { typ := reflect.TypeFor[Resources]() for field := range typ.Fields() { - field := field jsonTags := strings.Split(field.Tag.Get("json"), ",") pluralName := jsonTags[0] assert.Equal(t, actual[pluralName].PluralName, pluralName) diff --git a/bundle/deploy/terraform/tfdyn/convert_job_test.go b/bundle/deploy/terraform/tfdyn/convert_job_test.go index 6624e3e2c6d..f7a69f77a01 100644 --- a/bundle/deploy/terraform/tfdyn/convert_job_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_job_test.go @@ -297,8 +297,6 @@ func TestSupportedTypeTasksComplete(t *testing.T) { var tasksWithSource []string for field := range taskType.Fields() { - field := field - // Skip non-task fields (like DependsOn, Libraries, etc.) if !strings.HasSuffix(field.Name, "Task") { continue @@ -352,8 +350,6 @@ func findSourceFieldsShallow(t reflect.Type) []string { var paths []string for field := range t.Fields() { - field := field - // Check if this field is named "Source" if field.Name == "Source" { paths = append(paths, "") diff --git a/bundle/direct/dresources/app_test.go b/bundle/direct/dresources/app_test.go index b1a20632550..c7cbfacd1af 100644 --- a/bundle/direct/dresources/app_test.go +++ b/bundle/direct/dresources/app_test.go @@ -150,7 +150,6 @@ func TestAppDoUpdate_UpdateMaskHasAllFields(t *testing.T) { fields := reflect.TypeFor[apps.App]() var allFields []string for field := range fields.Fields() { - field := field jsonTag := field.Tag.Get("json") if jsonTag == "" || jsonTag == "-" { continue diff --git a/bundle/direct/dresources/util_test.go b/bundle/direct/dresources/util_test.go index e1630d0c5f9..544b3e2bde8 100644 --- a/bundle/direct/dresources/util_test.go +++ b/bundle/direct/dresources/util_test.go @@ -13,14 +13,12 @@ func assertFieldsCovered(t *testing.T, sdkType, remoteType reflect.Type, skip ma t.Helper() remoteFields := map[string]bool{} for f := range remoteType.Fields() { - f := f if !f.Anonymous { remoteFields[f.Name] = true } } for field := range sdkType.Fields() { - field := field if skip[field.Name] { assert.NotContains(t, remoteFields, field.Name, "field %s is in skip list but present in %s; remove it from skip", field.Name, remoteType.Name()) continue diff --git a/bundle/docsgen/nodes_test.go b/bundle/docsgen/nodes_test.go index 2b5bd6ca025..227d1bc01b3 100644 --- a/bundle/docsgen/nodes_test.go +++ b/bundle/docsgen/nodes_test.go @@ -170,8 +170,3 @@ func TestDoNotSuggestFields(t *testing.T) { assert.Len(t, nodes[0].Attributes, 1) assert.Equal(t, "nestedNotDoNotSuggestField", nodes[0].Attributes[0].Title) } - -//go:fix inline -func strPtr(s string) *string { - return new(s) -} diff --git a/cmd/pipelines/history_test.go b/cmd/pipelines/history_test.go index 59b9928b034..c1baec58327 100644 --- a/cmd/pipelines/history_test.go +++ b/cmd/pipelines/history_test.go @@ -24,25 +24,25 @@ func TestUpdatesBefore(t *testing.T) { }{ { name: "before 700", - timestamp: int64Ptr(700), + timestamp: new(int64(700)), expectedCount: 3, expectedFirst: 600, }, { name: "before 1000", - timestamp: int64Ptr(1000), + timestamp: new(int64(1000)), expectedCount: 5, expectedFirst: 1000, }, { name: "before 200", - timestamp: int64Ptr(200), + timestamp: new(int64(200)), expectedCount: 1, expectedFirst: 200, }, { name: "before 100", - timestamp: int64Ptr(100), + timestamp: new(int64(100)), expectedCount: 0, expectedFirst: 0, }, @@ -79,25 +79,25 @@ func TestUpdatesAfter(t *testing.T) { }{ { name: "after 500", - timestamp: int64Ptr(500), + timestamp: new(int64(500)), expectedCount: 3, expectedFirst: 1000, }, { name: "after 200", - timestamp: int64Ptr(200), + timestamp: new(int64(200)), expectedCount: 5, expectedFirst: 1000, }, { name: "after 1000", - timestamp: int64Ptr(1000), + timestamp: new(int64(1000)), expectedCount: 1, expectedFirst: 1000, }, { name: "after 1200", - timestamp: int64Ptr(1200), + timestamp: new(int64(1200)), expectedCount: 0, expectedFirst: 0, }, @@ -181,7 +181,7 @@ func TestFilterUpdates(t *testing.T) { name: "start time nil, end time set", updates: updates, startTime: nil, - endTime: int64Ptr(700), + endTime: new(int64(700)), expectedCount: 3, expectedFirst: 600, expectedLast: 200, @@ -189,7 +189,7 @@ func TestFilterUpdates(t *testing.T) { { name: "start time set, end time nil", updates: updates, - startTime: int64Ptr(500), + startTime: new(int64(500)), endTime: nil, expectedCount: 3, expectedFirst: 1000, @@ -198,8 +198,8 @@ func TestFilterUpdates(t *testing.T) { { name: "both times set within range", updates: updates, - startTime: int64Ptr(300), - endTime: int64Ptr(900), + startTime: new(int64(300)), + endTime: new(int64(900)), expectedCount: 3, expectedFirst: 800, expectedLast: 400, @@ -207,8 +207,8 @@ func TestFilterUpdates(t *testing.T) { { name: "both times set, no overlap", updates: updates, - startTime: int64Ptr(1200), - endTime: int64Ptr(1500), + startTime: new(int64(1200)), + endTime: new(int64(1500)), expectedCount: 0, expectedFirst: 0, expectedLast: 0, @@ -216,7 +216,7 @@ func TestFilterUpdates(t *testing.T) { { name: "start time after all updates", updates: updates, - startTime: int64Ptr(1200), + startTime: new(int64(1200)), endTime: nil, expectedCount: 0, expectedFirst: 0, @@ -226,7 +226,7 @@ func TestFilterUpdates(t *testing.T) { name: "end time before all updates", updates: updates, startTime: nil, - endTime: int64Ptr(100), + endTime: new(int64(100)), expectedCount: 0, expectedFirst: 0, expectedLast: 0, @@ -234,8 +234,8 @@ func TestFilterUpdates(t *testing.T) { { name: "start time after end time but within range", updates: updates, - startTime: int64Ptr(700), - endTime: int64Ptr(500), + startTime: new(int64(700)), + endTime: new(int64(500)), expectedCount: 0, expectedFirst: 0, expectedLast: 0, @@ -243,8 +243,8 @@ func TestFilterUpdates(t *testing.T) { { name: "start and end time match exact values in list", updates: updates, - startTime: int64Ptr(400), - endTime: int64Ptr(800), + startTime: new(int64(400)), + endTime: new(int64(800)), expectedCount: 3, expectedFirst: 800, expectedLast: 400, @@ -289,8 +289,3 @@ func TestFilterUpdates(t *testing.T) { }) } } - -// Helper function to create int64 pointers -// -//go:fix inline -func int64Ptr(v int64) *int64 { return new(v) } diff --git a/libs/apps/runlocal/spec_test.go b/libs/apps/runlocal/spec_test.go index 7425e9ce778..f4218c09e41 100644 --- a/libs/apps/runlocal/spec_test.go +++ b/libs/apps/runlocal/spec_test.go @@ -149,10 +149,3 @@ func TestAppSpecLoadEnvVars(t *testing.T) { }) } } - -// Helper function to create a string pointer -// -//go:fix inline -func stringPtr(s string) *string { - return new(s) -} diff --git a/libs/calladapt/validate.go b/libs/calladapt/validate.go index 80b9023dc56..e33697a79f4 100644 --- a/libs/calladapt/validate.go +++ b/libs/calladapt/validate.go @@ -17,7 +17,6 @@ func EnsureNoExtraMethods(receiver any, ifaceTypes ...reflect.Type) error { } for m := range rt.Methods() { - m := m if _, ok := allowed[m.Name]; !ok { return fmt.Errorf("unexpected method %s on %v; only methods from %v are allowed", m.Name, rt, ifaceTypes) } diff --git a/libs/structs/structaccess/convert_test.go b/libs/structs/structaccess/convert_test.go index 43f5003af12..f4ccbef0f05 100644 --- a/libs/structs/structaccess/convert_test.go +++ b/libs/structs/structaccess/convert_test.go @@ -146,23 +146,3 @@ func TestConvertToString(t *testing.T) { }) } } - -//go:fix inline -func stringPtr(s string) *string { - return new(s) -} - -//go:fix inline -func intPtr(i int) *int { - return new(i) -} - -//go:fix inline -func float64Ptr(f float64) *float64 { - return new(f) -} - -//go:fix inline -func boolPtr(b bool) *bool { - return new(b) -} diff --git a/libs/structs/structaccess/typecheck.go b/libs/structs/structaccess/typecheck.go index f2c91e13e5c..6e7c7d90ea4 100644 --- a/libs/structs/structaccess/typecheck.go +++ b/libs/structs/structaccess/typecheck.go @@ -143,7 +143,6 @@ func FindStructFieldByKeyType(t reflect.Type, key string) (reflect.StructField, // First pass: direct fields for sf := range t.Fields() { - sf := sf if sf.PkgPath != "" { // unexported continue } @@ -163,7 +162,6 @@ func FindStructFieldByKeyType(t reflect.Type, key string) (reflect.StructField, // Second pass: search embedded anonymous structs recursively (flattening semantics) for sf := range t.Fields() { - sf := sf if !sf.Anonymous { continue } diff --git a/libs/structs/structwalk/walktype.go b/libs/structs/structwalk/walktype.go index dc7e958b600..cd4be28c843 100644 --- a/libs/structs/structwalk/walktype.go +++ b/libs/structs/structwalk/walktype.go @@ -105,7 +105,6 @@ func walkTypeValue(path *structpath.PatternNode, typ reflect.Type, field *reflec func walkTypeStruct(path *structpath.PatternNode, st reflect.Type, visit VisitTypeFunc, visitedCount map[reflect.Type]int) { for sf := range st.Fields() { - sf := sf if sf.PkgPath != "" { continue // unexported } From 10c03956f1a738b2da3ac5adafba6176ef1d5d39 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:44:36 +0200 Subject: [PATCH 4/6] Add changelog entry for Go 1.26.3 bump Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index f2e569c609c..b7372336591 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -8,3 +8,6 @@ ### Bundles * The error reported when a direct-only resource (catalogs, external locations, vector search endpoints) is used with the terraform engine now also suggests setting `bundle.engine: direct` in `databricks.yml`, in addition to the `DATABRICKS_BUNDLE_ENGINE` environment variable ([#5295](https://github.com/databricks/cli/pull/5295)). + +### Dependency updates +* Bump Go toolchain to 1.26.3 ([#5302](https://github.com/databricks/cli/pull/5302)). From 9e966bf6c0c2dd82e80e442197bd1a33f415affd Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:13:02 +0200 Subject: [PATCH 5/6] Add lint rule preferring b.Loop() over b.N loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit testing.B.Loop() was added in Go 1.24 with a performance regression that made it prevent inlining; that was fixed in Go 1.26. There's no longer any reason to use 'for i := 0; i < b.N; i++' — b.Loop() handles the loop counter, correct keep-alive semantics, and timer setup automatically. This commit adds the rule only; lint will fail on existing benchmarks. The follow-up commit migrates them. Co-authored-by: Isaac --- libs/gorules/rule_benchmark_loop.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 libs/gorules/rule_benchmark_loop.go diff --git a/libs/gorules/rule_benchmark_loop.go b/libs/gorules/rule_benchmark_loop.go new file mode 100644 index 00000000000..50eac3ab494 --- /dev/null +++ b/libs/gorules/rule_benchmark_loop.go @@ -0,0 +1,15 @@ +package gorules + +import "github.com/quasilyte/go-ruleguard/dsl" + +// UseBenchmarkLoop detects classic benchmark loops over b.N and suggests +// b.Loop() (Go 1.24+; the inlining regression was fixed in 1.26 so there's +// no longer a reason to keep b.N-based loops). +func UseBenchmarkLoop(m dsl.Matcher) { + m.Match( + `for $_ := range $b.N`, + `for range $b.N`, + ). + Where(m["b"].Type.Is("*testing.B")). + Report(`Use 'for $b.Loop()' instead of looping over $b.N (Go 1.24+, performance-correct in 1.26+)`) +} From 99cd8060b4ad5e685b20e8bc0df04ad137121bf5 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 21 May 2026 20:14:11 +0200 Subject: [PATCH 6/6] Migrate b.N benchmark loops to b.Loop() b.Loop() was added in Go 1.24 but had an inlining regression that's fixed in Go 1.26. The new form is strictly better: automatic timer setup, correct keep-alive of the loop body, and inlineable. b.ResetTimer() calls immediately before the loop are no longer needed. Co-authored-by: Isaac --- libs/structs/structdiff/bench_test.go | 4 +--- libs/structs/structtag/jsontag_test.go | 4 ++-- libs/structs/structwalk/walktype_bench_test.go | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libs/structs/structdiff/bench_test.go b/libs/structs/structdiff/bench_test.go index f0406047835..08b386416ef 100644 --- a/libs/structs/structdiff/bench_test.go +++ b/libs/structs/structdiff/bench_test.go @@ -17,15 +17,13 @@ func bench(b *testing.B, job1, job2 string) { total := 0 - b.ResetTimer() - for range b.N { + for b.Loop() { changes, err := GetStructDiff(&x, &y, nil) if err != nil { b.Fatalf("error: %s", err) } total += len(changes) } - b.StopTimer() b.Logf("Total: %d / %d", total, b.N) } diff --git a/libs/structs/structtag/jsontag_test.go b/libs/structs/structtag/jsontag_test.go index b45fd566ea1..810d66851b7 100644 --- a/libs/structs/structtag/jsontag_test.go +++ b/libs/structs/structtag/jsontag_test.go @@ -59,7 +59,7 @@ var benchTags = []JSONTag{ } func BenchmarkJSONTagName(b *testing.B) { - for range b.N { + for b.Loop() { for _, tag := range benchTags { tag.Name() } @@ -67,7 +67,7 @@ func BenchmarkJSONTagName(b *testing.B) { } func BenchmarkJSONTagOmitEmpty(b *testing.B) { - for range b.N { + for b.Loop() { for _, tag := range benchTags { tag.OmitEmpty() } diff --git a/libs/structs/structwalk/walktype_bench_test.go b/libs/structs/structwalk/walktype_bench_test.go index 5f4b05bf986..5947ba5ca47 100644 --- a/libs/structs/structwalk/walktype_bench_test.go +++ b/libs/structs/structwalk/walktype_bench_test.go @@ -21,8 +21,7 @@ func countFields(typ reflect.Type) (int, error) { func benchmarkWalkType(b *testing.B, tt reflect.Type) { total := 0 - b.ResetTimer() - for range b.N { + for b.Loop() { count, err := countFields(tt) if err != nil { b.Fatalf("WalkType failed: %v", err) @@ -30,7 +29,6 @@ func benchmarkWalkType(b *testing.B, tt reflect.Type) { total += count } - b.StopTimer() // Root now correctly includes embedded struct fields, so it has many more fields than JobSettings // (3,487 vs 533) because it contains JobSettings plus other resource types and config fields b.Logf("Counted fields in %s: %d (%d/%d)", tt, total/b.N, total, b.N)