diff --git a/experimental/ssh/internal/vscode/settings.go b/experimental/ssh/internal/vscode/settings.go index dd3e7842b5..0877a57bff 100644 --- a/experimental/ssh/internal/vscode/settings.go +++ b/experimental/ssh/internal/vscode/settings.go @@ -214,29 +214,33 @@ func validateSettings(v hujson.Value, connectionName string) *missingSettings { func settingsMessage(connectionName string, missing *missingSettings) string { var lines []string if missing.portRange { - lines = append(lines, fmt.Sprintf(" \"%s\": {\"%s\": \"%s\"}", serverPickPortsKey, connectionName, portRange)) + lines = append(lines, fmt.Sprintf(" \"%s\": {\"%s\": \"%s\"}", serverPickPortsKey, connectionName, portRange)) } if missing.platform { - lines = append(lines, fmt.Sprintf(" \"%s\": {\"%s\": \"%s\"}", remotePlatformKey, connectionName, remotePlatform)) + lines = append(lines, fmt.Sprintf(" \"%s\": {\"%s\": \"%s\"}", remotePlatformKey, connectionName, remotePlatform)) } if missing.listenOnSocket { - lines = append(lines, fmt.Sprintf(" \"%s\": true // Global setting that affects all remote ssh connections", listenOnSocketKey)) + lines = append(lines, fmt.Sprintf(" \"%s\": true // Global setting", listenOnSocketKey)) } if len(missing.extensions) > 0 { quoted := make([]string, len(missing.extensions)) for i, ext := range missing.extensions { quoted[i] = fmt.Sprintf("\"%s\"", ext) } - lines = append(lines, fmt.Sprintf(" \"%s\": [%s] // Global setting that affects all remote ssh connections", defaultExtensionsKey, strings.Join(quoted, ", "))) + lines = append(lines, fmt.Sprintf(" \"%s\": [%s] // Global setting", defaultExtensionsKey, strings.Join(quoted, ", "))) } - return strings.Join(lines, "\n") + return " {\n" + strings.Join(lines, ",\n") + "\n }" } func promptUserForUpdate(ctx context.Context, ide, connectionName string, missing *missingSettings) (bool, error) { question := fmt.Sprintf( - "The following settings will be applied to %s for '%s':\n%s\nApply these settings?", + "The following settings will be applied to %s for '%s':\n\n%s\n\nApply these settings?", getIDE(ide).Name, connectionName, settingsMessage(connectionName, missing)) - return cmdio.AskYesOrNo(ctx, question) + ans, err := cmdio.Ask(ctx, question+" [Y/n]", "y") + if err != nil { + return false, err + } + return strings.ToLower(ans) == "y", nil } func handleMissingFile(ctx context.Context, ide, connectionName, settingsPath string) error { diff --git a/libs/gorules/rule_time_now_in_testserver.go b/libs/gorules/rule_time_now_in_testserver.go new file mode 100644 index 0000000000..ac20fb8e42 --- /dev/null +++ b/libs/gorules/rule_time_now_in_testserver.go @@ -0,0 +1,14 @@ +package gorules + +import "github.com/quasilyte/go-ruleguard/dsl" + +// NoTimeNowUnixMilliInTestServer forbids direct time.Now().UnixMilli() calls in libs/testserver. +// Use nowMilli() instead to guarantee unique, strictly increasing timestamps. +// Integer millisecond timestamps get indexed replacements in test output (e.g. [UNIX_TIME_MILLIS][0]) +// and collisions between resources cause flaky tests. +func NoTimeNowUnixMilliInTestServer(m dsl.Matcher) { + m.Match(`time.Now().UnixMilli()`). + Where(m.File().PkgPath.Matches(`.*/libs/testserver`) && + !m.File().Name.Matches(`fake_workspace\.go$`)). + Report(`Use nowMilli() instead of time.Now().UnixMilli() in testserver to ensure unique timestamps`) +} diff --git a/libs/testserver/catalogs.go b/libs/testserver/catalogs.go index bd9598d600..859721ee73 100644 --- a/libs/testserver/catalogs.go +++ b/libs/testserver/catalogs.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "time" "github.com/databricks/databricks-sdk-go/service/catalog" ) @@ -29,14 +28,14 @@ func (s *FakeWorkspace) CatalogsCreate(req Request) Response { Options: createRequest.Options, Properties: createRequest.Properties, FullName: createRequest.Name, - CreatedAt: time.Now().UnixMilli(), + CreatedAt: nowMilli(), CreatedBy: s.CurrentUser().UserName, - UpdatedAt: time.Now().UnixMilli(), UpdatedBy: s.CurrentUser().UserName, MetastoreId: nextUUID(), Owner: s.CurrentUser().UserName, CatalogType: catalog.CatalogTypeManagedCatalog, } + catalogInfo.UpdatedAt = catalogInfo.CreatedAt s.Catalogs[createRequest.Name] = catalogInfo return Response{ @@ -79,7 +78,7 @@ func (s *FakeWorkspace) CatalogsUpdate(req Request, name string) Response { name = updateRequest.NewName } - existing.UpdatedAt = time.Now().UnixMilli() + existing.UpdatedAt = nowMilli() existing.UpdatedBy = s.CurrentUser().UserName s.Catalogs[name] = existing diff --git a/libs/testserver/external_locations.go b/libs/testserver/external_locations.go index 0606ad76e5..b0000deb2a 100644 --- a/libs/testserver/external_locations.go +++ b/libs/testserver/external_locations.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "time" "github.com/databricks/databricks-sdk-go/service/catalog" ) @@ -37,13 +36,13 @@ func (s *FakeWorkspace) ExternalLocationsCreate(req Request) Response { Fallback: createRequest.Fallback, EncryptionDetails: createRequest.EncryptionDetails, FileEventQueue: createRequest.FileEventQueue, - CreatedAt: time.Now().UnixMilli(), + CreatedAt: nowMilli(), CreatedBy: s.CurrentUser().UserName, - UpdatedAt: time.Now().UnixMilli(), UpdatedBy: s.CurrentUser().UserName, MetastoreId: nextUUID(), Owner: s.CurrentUser().UserName, } + locationInfo.UpdatedAt = locationInfo.CreatedAt s.ExternalLocations[createRequest.Name] = locationInfo return Response{ @@ -95,7 +94,7 @@ func (s *FakeWorkspace) ExternalLocationsUpdate(req Request, name string) Respon name = updateRequest.NewName } - existing.UpdatedAt = time.Now().UnixMilli() + existing.UpdatedAt = nowMilli() existing.UpdatedBy = s.CurrentUser().UserName s.ExternalLocations[name] = existing diff --git a/libs/testserver/pipelines.go b/libs/testserver/pipelines.go index 763a38be84..a6ce25b022 100644 --- a/libs/testserver/pipelines.go +++ b/libs/testserver/pipelines.go @@ -3,7 +3,6 @@ package testserver import ( "encoding/json" "fmt" - "time" "github.com/databricks/databricks-sdk-go/service/pipelines" ) @@ -41,7 +40,7 @@ func (s *FakeWorkspace) PipelineCreate(req Request) Response { pipelineId := nextUUID() r.PipelineId = pipelineId r.CreatorUserName = "tester@databricks.com" - r.LastModified = time.Now().UnixMilli() + r.LastModified = nowMilli() r.Name = r.Spec.Name r.RunAsUserName = "tester@databricks.com" r.State = "IDLE" diff --git a/libs/testserver/registered_models.go b/libs/testserver/registered_models.go index 74815ae7a8..e3723a95e9 100644 --- a/libs/testserver/registered_models.go +++ b/libs/testserver/registered_models.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "time" "github.com/databricks/databricks-sdk-go/service/catalog" ) @@ -30,13 +29,13 @@ func (s *FakeWorkspace) RegisteredModelsCreate(req Request) Response { SchemaName: createRequest.SchemaName, StorageLocation: createRequest.StorageLocation, FullName: fullName, - CreatedAt: time.Now().UnixMilli(), + CreatedAt: nowMilli(), CreatedBy: s.CurrentUser().UserName, - UpdatedAt: time.Now().UnixMilli(), UpdatedBy: s.CurrentUser().UserName, MetastoreId: nextUUID(), Owner: s.CurrentUser().UserName, } + registeredModel.UpdatedAt = registeredModel.CreatedAt s.RegisteredModels[fullName] = registeredModel return Response{ @@ -78,7 +77,7 @@ func (s *FakeWorkspace) RegisteredModelsUpdate(req Request, fullName string) Res fullName = existing.CatalogName + "." + existing.SchemaName + "." + updateRequest.NewName } - existing.UpdatedAt = time.Now().UnixMilli() + existing.UpdatedAt = nowMilli() s.RegisteredModels[fullName] = existing return Response{ Body: existing,