diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index 24f0c2088..8b721ffd1 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -3,6 +3,7 @@ package generic import ( "errors" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary" + "github.com/jfrog/jfrog-client-go/artifactory" "os" buildInfo "github.com/jfrog/build-info-go/entities" @@ -135,7 +136,7 @@ func (uc *UploadCommand) upload() (err error) { var artifactsDetailsReader *content.ContentReader = nil if uc.DetailedSummary() || toCollect { var summary *rtServicesUtils.OperationSummary - summary, err = servicesManager.UploadFilesWithSummary(uploadParamsArray...) + summary, err = servicesManager.UploadFilesWithSummary(artifactory.UploadServiceOptions{}, uploadParamsArray...) if err != nil { errorOccurred = true log.Error(err) @@ -162,7 +163,7 @@ func (uc *UploadCommand) upload() (err error) { } } } else { - successCount, failCount, err = servicesManager.UploadFiles(uploadParamsArray...) + successCount, failCount, err = servicesManager.UploadFiles(artifactory.UploadServiceOptions{}, uploadParamsArray...) if err != nil { errorOccurred = true log.Error(err) diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index 7fa69c2be..8da35cbd5 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -18,6 +18,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-client-go/artifactory/services" specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" clientutils "github.com/jfrog/jfrog-client-go/utils" @@ -344,7 +345,7 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD return err } } - summary, err := servicesManager.UploadFilesWithSummary(up) + summary, err := servicesManager.UploadFilesWithSummary(artifactory.UploadServiceOptions{}, up) if err != nil { return err } @@ -367,7 +368,7 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD } } } else { - _, totalFailed, err = servicesManager.UploadFiles(up) + _, totalFailed, err = servicesManager.UploadFiles(artifactory.UploadServiceOptions{}, up) if err != nil { return err } diff --git a/artifactory/commands/python/twine.go b/artifactory/commands/python/twine.go new file mode 100644 index 000000000..6cb70469b --- /dev/null +++ b/artifactory/commands/python/twine.go @@ -0,0 +1,195 @@ +package python + +import ( + "errors" + "fmt" + "github.com/jfrog/build-info-go/build" + "github.com/jfrog/build-info-go/utils/pythonutils" + buildUtils "github.com/jfrog/jfrog-cli-core/v2/common/build" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/auth" + "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "os" + "os/exec" + "strings" +) + +const ( + _configFileOptionKey = "--config-file" + _repositoryUrlOptionKey = "--repository-url" + _usernameOptionKey = "--username" + _passwordOptionKey = "--password" + _usernamePrefixOptionKey = "-u" + _passwordPrefixOptionKey = "-p" + _repositoryUrlEnvKey = "TWINE_REPOSITORY_URL" + _usernameEnvKey = "TWINE_USERNAME" + _passwordEnvKey = "TWINE_PASSWORD" + // Artifactory endpoint for pypi deployment. + _apiPypi = "api/pypi/" + _twineExecName = "twine" + _uploadCmdName = "upload" +) + +var twineRepoConfigFlags = []string{_configFileOptionKey, _repositoryUrlOptionKey, _usernameOptionKey, _passwordOptionKey, _usernamePrefixOptionKey, _passwordPrefixOptionKey} + +type TwineCommand struct { + serverDetails *config.ServerDetails + commandName string + args []string + targetRepo string + buildConfiguration *buildUtils.BuildConfiguration +} + +func NewTwineCommand(commandName string) *TwineCommand { + return &TwineCommand{ + commandName: commandName, + } +} + +func (tc *TwineCommand) CommandName() string { + return "twine_" + tc.commandName +} + +func (tc *TwineCommand) ServerDetails() (*config.ServerDetails, error) { + return tc.serverDetails, nil +} + +func (tc *TwineCommand) SetServerDetails(serverDetails *config.ServerDetails) *TwineCommand { + tc.serverDetails = serverDetails + return tc +} + +func (tc *TwineCommand) SetTargetRepo(targetRepo string) *TwineCommand { + tc.targetRepo = targetRepo + return tc +} + +func (tc *TwineCommand) SetArgs(args []string) *TwineCommand { + tc.args = args + return tc +} + +func (tc *TwineCommand) Run() (err error) { + // Assert no forbidden flags were provided. + if tc.isRepoConfigFlagProvided() { + return errorutils.CheckErrorf(tc.getRepoConfigFlagProvidedErr()) + } + if err = tc.extractAndFilterArgs(tc.args); err != nil { + return err + } + callbackFunc, err := tc.setAuthEnvVars() + defer func() { + err = errors.Join(err, callbackFunc()) + }() + + collectBuild, err := tc.buildConfiguration.IsCollectBuildInfo() + if err != nil { + return err + } + // If build info is not collected, or this is not an upload command, run the twine command directly. + if !collectBuild || tc.commandName != _uploadCmdName { + return tc.runPlainTwineCommand() + } + return tc.uploadAndCollectBuildInfo() +} + +func (tc *TwineCommand) extractAndFilterArgs(args []string) (err error) { + cleanArgs := append([]string(nil), args...) + cleanArgs, tc.buildConfiguration, err = buildUtils.ExtractBuildDetailsFromArgs(cleanArgs) + if err != nil { + return + } + tc.args = cleanArgs + return +} + +func (tc *TwineCommand) setAuthEnvVars() (callbackFunc func() error, err error) { + oldRepoUrl := os.Getenv(_repositoryUrlEnvKey) + oldUsername := os.Getenv(_usernameEnvKey) + oldPassword := os.Getenv(_passwordEnvKey) + callbackFunc = func() error { + return errors.Join(os.Setenv(_repositoryUrlOptionKey, oldRepoUrl), os.Setenv(_usernameEnvKey, oldUsername), os.Setenv(_passwordEnvKey, oldPassword)) + } + + if err = os.Setenv(_repositoryUrlEnvKey, utils.AddTrailingSlashIfNeeded(tc.serverDetails.ArtifactoryUrl)+_apiPypi+tc.targetRepo); err != nil { + return + } + + username := tc.serverDetails.User + password := tc.serverDetails.Password + // Get credentials from access-token if exists. + if tc.serverDetails.GetAccessToken() != "" { + if username == "" { + username = auth.ExtractUsernameFromAccessToken(tc.serverDetails.GetAccessToken()) + } + password = tc.serverDetails.GetAccessToken() + } + + if err = os.Setenv(_usernameEnvKey, username); err != nil { + return + } + err = os.Setenv(_passwordEnvKey, password) + return +} + +func (tc *TwineCommand) runPlainTwineCommand() error { + log.Debug("Running twine command:", tc.commandName, strings.Join(tc.args, " ")) + args := append([]string{tc.commandName}, tc.args...) + cmd := exec.Command(_twineExecName, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func (tc *TwineCommand) uploadAndCollectBuildInfo() error { + buildInfo, err := buildUtils.PrepareBuildPrerequisites(tc.buildConfiguration) + if err != nil { + return err + } + + defer func() { + if buildInfo != nil && err != nil { + err = errors.Join(err, buildInfo.Clean()) + } + }() + + var pythonModule *build.PythonModule + pythonModule, err = buildInfo.AddPythonModule("", pythonutils.Twine) + if err != nil { + return err + } + if tc.buildConfiguration.GetModule() != "" { + pythonModule.SetName(tc.buildConfiguration.GetModule()) + } + + artifacts, err := pythonModule.TwineUploadWithLogParsing(tc.args) + if err != nil { + return err + } + for i := range artifacts { + artifacts[i].OriginalDeploymentRepo = tc.targetRepo + } + if err = pythonModule.AddArtifacts(artifacts); err != nil { + return err + } + log.Debug(fmt.Sprintf("Command finished successfully. %d artifacs were added to build info.", len(artifacts))) + return nil +} + +func (tc *TwineCommand) isRepoConfigFlagProvided() bool { + for _, arg := range tc.args { + for _, flag := range twineRepoConfigFlags { + if strings.HasPrefix(arg, flag) { + return true + } + } + } + return false +} + +func (tc *TwineCommand) getRepoConfigFlagProvidedErr() string { + return "twine command must not be executed with the following flags: " + coreutils.ListToText(twineRepoConfigFlags) +} diff --git a/artifactory/commands/terraform/terraformpublish.go b/artifactory/commands/terraform/terraformpublish.go index 0a6e854e7..853683d82 100644 --- a/artifactory/commands/terraform/terraformpublish.go +++ b/artifactory/commands/terraform/terraformpublish.go @@ -11,6 +11,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/project" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-client-go/artifactory/services" servicesUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" clientUtils "github.com/jfrog/jfrog-client-go/utils" @@ -232,7 +233,7 @@ func createServiceManagerAndUpload(serverDetails *config.ServerDetails, uploadPa if err != nil { return nil, err } - return serviceManager.UploadFilesWithSummary(*uploadParams) + return serviceManager.UploadFilesWithSummary(artifactory.UploadServiceOptions{}, *uploadParams) } func (tpc *TerraformPublishCommand) walkDirAndUploadTerraformModules(pwd string, producer parallel.Runner, errorsQueue *clientUtils.ErrorsQueue, uploadSummary *[][]*servicesUtils.OperationSummary, produceTaskFunc ProduceTaskFunc) error { diff --git a/artifactory/commands/transferfiles/fulltransfer.go b/artifactory/commands/transferfiles/fulltransfer.go index a60d48e41..eb340ceaf 100644 --- a/artifactory/commands/transferfiles/fulltransfer.go +++ b/artifactory/commands/transferfiles/fulltransfer.go @@ -2,6 +2,7 @@ package transferfiles import ( "fmt" + "github.com/jfrog/gofrog/safeconvert" "path" "time" @@ -250,7 +251,11 @@ func (m *fullTransferPhase) handleFoundFile(pcWrapper *producerConsumerWrapper, return } // Increment the files count in the directory's node in the snapshot manager, to track its progress. - err = node.IncrementFilesCount(uint64(file.Size)) + unsignedFileSize, err := safeconvert.Int64ToUint64(file.Size) + if err != nil { + return fmt.Errorf("failed to convert file size to uint64: %w", err) + } + err = node.IncrementFilesCount(unsignedFileSize) if err != nil { return } diff --git a/artifactory/commands/transferfiles/longpropertycheck_test.go b/artifactory/commands/transferfiles/longpropertycheck_test.go index 560dbd662..f480cfa15 100644 --- a/artifactory/commands/transferfiles/longpropertycheck_test.go +++ b/artifactory/commands/transferfiles/longpropertycheck_test.go @@ -2,6 +2,7 @@ package transferfiles import ( "encoding/json" + "github.com/jfrog/gofrog/safeconvert" "io" "net/http" "net/http/httptest" @@ -56,7 +57,9 @@ func TestProperty(t *testing.T) { } func testProperty(t *testing.T, property Property, isLong bool) { - assert.Len(t, property.Value, int(property.valueLength())) + signedValueLen, err := safeconvert.UintToInt(property.valueLength()) + assert.NoError(t, err) + assert.Len(t, property.Value, signedValueLen) long := isLongProperty(property) assert.Equal(t, isLong, long) } diff --git a/artifactory/commands/transferfiles/manager.go b/artifactory/commands/transferfiles/manager.go index 11e53d804..7a6cb22c1 100644 --- a/artifactory/commands/transferfiles/manager.go +++ b/artifactory/commands/transferfiles/manager.go @@ -416,7 +416,7 @@ func updateProgress(phase *phaseBase, timeEstMng *state.TimeEstimationManager, } if timeEstMng != nil { - timeEstMng.AddChunkStatus(chunk, time.Since(chunkSentTime).Milliseconds()) + return timeEstMng.AddChunkStatus(chunk, time.Since(chunkSentTime).Milliseconds()) } return nil } diff --git a/artifactory/commands/transferfiles/state/statemanager.go b/artifactory/commands/transferfiles/state/statemanager.go index 962d10910..6d72813c3 100644 --- a/artifactory/commands/transferfiles/state/statemanager.go +++ b/artifactory/commands/transferfiles/state/statemanager.go @@ -1,6 +1,8 @@ package state import ( + "fmt" + "github.com/jfrog/gofrog/safeconvert" "path/filepath" "time" @@ -94,7 +96,11 @@ func (ts *TransferStateManager) SetRepoState(repoKey string, totalSizeBytes, tot log.Info("Calculated transferred files from previous run:", transferredFiles) log.Info("Calculated transferred bytes from previous run:", transferredSizeBytes) transferState.CurrentRepo.Phase1Info.TransferredUnits = int64(transferredFiles) - transferState.CurrentRepo.Phase1Info.TransferredSizeBytes = int64(transferredSizeBytes) + signedTransferredSizeBytes, err := safeconvert.Uint64ToInt64(transferredSizeBytes) + if err != nil { + return fmt.Errorf("failed to set transferred size bytes: %w", err) + } + transferState.CurrentRepo.Phase1Info.TransferredSizeBytes = signedTransferredSizeBytes } ts.TransferState = transferState @@ -110,7 +116,11 @@ func (ts *TransferStateManager) SetRepoState(repoKey string, totalSizeBytes, tot transferRunStatus.VisitedFolders = 0 transferRunStatus.OverallTransfer.TransferredUnits += int64(transferredFiles) - transferRunStatus.OverallTransfer.TransferredSizeBytes += int64(transferredSizeBytes) + signedTransferredSizeBytes, err := safeconvert.Uint64ToInt64(transferredSizeBytes) + if err != nil { + return fmt.Errorf("failed to set transferred size bytes: %w", err) + } + transferRunStatus.OverallTransfer.TransferredSizeBytes += signedTransferredSizeBytes return nil }) } diff --git a/artifactory/commands/transferfiles/state/statemanager_test.go b/artifactory/commands/transferfiles/state/statemanager_test.go index 2db3f9760..3d50dc385 100644 --- a/artifactory/commands/transferfiles/state/statemanager_test.go +++ b/artifactory/commands/transferfiles/state/statemanager_test.go @@ -1,6 +1,7 @@ package state import ( + "github.com/jfrog/gofrog/safeconvert" "sync" "testing" "time" @@ -340,9 +341,15 @@ func TestStateConcurrency(t *testing.T) { assert.Equal(t, 1000, int(stateManager.CurrentRepo.Phase3Info.TransferredSizeBytes)) assert.Equal(t, 1000, int(stateManager.CurrentRepo.Phase3Info.TransferredUnits)) assert.Equal(t, 1000, int(stateManager.OverallTransfer.TransferredSizeBytes)) - assert.Equal(t, 1000, int(stateManager.VisitedFolders)) - assert.Equal(t, 1000, int(stateManager.DelayedFiles)) - assert.Equal(t, 1000, int(stateManager.TransferFailures)) + signedVisitedFolders, err := safeconvert.Uint64ToInt(stateManager.VisitedFolders) + assert.NoError(t, err) + assert.Equal(t, 1000, signedVisitedFolders) + signedDelayedFiles, err := safeconvert.Uint64ToInt(stateManager.DelayedFiles) + assert.NoError(t, err) + assert.Equal(t, 1000, signedDelayedFiles) + signedTransferFailures, err := safeconvert.Uint64ToInt(stateManager.TransferFailures) + assert.NoError(t, err) + assert.Equal(t, 1000, signedTransferFailures) // Concurrently decrement delayed artifacts and transfer failures for i := 0; i < 500; i++ { @@ -356,6 +363,10 @@ func TestStateConcurrency(t *testing.T) { wg.Wait() // Assert 500 in delayed artifacts and transfer failures - assert.Equal(t, 500, int(stateManager.DelayedFiles)) - assert.Equal(t, 500, int(stateManager.TransferFailures)) + signedDelayedFiles, err = safeconvert.Uint64ToInt(stateManager.DelayedFiles) + assert.NoError(t, err) + assert.Equal(t, 500, signedDelayedFiles) + signedTransferFailures, err = safeconvert.Uint64ToInt(stateManager.TransferFailures) + assert.NoError(t, err) + assert.Equal(t, 500, signedTransferFailures) } diff --git a/artifactory/commands/transferfiles/state/timeestimation.go b/artifactory/commands/transferfiles/state/timeestimation.go index 943d5c6b7..9e17c01d6 100644 --- a/artifactory/commands/transferfiles/state/timeestimation.go +++ b/artifactory/commands/transferfiles/state/timeestimation.go @@ -1,7 +1,9 @@ package state import ( + "errors" "fmt" + "github.com/jfrog/gofrog/safeconvert" "time" "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/api" @@ -39,19 +41,23 @@ type TimeEstimationManager struct { stateManager *TransferStateManager } -func (tem *TimeEstimationManager) AddChunkStatus(chunkStatus api.ChunkStatus, durationMillis int64) { +func (tem *TimeEstimationManager) AddChunkStatus(chunkStatus api.ChunkStatus, durationMillis int64) error { if durationMillis == 0 { - return + return nil } - tem.addDataChunkStatus(chunkStatus, durationMillis) + return tem.addDataChunkStatus(chunkStatus, durationMillis) } -func (tem *TimeEstimationManager) addDataChunkStatus(chunkStatus api.ChunkStatus, durationMillis int64) { +func (tem *TimeEstimationManager) addDataChunkStatus(chunkStatus api.ChunkStatus, durationMillis int64) error { var chunkSizeBytes int64 for _, file := range chunkStatus.Files { if file.Status != api.Fail { - tem.CurrentTotalTransferredBytes += uint64(file.SizeBytes) + unsignedSizeBytes, err := safeconvert.Int64ToUint64(file.SizeBytes) + if err != nil { + return fmt.Errorf("failed to calculate the estimated remaining time: %w", err) + } + tem.CurrentTotalTransferredBytes += unsignedSizeBytes } if (file.Status == api.Success || file.Status == api.SkippedLargeProps) && !file.ChecksumDeployed { chunkSizeBytes += file.SizeBytes @@ -60,13 +66,13 @@ func (tem *TimeEstimationManager) addDataChunkStatus(chunkStatus api.ChunkStatus // If no files were uploaded regularly (with no errors and not checksum-deployed), don't use this chunk for the time estimation calculation. if chunkSizeBytes == 0 { - return + return nil } workingThreads, err := tem.stateManager.GetWorkingThreads() if err != nil { log.Error("Couldn't calculate time estimation:", err.Error()) - return + return err } speed := calculateChunkSpeed(workingThreads, chunkSizeBytes, durationMillis) tem.LastSpeeds = append(tem.LastSpeeds, speed) @@ -79,10 +85,11 @@ func (tem *TimeEstimationManager) addDataChunkStatus(chunkStatus api.ChunkStatus } if len(tem.LastSpeeds) == 0 { tem.SpeedsAverage = 0 - return + return err } // Calculate speed in bytes/ms tem.SpeedsAverage = tem.LastSpeedsSum / float64(len(tem.LastSpeeds)) + return nil } func calculateChunkSpeed(workingThreads int, chunkSizeSum, chunkDuration int64) float64 { @@ -108,31 +115,39 @@ func (tem *TimeEstimationManager) GetSpeedString() string { // 1. 5 minutes not passed since the beginning of the transfer // 2. No files transferred // 3. The transfer speed is less than 1 byte per second -func (tem *TimeEstimationManager) GetEstimatedRemainingTimeString() string { - remainingTimeSec := tem.getEstimatedRemainingSeconds() - if remainingTimeSec == 0 { - return "Not available yet" +func (tem *TimeEstimationManager) GetEstimatedRemainingTimeString() (string, error) { + remainingTimeSec, err := tem.getEstimatedRemainingSeconds() + if remainingTimeSec == 0 || err != nil { + return "Not available yet", err } - return SecondsToLiteralTime(int64(remainingTimeSec), "About ") + signedRemainingTimeSec, err := safeconvert.Uint64ToInt64(remainingTimeSec) + if err != nil { + return "", errors.New("failed to calculate the estimated remaining time: " + err.Error()) + } + return SecondsToLiteralTime(signedRemainingTimeSec, "About "), nil } -func (tem *TimeEstimationManager) getEstimatedRemainingSeconds() uint64 { +func (tem *TimeEstimationManager) getEstimatedRemainingSeconds() (uint64, error) { if tem.CurrentTotalTransferredBytes == 0 { // No files transferred - return 0 + return 0, nil } duration := time.Since(tem.stateManager.startTimestamp) if duration < minTransferTimeToShowEstimation { // 5 minutes not yet passed - return 0 + return 0, nil } transferredBytesInSeconds := tem.CurrentTotalTransferredBytes / uint64(duration.Seconds()) if transferredBytesInSeconds == 0 { // Less than 1 byte per second - return 0 + return 0, nil } remainingBytes := tem.stateManager.OverallTransfer.TotalSizeBytes - tem.stateManager.OverallTransfer.TransferredSizeBytes - return uint64(remainingBytes) / transferredBytesInSeconds + unsignedRemainingBytes, err := safeconvert.Int64ToUint64(remainingBytes) + if err != nil { + return 0, fmt.Errorf("failed to calculate the estimated remaining time: %w", err) + } + return unsignedRemainingBytes / transferredBytesInSeconds, nil } diff --git a/artifactory/commands/transferfiles/state/timeestimation_test.go b/artifactory/commands/transferfiles/state/timeestimation_test.go index 78c1688eb..b9b23d8fc 100644 --- a/artifactory/commands/transferfiles/state/timeestimation_test.go +++ b/artifactory/commands/transferfiles/state/timeestimation_test.go @@ -1,6 +1,7 @@ package state import ( + "github.com/jfrog/gofrog/safeconvert" "testing" "time" @@ -51,7 +52,9 @@ func TestGetSpeed(t *testing.T) { addChunkStatus(t, timeEstMng, chunkStatus1, 3, true, 10*milliSecsInSecond) assert.Equal(t, 7.5, timeEstMng.getSpeed()) assert.Equal(t, "7.500 MB/s", timeEstMng.GetSpeedString()) - assert.NotZero(t, timeEstMng.getEstimatedRemainingSeconds()) + estimatedRemainingSeconds, err := timeEstMng.getEstimatedRemainingSeconds() + assert.NoError(t, err) + assert.NotZero(t, estimatedRemainingSeconds) // Chunk 2: the upload of one of the files failed and the files are not included in the repository's total size (includedInTotalSize == false) chunkStatus2 := api.ChunkStatus{ @@ -63,20 +66,27 @@ func TestGetSpeed(t *testing.T) { addChunkStatus(t, timeEstMng, chunkStatus2, 2, false, 5*milliSecsInSecond) assert.Equal(t, float64(8), timeEstMng.getSpeed()) assert.Equal(t, "8.000 MB/s", timeEstMng.GetSpeedString()) - assert.NotZero(t, timeEstMng.getEstimatedRemainingSeconds()) + estimatedRemainingSeconds, err = timeEstMng.getEstimatedRemainingSeconds() + assert.NoError(t, err) + assert.NotZero(t, estimatedRemainingSeconds) } func TestGetEstimatedRemainingSeconds(t *testing.T) { timeEstMng, cleanUp := initTimeEstimationDataTest(t) defer cleanUp() - timeEstMng.CurrentTotalTransferredBytes = uint64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) + unsignedTotalSizeBytes, err := safeconvert.Int64ToUint64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) + assert.NoError(t, err) + timeEstMng.CurrentTotalTransferredBytes = unsignedTotalSizeBytes timeEstMng.stateManager.OverallTransfer.TransferredSizeBytes = timeEstMng.stateManager.OverallTransfer.TotalSizeBytes - assert.Zero(t, timeEstMng.getEstimatedRemainingSeconds()) + estimatedRemainingSeconds, err := timeEstMng.getEstimatedRemainingSeconds() + assert.NoError(t, err) + assert.Zero(t, estimatedRemainingSeconds) - timeEstMng.CurrentTotalTransferredBytes = uint64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) / 2 + timeEstMng.CurrentTotalTransferredBytes = unsignedTotalSizeBytes / 2 timeEstMng.stateManager.OverallTransfer.TransferredSizeBytes = timeEstMng.stateManager.OverallTransfer.TotalSizeBytes / 2 - calculatedEstimatedSeconds := timeEstMng.getEstimatedRemainingSeconds() + calculatedEstimatedSeconds, err := timeEstMng.getEstimatedRemainingSeconds() + assert.NoError(t, err) assert.NotZero(t, calculatedEstimatedSeconds) } @@ -90,7 +100,9 @@ func TestGetEstimatedRemainingTimeStringNotAvailableYet(t *testing.T) { createFileUploadStatusResponse(repo1Key, 8*rtServicesUtils.SizeMiB, true, api.Success), }, } - assert.Equal(t, "Not available yet", timeEstMng.GetEstimatedRemainingTimeString()) + estimatedRemainingTime, err := timeEstMng.GetEstimatedRemainingTimeString() + assert.NoError(t, err) + assert.Equal(t, "Not available yet", estimatedRemainingTime) addChunkStatus(t, timeEstMng, chunkStatus1, 3, true, 10*milliSecsInSecond) assert.Equal(t, "Not available yet", timeEstMng.GetSpeedString()) } @@ -101,17 +113,23 @@ func TestGetEstimatedRemainingTimeString(t *testing.T) { // Test "Not available yet" by setting the TotalTransferredBytes to 0 timeEstMng.CurrentTotalTransferredBytes = 0 - assert.Equal(t, "Not available yet", timeEstMng.GetEstimatedRemainingTimeString()) + estimatedRemainingTime, err := timeEstMng.GetEstimatedRemainingTimeString() + assert.NoError(t, err) + assert.Equal(t, "Not available yet", estimatedRemainingTime) // Test "About 1 minute" by setting the transferred bytes to 80% timeEstMng.CurrentTotalTransferredBytes = uint64(float64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) * 0.8) timeEstMng.stateManager.OverallTransfer.TransferredSizeBytes = int64(float64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) * 0.8) - assert.Equal(t, "About 1 minute", timeEstMng.GetEstimatedRemainingTimeString()) + estimatedRemainingTime, err = timeEstMng.GetEstimatedRemainingTimeString() + assert.NoError(t, err) + assert.Equal(t, "About 1 minute", estimatedRemainingTime) // Test "Less than a minute" by setting the transferred bytes to 90% timeEstMng.CurrentTotalTransferredBytes = uint64(float64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) * 0.9) timeEstMng.stateManager.OverallTransfer.TransferredSizeBytes = int64(float64(timeEstMng.stateManager.OverallTransfer.TotalSizeBytes) * 0.9) - assert.Equal(t, "Less than a minute", timeEstMng.GetEstimatedRemainingTimeString()) + estimatedRemainingTime, err = timeEstMng.GetEstimatedRemainingTimeString() + assert.NoError(t, err) + assert.Equal(t, "Less than a minute", estimatedRemainingTime) } func newDefaultTimeEstimationManager(t *testing.T, buildInfoRepos bool) *TimeEstimationManager { @@ -220,7 +238,7 @@ func addChunkStatus(t *testing.T, timeEstMng *TimeEstimationManager, chunkStatus assert.NoError(t, err) } assert.NoError(t, timeEstMng.stateManager.SetWorkingThreads(workingThreads)) - timeEstMng.AddChunkStatus(chunkStatus, durationMillis) + assert.NoError(t, timeEstMng.AddChunkStatus(chunkStatus, durationMillis)) } func assertTransferredSizes(t *testing.T, stateManager *TransferStateManager, repo1expected, repo2expected int64) { diff --git a/artifactory/commands/transferfiles/status.go b/artifactory/commands/transferfiles/status.go index 7bbd3dcd7..a6d51bb2d 100644 --- a/artifactory/commands/transferfiles/status.go +++ b/artifactory/commands/transferfiles/status.go @@ -44,7 +44,9 @@ func ShowStatus() error { return nil } - addOverallStatus(stateManager, &output, stateManager.GetRunningTimeString()) + if err = addOverallStatus(stateManager, &output, stateManager.GetRunningTimeString()); err != nil { + return err + } if stateManager.CurrentRepoKey != "" { transferState, exists, err := state.LoadTransferState(stateManager.CurrentRepoKey, false) if err != nil { @@ -71,7 +73,7 @@ func isStopping() (bool, error) { return fileutils.IsFileExists(filepath.Join(transferDir, StopFileName), false) } -func addOverallStatus(stateManager *state.TransferStateManager, output *strings.Builder, runningTime string) { +func addOverallStatus(stateManager *state.TransferStateManager, output *strings.Builder, runningTime string) error { addTitle(output, "Overall Transfer Status") addString(output, coreutils.RemoveEmojisIfNonSupportedTerminal("๐ŸŸข"), "Status", "Running", 3) addString(output, "๐Ÿƒ", "Running for", runningTime, 3) @@ -79,12 +81,17 @@ func addOverallStatus(stateManager *state.TransferStateManager, output *strings. addString(output, "๐Ÿ“ฆ", "Repositories", fmt.Sprintf("%d / %d", stateManager.TotalRepositories.TransferredUnits, stateManager.TotalRepositories.TotalUnits)+calcPercentageInt64(stateManager.TotalRepositories.TransferredUnits, stateManager.TotalRepositories.TotalUnits), 2) addString(output, "๐Ÿงต", "Working threads", strconv.Itoa(stateManager.WorkingThreads), 2) addString(output, "โšก", "Transfer speed", stateManager.GetSpeedString(), 2) - addString(output, "โŒ›", "Estimated time remaining", stateManager.GetEstimatedRemainingTimeString(), 1) + estimatedRemainingTime, err := stateManager.GetEstimatedRemainingTimeString() + if err != nil { + return err + } + addString(output, "โŒ›", "Estimated time remaining", estimatedRemainingTime, 1) failureTxt := strconv.FormatUint(stateManager.TransferFailures, 10) if stateManager.TransferFailures > 0 { failureTxt += " (" + progressbar.RetryFailureContentNote + ")" } addString(output, "โŒ", "Transfer failures", failureTxt, 2) + return nil } func calcPercentageInt64(transferred, total int64) string { diff --git a/artifactory/commands/transferfiles/transfer.go b/artifactory/commands/transferfiles/transfer.go index ba872ffd2..a08d04562 100644 --- a/artifactory/commands/transferfiles/transfer.go +++ b/artifactory/commands/transferfiles/transfer.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/jfrog/gofrog/safeconvert" "os" "os/signal" "path/filepath" @@ -240,13 +241,21 @@ func (tdc *TransferFilesCommand) initStateManager(allSourceLocalRepos, sourceBui if e != nil { return e } - tdc.stateManager.TransferFailures = uint64(numberInitialErrors) + unsignedNumberInitialErrors, err := safeconvert.IntToUint(numberInitialErrors) + if err != nil { + return fmt.Errorf("failed to convert number of initial errors to uint: %w", err) + } + tdc.stateManager.TransferFailures = uint64(unsignedNumberInitialErrors) numberInitialDelays, e := getDelayedFilesCount(allSourceLocalRepos) if e != nil { return e } - tdc.stateManager.DelayedFiles = uint64(numberInitialDelays) + unsignedNumberInitialDelay, err := safeconvert.IntToUint(numberInitialDelays) + if err != nil { + return err + } + tdc.stateManager.DelayedFiles = uint64(unsignedNumberInitialDelay) } else { tdc.stateManager.VisitedFolders = 0 tdc.stateManager.TransferFailures = 0 diff --git a/artifactory/commands/utils/precheckrunner/checkrunner.go b/artifactory/commands/utils/precheckrunner/checkrunner.go index 62b435453..eb87da5a5 100644 --- a/artifactory/commands/utils/precheckrunner/checkrunner.go +++ b/artifactory/commands/utils/precheckrunner/checkrunner.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "github.com/gookit/color" + "github.com/jfrog/gofrog/safeconvert" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" corelog "github.com/jfrog/jfrog-cli-core/v2/utils/log" "github.com/jfrog/jfrog-cli-core/v2/utils/progressbar" @@ -170,7 +171,15 @@ func (pcr *PreCheckRunner) cleanup() (err error) { } } // Notify on final status of the run - if pcr.status.failures == 0 && len(pcr.checks) == int(pcr.status.successes+pcr.status.failures) && err == nil { + signedFailures, err := safeconvert.UintToInt(pcr.status.failures) + if err != nil { + return fmt.Errorf("failed to convert failures to int: %w", err) + } + signedSuccesses, err := safeconvert.UintToInt(pcr.status.successes) + if err != nil { + return fmt.Errorf("failed to convert successes to int: %w", err) + } + if pcr.status.failures == 0 && len(pcr.checks) == signedFailures+signedSuccesses && err == nil { log.Info(coreutils.PrintTitle(fmt.Sprintf("All the checks passed ๐Ÿธ (elapsed time %s).", time.Since(pcr.status.startTime)))) } else { log.Error(coreutils.PrintTitle(fmt.Sprintf("%d/%d checks passed (elapsed time %s), check the log for more information.", diff --git a/artifactory/commands/utils/precheckrunner/checkrunner_test.go b/artifactory/commands/utils/precheckrunner/checkrunner_test.go index 476f3eea6..abc794ef6 100644 --- a/artifactory/commands/utils/precheckrunner/checkrunner_test.go +++ b/artifactory/commands/utils/precheckrunner/checkrunner_test.go @@ -3,6 +3,7 @@ package precheckrunner import ( "context" "fmt" + "github.com/jfrog/gofrog/safeconvert" "github.com/stretchr/testify/assert" "testing" ) @@ -19,8 +20,8 @@ func TestChecks(t *testing.T) { func TestRunChecks(t *testing.T) { // Init expectedErr := fmt.Errorf("CHECK_ERROR") - nSuccess := 3 - nFail := 2 + nSuccess := uint(3) + nFail := uint(2) runner := NewPreChecksRunner() successCheck := NewCheck("success", func(args RunArguments) (bool, error) { return true, nil @@ -34,15 +35,15 @@ func TestRunChecks(t *testing.T) { // Empty runAndAssert(t, 0, 0, nil, runner) // With checks - for i := 0; i < nSuccess; i++ { + for i := uint(0); i < nSuccess; i++ { runner.AddCheck(successCheck) } - runAndAssert(t, uint(nSuccess), 0, nil, runner) + runAndAssert(t, nSuccess, 0, nil, runner) // With failed checks - for i := 0; i < nFail; i++ { + for i := uint(0); i < nFail; i++ { runner.AddCheck(failCheck) } - runAndAssert(t, uint(nSuccess), uint(nFail), nil, runner) + runAndAssert(t, nSuccess, nFail, nil, runner) // With check that has error runner.AddCheck(errCheck) runAndAssert(t, 0, 0, expectedErr, runner) @@ -56,6 +57,10 @@ func runAndAssert(t *testing.T, expectedSuccess, expectedFail uint, shouldHaveEr assert.NoError(t, err) assert.Equal(t, expectedSuccess, runner.status.successes) assert.Equal(t, expectedFail, runner.status.failures) - assert.Len(t, runner.checks, int(expectedSuccess+expectedFail)) + signedExpectedSuccess, err := safeconvert.UintToInt(expectedSuccess) + assert.NoError(t, err) + signedExpectedFail, err := safeconvert.UintToInt(expectedFail) + assert.NoError(t, err) + assert.Len(t, runner.checks, signedExpectedSuccess+signedExpectedFail) } } diff --git a/artifactory/commands/utils/precheckrunner/remoteurlchecker.go b/artifactory/commands/utils/precheckrunner/remoteurlchecker.go index 048201254..9a389b539 100644 --- a/artifactory/commands/utils/precheckrunner/remoteurlchecker.go +++ b/artifactory/commands/utils/precheckrunner/remoteurlchecker.go @@ -3,6 +3,7 @@ package precheckrunner import ( "encoding/json" "fmt" + "github.com/jfrog/gofrog/safeconvert" "net/http" "time" @@ -165,7 +166,11 @@ func (rrc *RemoteRepositoryCheck) startCheckRemoteRepositories(rtDetails *httput if args.ProgressMng == nil { return nil, nil } - return args.ProgressMng.NewTasksProgressBar(int64(response.TotalRepositories), "Remote repositories"), nil + signedTotalRepositories, err := safeconvert.UintToInt(response.TotalRepositories) + if err != nil { + return nil, fmt.Errorf("failed to convert total repositories count to int: %w", err) + } + return args.ProgressMng.NewTasksProgressBar(int64(signedTotalRepositories), "Remote repositories"), nil } func (rrc *RemoteRepositoryCheck) waitForRemoteReposCheckCompletion(rtDetails *httputils.HttpClientDetails, artifactoryUrl string, progressBar *progressbar.TasksProgressBar) (*[]inaccessibleRepository, error) { @@ -207,7 +212,11 @@ func (rrc *RemoteRepositoryCheck) createImportPollingAction(rtDetails *httputils return true, nil, err } if progressBar != nil { - delta := int64(response.CheckedRepositories) - progressBar.GetBar().Current() + signedCheckedRepositories, err := safeconvert.UintToInt(response.CheckedRepositories) + if err != nil { + return true, nil, fmt.Errorf("failed to convert checked repositories count to int: %w", err) + } + delta := int64(signedCheckedRepositories) - progressBar.GetBar().Current() progressBar.GetBar().IncrInt64(delta) } } diff --git a/artifactory/utils/commandsummary/buildinfosummary.go b/artifactory/utils/commandsummary/buildinfosummary.go index 2a0fe9e08..9861c723c 100644 --- a/artifactory/utils/commandsummary/buildinfosummary.go +++ b/artifactory/utils/commandsummary/buildinfosummary.go @@ -31,6 +31,7 @@ var ( buildInfo.Generic: true, buildInfo.Terraform: true, buildInfo.Docker: true, + buildInfo.Python: true, } ) diff --git a/common/commands/config.go b/common/commands/config.go index 0870614a1..d771fc865 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -338,16 +338,11 @@ func (cc *ConfigCommand) getConfigurationFromUser() (err error) { return } - var clientCertChecked bool if cc.details.Password == "" && cc.details.AccessToken == "" { - clientCertChecked, err = cc.promptForCredentials(disallowUsingSavedPassword) - if err != nil { + if err = cc.promptForCredentials(disallowUsingSavedPassword); err != nil { return err } } - if !clientCertChecked { - cc.checkClientCertForReverseProxy() - } return } @@ -410,7 +405,7 @@ func (cc *ConfigCommand) promptUrls(disallowUsingSavedPassword *bool) error { }) } -func (cc *ConfigCommand) promptForCredentials(disallowUsingSavedPassword bool) (clientCertChecked bool, err error) { +func (cc *ConfigCommand) promptForCredentials(disallowUsingSavedPassword bool) (err error) { var authMethod AuthenticationMethod authMethod, err = cc.promptAuthMethods() if err != nil { @@ -418,19 +413,17 @@ func (cc *ConfigCommand) promptForCredentials(disallowUsingSavedPassword bool) ( } switch authMethod { case BasicAuth: - return false, ioutils.ReadCredentialsFromConsole(cc.details, cc.defaultDetails, disallowUsingSavedPassword) + return ioutils.ReadCredentialsFromConsole(cc.details, cc.defaultDetails, disallowUsingSavedPassword) case AccessToken: - return false, cc.promptForAccessToken() + return cc.promptForAccessToken() case MTLS: cc.checkCertificateForMTLS() log.Warn("Please notice that authentication using client certificates (mTLS) is not supported by commands which integrate with package managers.") - return true, nil + return nil case WebLogin: - // Web login sends requests, so certificates must be obtained first if they are required. - cc.checkClientCertForReverseProxy() - return true, cc.handleWebLogin() + return cc.handleWebLogin() default: - return false, errorutils.CheckErrorf("unexpected authentication method") + return errorutils.CheckErrorf("unexpected authentication method") } } @@ -465,15 +458,6 @@ func (cc *ConfigCommand) readClientCertInfoFromConsole() { } } -func (cc *ConfigCommand) checkClientCertForReverseProxy() { - if cc.details.ClientCertPath != "" && cc.details.ClientCertKeyPath != "" || cc.useWebLogin { - return - } - if coreutils.AskYesNo("Is the Artifactory reverse proxy configured to accept a client certificate?", false) { - cc.readClientCertInfoFromConsole() - } -} - func readAccessTokenFromConsole(details *config.ServerDetails) error { token, err := ioutils.ScanPasswordFromConsole("JFrog access token:") if err == nil { diff --git a/common/commands/configfile.go b/common/commands/configfile.go index 60e8a35ee..450e71895 100644 --- a/common/commands/configfile.go +++ b/common/commands/configfile.go @@ -153,7 +153,9 @@ func handleInteractiveConfigCreation(configFile *ConfigFile, confType project.Pr switch confType { case project.Go: return configFile.setDeployerResolver() - case project.Pip, project.Pipenv, project.Poetry: + case project.Pip, project.Pipenv: + return configFile.setDeployerResolver() + case project.Poetry: return configFile.setResolver(false) case project.Yarn: return configFile.setResolver(false) diff --git a/go.mod b/go.mod index 3f6aa6d9c..c24648de9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jfrog/jfrog-cli-core/v2 -go 1.22.3 +go 1.22.7 require github.com/c-bata/go-prompt v0.2.5 // Should not be updated to 0.2.6 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372) @@ -12,9 +12,9 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.9 - github.com/jfrog/build-info-go v1.9.35 - github.com/jfrog/gofrog v1.7.5 - github.com/jfrog/jfrog-client-go v1.46.1 + github.com/jfrog/build-info-go v1.10.0 + github.com/jfrog/gofrog v1.7.6 + github.com/jfrog/jfrog-client-go v1.47.0 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -22,11 +22,11 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.15 github.com/vbauerster/mpb/v8 v8.8.3 - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 - golang.org/x/mod v0.20.0 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + golang.org/x/mod v0.21.0 golang.org/x/sync v0.8.0 - golang.org/x/term v0.23.0 - golang.org/x/text v0.17.0 + golang.org/x/term v0.24.0 + golang.org/x/text v0.18.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -88,16 +88,16 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/tools v0.25.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240827071113-de462dc3df22 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240918081224-1c584cc334c7 -// replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240819133117-c3f52700927d +// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240918150101-ad5b10435a12 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index c48003efc..3cd9c2bb6 100644 --- a/go.sum +++ b/go.sum @@ -92,12 +92,12 @@ github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+ github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= -github.com/jfrog/build-info-go v1.9.35 h1:P53Ckbuin0GYrq0LWMY0GZSptJcQwiUyW6lqTbXKdcc= -github.com/jfrog/build-info-go v1.9.35/go.mod h1:6mdtqjREK76bHNODXakqKR/+ksJ9dvfLS7H57BZtnLY= -github.com/jfrog/gofrog v1.7.5 h1:dFgtEDefJdlq9cqTRoe09RLxS5Bxbe1Ev5+E6SmZHcg= -github.com/jfrog/gofrog v1.7.5/go.mod h1:jyGiCgiqSSR7k86hcUSu67XVvmvkkgWTmPsH25wI298= -github.com/jfrog/jfrog-client-go v1.46.1 h1:ExqOF8ClOG9LO3vbm6jTIwQHHhprbu8lxB2RrM6mMI0= -github.com/jfrog/jfrog-client-go v1.46.1/go.mod h1:UCu2JNBfMp9rypEmCL84DCooG79xWIHVadZQR3Ab+BQ= +github.com/jfrog/build-info-go v1.10.0 h1:jSxmN58mH0LaP+v1IQadplwJPRILLgI3xieBTXTCSos= +github.com/jfrog/build-info-go v1.10.0/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= +github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s= +github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4= +github.com/jfrog/jfrog-client-go v1.47.0 h1:OBMB6TxqziBByjuk6hm0BM30pQwOb3XzjZKf/cmwCeM= +github.com/jfrog/jfrog-client-go v1.47.0/go.mod h1:UxzL9Q4pDoM+HQjSuQiGNakyoJNuxqPSs35/amBJvdY= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -229,14 +229,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= -golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -244,8 +244,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -277,15 +277,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -293,14 +293,14 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/utils/config/encryption.go b/utils/config/encryption.go index eb4db4445..2c78afb7d 100644 --- a/utils/config/encryption.go +++ b/utils/config/encryption.go @@ -193,7 +193,9 @@ func decrypt(encryptedSecret string, key string) (string, error) { return "", errorutils.CheckErrorf(decryptErrorPrefix + "unexpected cipher text size") } + //#nosec G407 nonce, cipherText := cipherText[:nonceSize], cipherText[nonceSize:] + //#nosec G407 plaintext, err := gcm.Open(nil, nonce, cipherText, nil) if err != nil { return "", errorutils.CheckError(err) diff --git a/utils/coreutils/cmdutils.go b/utils/coreutils/cmdutils.go index 4ef9fe34f..d57783c75 100644 --- a/utils/coreutils/cmdutils.go +++ b/utils/coreutils/cmdutils.go @@ -138,7 +138,7 @@ func FindFlagFirstMatch(flags, args []string) (flagIndex, flagValueIndex int, fl } func ExtractServerIdFromCommand(args []string) (cleanArgs []string, serverId string, err error) { - return extractStringOptionFromArgs(args, "server-id") + return ExtractStringOptionFromArgs(args, "server-id") } func ExtractThreadsFromArgs(args []string, defaultValue int) (cleanArgs []string, threads int, err error) { @@ -181,12 +181,12 @@ func ExtractLicensesFromArgs(args []string) (cleanArgs []string, licenses bool, // Used by docker scan (Xray) func ExtractRepoPathFromArgs(args []string) (cleanArgs []string, repoPath string, err error) { - return extractStringOptionFromArgs(args, "repo-path") + return ExtractStringOptionFromArgs(args, "repo-path") } // Used by docker scan (Xray) func ExtractWatchesFromArgs(args []string) (cleanArgs []string, watches string, err error) { - return extractStringOptionFromArgs(args, "watches") + return ExtractStringOptionFromArgs(args, "watches") } func ExtractDetailedSummaryFromArgs(args []string) (cleanArgs []string, detailedSummary bool, err error) { @@ -198,14 +198,14 @@ func ExtractXrayScanFromArgs(args []string) (cleanArgs []string, xrayScan bool, } func ExtractXrayOutputFormatFromArgs(args []string) (cleanArgs []string, format string, err error) { - return extractStringOptionFromArgs(args, "format") + return ExtractStringOptionFromArgs(args, "format") } func ExtractTagFromArgs(args []string) (cleanArgs []string, tag string, err error) { - return extractStringOptionFromArgs(args, "tag") + return ExtractStringOptionFromArgs(args, "tag") } -func extractStringOptionFromArgs(args []string, optionName string) (cleanArgs []string, value string, err error) { +func ExtractStringOptionFromArgs(args []string, optionName string) (cleanArgs []string, value string, err error) { cleanArgs = append([]string(nil), args...) flagIndex, valIndex, value, err := FindFlag("--"+optionName, cleanArgs) diff --git a/utils/coreutils/profiler.go b/utils/coreutils/profiler.go index 94626e6a4..b4986e529 100644 --- a/utils/coreutils/profiler.go +++ b/utils/coreutils/profiler.go @@ -3,6 +3,7 @@ package coreutils import ( "errors" "fmt" + "github.com/jfrog/gofrog/safeconvert" "os" "runtime/pprof" "time" @@ -70,7 +71,11 @@ func (p *Profiler) threadDumpToFile() (outputFilePath string, err error) { err = errors.Join(err, errorutils.CheckError(outputFile.Close())) }() - for i := 0; i < int(p.repetitions); i++ { + signedRepetitions, err := safeconvert.UintToInt(p.repetitions) + if err != nil { + return "", fmt.Errorf("failed to convert repetitions to int: %w", err) + } + for i := 0; i < signedRepetitions; i++ { fmt.Fprintf(outputFile, "========== Thread dump #%d ==========\n", i) prof := pprof.Lookup("goroutine") if err = errorutils.CheckError(prof.WriteTo(outputFile, 1)); err != nil { diff --git a/utils/coreutils/tableutils.go b/utils/coreutils/tableutils.go index cfa3a3eb1..ebccc161a 100644 --- a/utils/coreutils/tableutils.go +++ b/utils/coreutils/tableutils.go @@ -153,7 +153,7 @@ func PrepareTable(rows interface{}, emptyTableMessage string, printExtended bool rowsSliceValue := reflect.ValueOf(rows) if rowsSliceValue.Len() == 0 && emptyTableMessage != "" { - PrintMessage(emptyTableMessage) + PrintMessageInsideFrame(emptyTableMessage, "") return nil, nil } @@ -367,15 +367,27 @@ type embeddedTableCell struct { // PrintMessage prints message in a frame (which is actually a table with a single table). // For example: +// // โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” // โ”‚ An example of a message in a nice frame โ”‚ // โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -func PrintMessage(message string) { +// With a margin left of 4 spaces: +// +// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +// โ”‚ An example of a message in a nice frame โ”‚ +// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +func PrintMessageInsideFrame(message, marginLeft string) { tableWriter := table.NewWriter() tableWriter.SetOutputMirror(os.Stdout) if log.IsStdOutTerminal() { tableWriter.SetStyle(table.StyleLight) } + + // Set margin left for the whole frame (for example, " "). + tableWriter.Style().Box.Left = marginLeft + tableWriter.Style().Box.Left + tableWriter.Style().Box.TopLeft = marginLeft + tableWriter.Style().Box.TopLeft + tableWriter.Style().Box.BottomLeft = marginLeft + tableWriter.Style().Box.BottomLeft + // Remove emojis from non-supported terminals message = RemoveEmojisIfNonSupportedTerminal(message) tableWriter.AppendRow(table.Row{message}) diff --git a/utils/progressbar/progressbarmng.go b/utils/progressbar/progressbarmng.go index 7f43b168c..ea59dfa13 100644 --- a/utils/progressbar/progressbarmng.go +++ b/utils/progressbar/progressbarmng.go @@ -320,7 +320,8 @@ func barStyle(isGeneral bool) mpb.BarStyleComposer { filler = "๐ŸŸฉ" } } - return mpb.BarStyle().Lbound("[").Filler(filler).Tip(filler).Padding(padding).Refiller("").Rbound("]") + // Should look like this at the beginning: [๐ŸŸฆ ] and then [๐ŸŸฆ๐ŸŸฆ ] and so on. (Or for windows: [โ—..........] and then [โ—โ—.........]) + return mpb.BarStyle().Lbound("[" + filler).Filler(filler).Tip(filler).Padding(padding).Refiller("").Rbound("]") } // The ShouldInitProgressBar func is used to determine whether the progress bar should be displayed. diff --git a/utils/progressbar/transferprogressbarmanager.go b/utils/progressbar/transferprogressbarmanager.go index 0bb9ed76a..db42b2ad8 100644 --- a/utils/progressbar/transferprogressbarmanager.go +++ b/utils/progressbar/transferprogressbarmanager.go @@ -1,6 +1,8 @@ package progressbar import ( + "fmt" + "github.com/jfrog/gofrog/safeconvert" "sync" "time" @@ -306,7 +308,11 @@ func (tpm *TransferProgressMng) NewVisitedFoldersBar() *TasksProgressBar { if tpm.ignoreState { return 0, nil } - return int(tpm.stateMng.VisitedFolders), nil + signedVisitedFolders, err := safeconvert.Uint64ToInt(tpm.stateMng.VisitedFolders) + if err != nil { + return 0, fmt.Errorf("failed to convert visited folders to int: %w", err) + } + return signedVisitedFolders, nil } return tpm.barMng.newCounterProgressBar(getVals, tpm.transferLabels.VisitedFolders, nil) } @@ -316,7 +322,11 @@ func (tpm *TransferProgressMng) NewDelayedBar() *TasksProgressBar { if tpm.ignoreState { return 0, nil } - return int(tpm.stateMng.DelayedFiles), nil + signedDelayedFiles, err := safeconvert.Uint64ToInt(tpm.stateMng.DelayedFiles) + if err != nil { + return 0, fmt.Errorf("failed to convert delayed files to int: %w", err) + } + return signedDelayedFiles, nil } counterDescription := func() string { return DelayedFilesContentNote } return tpm.barMng.newCounterProgressBar(getVals, tpm.transferLabels.DelayedFiles, tpm.createCounterDescription(counterDescription)) @@ -327,7 +337,11 @@ func (tpm *TransferProgressMng) NewErrorBar() *TasksProgressBar { if tpm.ignoreState { return 0, nil } - return int(tpm.stateMng.TransferFailures), nil + signedTransferFailures, err := safeconvert.Uint64ToInt(tpm.stateMng.TransferFailures) + if err != nil { + return 0, fmt.Errorf("failed to convert transfer failures to int: %w", err) + } + return signedTransferFailures, nil } counterDescription := func() string { if tpm.ignoreState || tpm.stateMng.TransferFailures == 0 { diff --git a/utils/reposnapshot/snapshotmanager_test.go b/utils/reposnapshot/snapshotmanager_test.go index 4b372d640..454a00925 100644 --- a/utils/reposnapshot/snapshotmanager_test.go +++ b/utils/reposnapshot/snapshotmanager_test.go @@ -2,6 +2,7 @@ package reposnapshot import ( "encoding/json" + "github.com/jfrog/gofrog/safeconvert" "os" "path" "path/filepath" @@ -190,7 +191,9 @@ func createNodeBase(t *testing.T, name string, filesCount int, parent *Node) *No node := CreateNewNode(name, parent) node.NodeStatus = DoneExploring for i := 0; i < filesCount; i++ { - assert.NoError(t, node.IncrementFilesCount(uint64(i))) + unsignedFileIndex, err := safeconvert.IntToUint(i) + assert.NoError(t, err) + assert.NoError(t, node.IncrementFilesCount(uint64(unsignedFileIndex))) } return node }