From 160cd26a8ee359cea4160e0b51e54743a9ee657e Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Sun, 22 Sep 2024 12:14:17 +0300 Subject: [PATCH] Remove redundant log Signed-off-by: Michael Sverdlov --- utils/cliutils/persistence.go | 117 +++++++++++++++++++++++++++++ utils/cliutils/persistence_test.go | 81 ++++++++++++++++++++ utils/cliutils/utils.go | 16 ++-- utils/cliutils/utils_test.go | 11 ++- 4 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 utils/cliutils/persistence.go create mode 100644 utils/cliutils/persistence_test.go diff --git a/utils/cliutils/persistence.go b/utils/cliutils/persistence.go new file mode 100644 index 000000000..b231bab25 --- /dev/null +++ b/utils/cliutils/persistence.go @@ -0,0 +1,117 @@ +package cliutils + +import ( + "encoding/json" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "os" + "path/filepath" + gosync "sync" +) + +const persistenceFileName = "persistence.json" + +// PersistenceInfo represents the fields we are persisting +type PersistenceInfo struct { + LatestVersionCheckTime *int64 `json:"latestVersionCheckTime,omitempty"` + AiTermsVersion *int `json:"aiTermsVersion,omitempty"` +} + +var ( + persistenceFilePath string + fileLock gosync.Mutex +) + +// init initializes the persistence file path once, and stores it for future use +func init() { + homeDir, err := coreutils.GetJfrogHomeDir() + if err != nil { + panic("Failed to get JFrog home directory: " + err.Error()) + } + persistenceFilePath = filepath.Join(homeDir, persistenceFileName) +} + +// SetLatestVersionCheckTime updates the latest version check time in the persistence file +func SetLatestVersionCheckTime(timestamp int64) error { + info, err := getPersistenceInfo() + if err != nil { + return err + } + + info.LatestVersionCheckTime = ×tamp + return setPersistenceInfo(info) +} + +// GetLatestVersionCheckTime retrieves the latest version check time from the persistence file +func GetLatestVersionCheckTime() (*int64, error) { + info, err := getPersistenceInfo() + if err != nil { + return nil, err + } + + return info.LatestVersionCheckTime, nil +} + +// SetAiTermsVersion updates the AI terms version in the persistence file +func SetAiTermsVersion(version int) error { + info, err := getPersistenceInfo() + if err != nil { + return err + } + + info.AiTermsVersion = &version + return setPersistenceInfo(info) +} + +// GetAiTermsVersion retrieves the AI terms version from the persistence file +func GetAiTermsVersion() (*int, error) { + info, err := getPersistenceInfo() + if err != nil { + return nil, err + } + + return info.AiTermsVersion, nil +} + +// getPersistenceInfo reads the persistence file, creates it if it doesn't exist, and returns the persisted info +func getPersistenceInfo() (*PersistenceInfo, error) { + if _, err := os.Stat(persistenceFilePath); os.IsNotExist(err) { + // Create an empty persistence file if it doesn't exist + pFile := &PersistenceInfo{} + if err = setPersistenceInfo(pFile); err != nil { + return nil, errorutils.CheckErrorf("failed while attempting to initialize persistence file" + err.Error()) + } + return pFile, nil + } + + fileLock.Lock() + defer fileLock.Unlock() + data, err := os.ReadFile(persistenceFilePath) + if err != nil { + return nil, errorutils.CheckErrorf("failed while attempting to read persistence file" + err.Error()) + } + + var info PersistenceInfo + if err = json.Unmarshal(data, &info); err != nil { + return nil, errorutils.CheckErrorf("failed while attempting to parse persistence file" + err.Error()) + } + + return &info, nil +} + +// setPersistenceInfo writes the given info to the persistence file +func setPersistenceInfo(info *PersistenceInfo) error { + fileLock.Lock() + defer fileLock.Unlock() + + data, err := json.MarshalIndent(info, "", " ") + if err != nil { + return errorutils.CheckErrorf("failed while attempting to create persistence file" + err.Error()) + } + + err = os.WriteFile(persistenceFilePath, data, 0644) + if err != nil { + return errorutils.CheckErrorf("failed while attempting to write persistence file" + err.Error()) + } + return nil +} diff --git a/utils/cliutils/persistence_test.go b/utils/cliutils/persistence_test.go new file mode 100644 index 000000000..942f69b0c --- /dev/null +++ b/utils/cliutils/persistence_test.go @@ -0,0 +1,81 @@ +package cliutils + +import ( + "os" + "path/filepath" + "testing" + "time" +) + +// TestSetAndGetLatestVersionCheckTime tests setting and getting the LatestVersionCheckTime +func TestSetAndGetLatestVersionCheckTime(t *testing.T) { + // Setup temporary directory + persistenceFilePath = filepath.Join(t.TempDir(), persistenceFileName) + + // Set the timestamp + timestamp := time.Now().UnixMilli() + err := SetLatestVersionCheckTime(timestamp) + if err != nil { + t.Fatalf("Failed to set LatestVersionCheckTime: %v", err) + } + + // Get the timestamp + storedTimestamp, err := GetLatestVersionCheckTime() + if err != nil { + t.Fatalf("Failed to get LatestVersionCheckTime: %v", err) + } + + // Assert equality + if *storedTimestamp != timestamp { + t.Fatalf("Expected %d, got %d", timestamp, *storedTimestamp) + } +} + +// TestSetAndGetAiTermsVersion tests setting and getting the AiTermsVersion +func TestSetAndGetAiTermsVersion(t *testing.T) { + // Setup temporary directory + persistenceFilePath = filepath.Join(t.TempDir(), persistenceFileName) + + // Set the AI terms version + version := 42 + err := SetAiTermsVersion(version) + if err != nil { + t.Fatalf("Failed to set AiTermsVersion: %v", err) + } + + // Get the AI terms version + storedVersion, err := GetAiTermsVersion() + if err != nil { + t.Fatalf("Failed to get AiTermsVersion: %v", err) + } + + // Assert equality + if *storedVersion != version { + t.Fatalf("Expected %d, got %d", version, *storedVersion) + } +} + +// TestPersistenceFileCreation tests if the persistence file is created when it doesn't exist +func TestPersistenceFileCreation(t *testing.T) { + // Setup temporary directory + persistenceFilePath = filepath.Join(t.TempDir(), persistenceFileName) + + // Ensure the persistence file doesn't exist + _, err := os.Stat(persistenceFilePath) + if !os.IsNotExist(err) { + t.Fatalf("Expected file to not exist, but it does: %v", err) + } + + // Trigger file creation by setting version check time + timestamp := time.Now().UnixMilli() + err = SetLatestVersionCheckTime(timestamp) + if err != nil { + t.Fatalf("Failed to set LatestVersionCheckTime: %v", err) + } + + // Verify the persistence file was created + _, err = os.Stat(persistenceFilePath) + if os.IsNotExist(err) { + t.Fatalf("Expected file to exist, but it does not: %v", err) + } +} diff --git a/utils/cliutils/utils.go b/utils/cliutils/utils.go index f8bc4f592..257323841 100644 --- a/utils/cliutils/utils.go +++ b/utils/cliutils/utils.go @@ -8,7 +8,6 @@ import ( "io" "net/http" "os" - "path" "path/filepath" "strconv" "strings" @@ -699,21 +698,20 @@ func shouldCheckLatestCliVersion() (shouldCheck bool, err error) { if strings.ToLower(os.Getenv(JfrogCliAvoidNewVersionWarning)) == "true" { return } - homeDir, err := coreutils.GetJfrogHomeDir() + latestVersionCheckTime, err := GetLatestVersionCheckTime() if err != nil { return } - indicatorFile := path.Join(homeDir, "Latest_Cli_Version_Check_Indicator") - fileInfo, err := os.Stat(indicatorFile) - if err != nil && !os.IsNotExist(err) { - err = fmt.Errorf("couldn't get indicator file %s info: %s", indicatorFile, err.Error()) + timeNow := time.Now().UnixMilli() + if latestVersionCheckTime != nil && + (timeNow-*latestVersionCheckTime) < LatestCliVersionCheckInterval.Milliseconds() { + // Timestamp file exists and updated less than 6 hours ago, therefor no need to check version again return } - if err == nil && (time.Now().UnixMilli()-fileInfo.ModTime().UnixMilli()) < LatestCliVersionCheckInterval.Milliseconds() { - // Timestamp file exists and updated less than 6 hours ago, therefor no need to check version again + if err = SetLatestVersionCheckTime(timeNow); err != nil { return } - return true, os.WriteFile(indicatorFile, []byte{}, 0666) + return true, nil } func getLatestCliVersionFromGithubAPI() (githubVersionInfo githubResponse, err error) { diff --git a/utils/cliutils/utils_test.go b/utils/cliutils/utils_test.go index 0d257bb5f..937efdd17 100644 --- a/utils/cliutils/utils_test.go +++ b/utils/cliutils/utils_test.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strings" "testing" + "time" coretests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" "github.com/jfrog/jfrog-cli/utils/tests" @@ -114,9 +115,7 @@ func testCheckNewCliVersionAvailable(t *testing.T, version string, shouldWarn bo } func TestShouldCheckLatestCliVersion(t *testing.T) { - // Create temp JFROG_HOME - cleanUpTempEnv := configtests.CreateTempEnv(t, false) - defer cleanUpTempEnv() + persistenceFilePath = filepath.Join(t.TempDir(), persistenceFileName) // Validate that avoiding the version check using an environment variable is working setEnvCallback := clientTestUtils.SetEnvWithCallbackAndAssert(t, JfrogCliAvoidNewVersionWarning, "true") @@ -134,4 +133,10 @@ func TestShouldCheckLatestCliVersion(t *testing.T) { shouldCheck, err = shouldCheckLatestCliVersion() assert.NoError(t, err) assert.False(t, shouldCheck) + + assert.NoError(t, SetLatestVersionCheckTime(time.Now().UnixMilli()-LatestCliVersionCheckInterval.Milliseconds())) + // Third run, more than 6 hours between runs, so should return true + shouldCheck, err = shouldCheckLatestCliVersion() + assert.NoError(t, err) + assert.True(t, shouldCheck) }