diff --git a/artifactory/commands/transfer/settings.go b/artifactory/commands/transfer/settings.go index b034412de..3a4959000 100644 --- a/artifactory/commands/transfer/settings.go +++ b/artifactory/commands/transfer/settings.go @@ -35,7 +35,7 @@ func (tst *TransferSettingsCommand) Run() error { ioutils.ScanFromConsole("Set the maximum number of working threads", &threadsNumberInput, currThreadsNumber) threadsNumber, err := strconv.Atoi(threadsNumberInput) if err != nil || threadsNumber < 1 || threadsNumber > MaxThreadsLimit { - return errorutils.CheckErrorf("the value must be a number between 1 and " + strconv.Itoa(MaxThreadsLimit)) + return errorutils.CheckErrorf("the value must be a number between 1 and %s", strconv.Itoa(MaxThreadsLimit)) } conf := &utils.TransferSettings{ThreadsNumber: threadsNumber} err = utils.SaveTransferSettings(conf) diff --git a/artifactory/commands/transferconfig/transferconfig.go b/artifactory/commands/transferconfig/transferconfig.go index 42af06f40..d71577b8f 100644 --- a/artifactory/commands/transferconfig/transferconfig.go +++ b/artifactory/commands/transferconfig/transferconfig.go @@ -291,7 +291,7 @@ func (tcc *TransferConfigCommand) verifyConfigImportPlugin() error { // Unexpected status received: 403 if the user is not admin, 500+ if there is a server error messageFormat := fmt.Sprintf("Target server response: %s.\n%s", resp.Status, body) - return errorutils.CheckErrorf(messageFormat) + return errors.New(messageFormat) } // Creates the Pre-checks runner for the config import command diff --git a/artifactory/commands/transferfiles/utils.go b/artifactory/commands/transferfiles/utils.go index 4db4c0587..1aa353fb4 100644 --- a/artifactory/commands/transferfiles/utils.go +++ b/artifactory/commands/transferfiles/utils.go @@ -417,7 +417,7 @@ func uploadChunkWhenPossibleHandler(pcWrapper *producerConsumerWrapper, phaseBas shouldStop := uploadChunkWhenPossible(pcWrapper, phaseBase, chunk, uploadTokensChan, errorsChannelMng) if shouldStop { // The specific error that triggered the stop is already in the errors channel - return errorutils.CheckErrorf(logMsgPrefix + "stopped") + return errorutils.CheckErrorf("%sstopped", logMsgPrefix) } return nil } diff --git a/artifactory/commands/utils/templateutils.go b/artifactory/commands/utils/templateutils.go index f88f5854c..3e291167b 100644 --- a/artifactory/commands/utils/templateutils.go +++ b/artifactory/commands/utils/templateutils.go @@ -70,10 +70,10 @@ func ConvertTemplateToMaps(templateUserCommand TemplateUserCommand) (interface{} func ValidateMapEntry(key string, value interface{}, writersMap map[string]ioutils.AnswerWriter) error { if _, ok := writersMap[key]; !ok { - return errorutils.CheckErrorf("template syntax error: unknown key: \"" + key + "\".") + return errorutils.CheckErrorf("template syntax error: unknown key: \"%s\".", key) } if _, ok := value.(string); !ok { - return errorutils.CheckErrorf("template syntax error: the value for the key: \"" + key + "\" is not a string type.") + return errorutils.CheckErrorf("template syntax error: the value for the key: \"%s\" is not a string type.", key) } return nil } diff --git a/artifactory/commands/utils/transfer.go b/artifactory/commands/utils/transfer.go index ae9117b25..5d2083feb 100644 --- a/artifactory/commands/utils/transfer.go +++ b/artifactory/commands/utils/transfer.go @@ -2,15 +2,17 @@ package utils import ( "encoding/json" + "errors" "fmt" + "net/http" + "time" + "github.com/gocarina/gocsv" ioutils "github.com/jfrog/gofrog/io" logutils "github.com/jfrog/jfrog-cli-core/v2/utils/log" "github.com/jfrog/jfrog-client-go/http/jfroghttpclient" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/httputils" - "net/http" - "time" ) type ServerType string @@ -40,7 +42,7 @@ func GetTransferPluginVersion(client *jfroghttpclient.JfrogHttpClient, url, plug return "", errorutils.CheckErrorf("%sIt looks like the %s plugin is not installed on the %s server.", messageFormat, pluginName, serverType) } else { // 403 if the user is not admin, 500+ if there is a server error - return "", errorutils.CheckErrorf(messageFormat) + return "", errors.New(messageFormat) } } diff --git a/artifactory/utils/commandsummary/evidence_url.go b/artifactory/utils/commandsummary/evidence_url.go new file mode 100644 index 000000000..50ca88bca --- /dev/null +++ b/artifactory/utils/commandsummary/evidence_url.go @@ -0,0 +1,63 @@ +package commandsummary + +import ( + "fmt" + "net/url" +) + +const ( + releaseBundleEvidenceFormat = "%sui/artifactory/lifecycle?range=Any+Time&bundleName=%s&repositoryKey=%s&releaseBundleVersion=%s&activeVersionTab=Evidence+Graph" + buildEvidenceFormat = "%sui/builds/%s/%s/%s/Evidence/%s?buildRepo=%s" + artifactEvidenceFormat = "%sui/repos/tree/Evidence/%s?clearFilter=true" +) + +func GenerateEvidenceUrlByType(data EvidenceSummaryData, section summarySection) (string, error) { + switch data.SubjectType { + // Currently, it is not possible to generate a link to the evidence tab for packages in the Artifactory UI. + // The link will point to the lead artifact of the package instead. + // This logic will be updated once UI support is available + case SubjectTypePackage, SubjectTypeArtifact: + return generateArtifactEvidenceUrl(data.Subject, section) + case SubjectTypeReleaseBundle: + return generateReleaseBundleEvidenceUrl(data, section) + case SubjectTypeBuild: + return generateBuildEvidenceUrl(data, section) + default: + return generateArtifactEvidenceUrl(data.Subject, section) + } +} + +func generateArtifactEvidenceUrl(pathInRt string, section summarySection) (string, error) { + urlStr := fmt.Sprintf(artifactEvidenceFormat, StaticMarkdownConfig.GetPlatformUrl(), pathInRt) + return addGitHubTrackingToUrl(urlStr, section) +} + +func generateReleaseBundleEvidenceUrl(data EvidenceSummaryData, section summarySection) (string, error) { + if data.ReleaseBundleName == "" || data.ReleaseBundleVersion == "" { + return generateArtifactEvidenceUrl(data.Subject, section) + } + + urlStr := fmt.Sprintf(releaseBundleEvidenceFormat, + StaticMarkdownConfig.GetPlatformUrl(), + data.ReleaseBundleName, + data.RepoKey, + data.ReleaseBundleVersion) + + return addGitHubTrackingToUrl(urlStr, section) +} + +func generateBuildEvidenceUrl(data EvidenceSummaryData, section summarySection) (string, error) { + if data.BuildName == "" || data.BuildNumber == "" || data.BuildTimestamp == "" { + return generateArtifactEvidenceUrl(data.Subject, section) + } + + urlStr := fmt.Sprintf(buildEvidenceFormat, + StaticMarkdownConfig.GetPlatformUrl(), + url.QueryEscape(data.BuildName), + data.BuildNumber, + data.BuildTimestamp, + url.QueryEscape(data.BuildName), + data.RepoKey) + + return addGitHubTrackingToUrl(urlStr, section) +} diff --git a/artifactory/utils/commandsummary/evidence_url_test.go b/artifactory/utils/commandsummary/evidence_url_test.go new file mode 100644 index 000000000..352096985 --- /dev/null +++ b/artifactory/utils/commandsummary/evidence_url_test.go @@ -0,0 +1,141 @@ +package commandsummary + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateEvidenceUrlByType(t *testing.T) { + // Set up test environment + originalWorkflow := os.Getenv(workflowEnvKey) + err := os.Setenv(workflowEnvKey, "JFrog CLI Core Tests") + if err != nil { + assert.FailNow(t, "Failed to set environment variable", err) + } + defer func() { + if originalWorkflow != "" { + err = os.Setenv(workflowEnvKey, originalWorkflow) + if err != nil { + assert.Fail(t, "Failed to restore workflow environment variable", err) + return + } + } else { + os.Unsetenv(workflowEnvKey) + } + }() + + // Configure static markdown config for tests + StaticMarkdownConfig.setPlatformUrl("https://myplatform.com/") + StaticMarkdownConfig.setPlatformMajorVersion(7) + + tests := []struct { + name string + data EvidenceSummaryData + expectedURL string + expectError bool + }{ + { + name: "Package evidence URL", + data: EvidenceSummaryData{ + Subject: "repo/path/package.jar", + SubjectType: SubjectTypePackage, + }, + expectedURL: "https://myplatform.com/ui/repos/tree/Evidence/repo/path/package.jar?clearFilter=true&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Artifact evidence URL", + data: EvidenceSummaryData{ + Subject: "repo/path/artifact.txt", + SubjectType: SubjectTypeArtifact, + }, + expectedURL: "https://myplatform.com/ui/repos/tree/Evidence/repo/path/artifact.txt?clearFilter=true&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Release bundle evidence URL", + data: EvidenceSummaryData{ + Subject: "release-bundles-v2/my-bundle/1.0.0/release-bundle.json.evd", + SubjectType: SubjectTypeReleaseBundle, + ReleaseBundleName: "my-bundle", + ReleaseBundleVersion: "1.0.0", + RepoKey: "release-bundles-v2", + }, + expectedURL: "", // Will be checked with custom assertion + }, + { + name: "Build evidence URL", + data: EvidenceSummaryData{ + Subject: "artifactory-build-info/my-build/123/1234567890.json", + SubjectType: SubjectTypeBuild, + BuildName: "my-build", + BuildNumber: "123", + BuildTimestamp: "1234567890", + RepoKey: "artifactory-build-info", + }, + expectedURL: "https://myplatform.com/ui/builds/my-build/123/1234567890/Evidence/my-build?buildRepo=artifactory-build-info&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Build with special characters in name", + data: EvidenceSummaryData{ + Subject: "artifactory-build-info/my build with spaces/123/1234567890.json", + SubjectType: SubjectTypeBuild, + BuildName: "my build with spaces", + BuildNumber: "123", + BuildTimestamp: "1234567890", + RepoKey: "artifactory-build-info", + }, + expectedURL: "https://myplatform.com/ui/builds/my+build+with+spaces/123/1234567890/Evidence/my+build+with+spaces?buildRepo=artifactory-build-info&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Invalid release bundle falls back to artifact URL", + data: EvidenceSummaryData{ + Subject: "invalid/path", + SubjectType: SubjectTypeReleaseBundle, + }, + expectedURL: "https://myplatform.com/ui/repos/tree/Evidence/invalid/path?clearFilter=true&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Invalid build falls back to artifact URL", + data: EvidenceSummaryData{ + Subject: "invalid/build/path", + SubjectType: SubjectTypeBuild, + }, + expectedURL: "https://myplatform.com/ui/repos/tree/Evidence/invalid/build/path?clearFilter=true&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + { + name: "Default type uses artifact URL", + data: EvidenceSummaryData{ + Subject: "some/path/file.txt", + SubjectType: "", // Empty type should default to artifact + }, + expectedURL: "https://myplatform.com/ui/repos/tree/Evidence/some/path/file.txt?clearFilter=true&gh_job_id=JFrog+CLI+Core+Tests&gh_section=evidence&m=3&s=1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + url, err := GenerateEvidenceUrlByType(tt.data, evidenceSection) + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + if tt.expectedURL != "" { + assert.Equal(t, tt.expectedURL, url) + } else if tt.name == "Release bundle evidence URL" { + // Special handling for release bundle URL due to parameter ordering + assert.Contains(t, url, "https://myplatform.com/ui/artifactory/lifecycle?") + assert.Contains(t, url, "bundleName=my-bundle") + assert.Contains(t, url, "repositoryKey=release-bundles-v2") + assert.Contains(t, url, "releaseBundleVersion=1.0.0") + assert.Contains(t, url, "activeVersionTab=Evidence+Graph") + assert.Contains(t, url, "gh_job_id=JFrog+CLI+Core+Tests") + assert.Contains(t, url, "gh_section=evidence") + assert.Contains(t, url, "m=3") + assert.Contains(t, url, "s=1") + assert.Contains(t, url, "range=Any+Time") + } + } + }) + } +} diff --git a/artifactory/utils/commandsummary/evidencesummary.go b/artifactory/utils/commandsummary/evidencesummary.go new file mode 100644 index 000000000..5e87d5cf7 --- /dev/null +++ b/artifactory/utils/commandsummary/evidencesummary.go @@ -0,0 +1,151 @@ +package commandsummary + +import ( + "fmt" + "github.com/jfrog/jfrog-client-go/utils/log" + "strings" + "time" +) + +const evidenceHeaderSize = 3 + +type EvidenceSummaryData struct { + Subject string `json:"subject"` + SubjectSha256 string `json:"subjectSha256"` + PredicateType string `json:"predicateType"` + PredicateSlug string `json:"predicateSlug"` + Verified bool `json:"verified"` + DisplayName string `json:"displayName,omitempty"` + SubjectType SubjectType `json:"subjectType"` + BuildName string `json:"buildName"` + BuildNumber string `json:"buildNumber"` + BuildTimestamp string `json:"buildTimestamp"` + ReleaseBundleName string `json:"releaseBundleName"` + ReleaseBundleVersion string `json:"releaseBundleVersion"` + RepoKey string `json:"repoKey"` + CreatedAt time.Time `json:"createdAt"` +} + +type SubjectType string + +const ( + SubjectTypeArtifact SubjectType = "artifact" + SubjectTypeBuild SubjectType = "build" + SubjectTypePackage SubjectType = "package" + SubjectTypeReleaseBundle SubjectType = "release-bundle" +) + +type EvidenceSummary struct { + CommandSummary +} + +func NewEvidenceSummary() (*CommandSummary, error) { + return New(&EvidenceSummary{}, "evidence") +} + +func (es *EvidenceSummary) GetSummaryTitle() string { + return "🔎 Evidence" +} + +func (es *EvidenceSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (finalMarkdown string, err error) { + log.Debug("Generating evidence summary markdown.") + var evidenceData []EvidenceSummaryData + for _, filePath := range dataFilePaths { + var evidence EvidenceSummaryData + if err = UnmarshalFromFilePath(filePath, &evidence); err != nil { + log.Warn("Failed to unmarshal evidence data from file %s: %v", filePath, err) + return + } + evidenceData = append(evidenceData, evidence) + } + + if len(evidenceData) == 0 { + return + } + + tableMarkdown := es.generateEvidenceTable(evidenceData) + return WrapCollapsableMarkdown(es.GetSummaryTitle(), tableMarkdown, evidenceHeaderSize), nil +} + +func (es *EvidenceSummary) generateEvidenceTable(evidenceData []EvidenceSummaryData) string { + var tableBuilder strings.Builder + tableBuilder.WriteString(es.getTableHeader()) + + for _, evidence := range evidenceData { + es.appendEvidenceRow(&tableBuilder, evidence) + } + + tableBuilder.WriteString(" \n") + return tableBuilder.String() +} + +func (es *EvidenceSummary) getTableHeader() string { + return "\n" +} + +func (es *EvidenceSummary) appendEvidenceRow(tableBuilder *strings.Builder, evidence EvidenceSummaryData) { + subject := es.formatSubjectWithLink(evidence) + evidenceType := es.formatEvidenceType(evidence) + verificationStatus := es.formatVerificationStatus(evidence.Verified) + + tableBuilder.WriteString(fmt.Sprintf("\n", subject, evidenceType, verificationStatus)) +} + +func (es *EvidenceSummary) formatSubjectWithLink(evidence EvidenceSummaryData) string { + if evidence.Subject == "" { + return "evidence" + } + + evidenceUrl, err := GenerateEvidenceUrlByType(evidence, evidenceSection) + if err != nil { + log.Warn("Failed to generate evidence URL: %v", err) + evidenceUrl = "" + } + + displayName := evidence.DisplayName + if displayName == "" { + displayName = evidence.Subject + } + + var viewLink string + subjectType := es.formatSubjectType(evidence.SubjectType) + if evidenceUrl != "" { + viewLink = fmt.Sprintf(`%s %s`, subjectType, evidenceUrl, displayName) + } else { + viewLink = fmt.Sprintf("%s %s", subjectType, displayName) + } + + return viewLink +} + +func (es *EvidenceSummary) formatVerificationStatus(verified bool) string { + if verified { + return fmt.Sprintf("%s Verified", "✅") + } + return fmt.Sprintf("%s Not Verified", "❌") +} + +func (es *EvidenceSummary) formatEvidenceType(evidence EvidenceSummaryData) string { + if evidence.PredicateSlug == "" { + if evidence.PredicateType == "" { + return "⚠️ Unknown" + } + return evidence.PredicateType + } + return evidence.PredicateSlug +} + +func (es *EvidenceSummary) formatSubjectType(subjectType SubjectType) string { + switch subjectType { + case SubjectTypePackage: + return "📦️" + case SubjectTypeBuild: + return "🛠️️" + case SubjectTypeReleaseBundle: + return "🧩" + case SubjectTypeArtifact: + return "📄" + default: + return "" + } +} diff --git a/artifactory/utils/commandsummary/evidencesummary_test.go b/artifactory/utils/commandsummary/evidencesummary_test.go new file mode 100644 index 000000000..e69356b8f --- /dev/null +++ b/artifactory/utils/commandsummary/evidencesummary_test.go @@ -0,0 +1,191 @@ +package commandsummary + +import ( + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +const ( + evidenceTable = "evidence.md" +) + +func prepareEvidenceTest(t *testing.T) (*EvidenceSummary, func()) { + originalWorkflow := os.Getenv(workflowEnvKey) + err := os.Setenv(workflowEnvKey, "JFrog CLI Core Tests") + if err != nil { + assert.Fail(t, "Failed to set environment variable", err) + } + + StaticMarkdownConfig.setPlatformUrl(testPlatformUrl) + StaticMarkdownConfig.setPlatformMajorVersion(7) + StaticMarkdownConfig.setExtendedSummary(false) + + cleanup := func() { + StaticMarkdownConfig.setExtendedSummary(false) + StaticMarkdownConfig.setPlatformMajorVersion(0) + StaticMarkdownConfig.setPlatformUrl("") + + if originalWorkflow != "" { + err = os.Setenv(workflowEnvKey, originalWorkflow) + if err != nil { + assert.Fail(t, "Failed to set workflow environment variable", err) + } + } else { + os.Unsetenv(workflowEnvKey) + } + } + + evidenceSummary := &EvidenceSummary{} + return evidenceSummary, cleanup +} + +func TestEvidenceTable(t *testing.T) { + evidenceSummary, cleanUp := prepareEvidenceTest(t) + defer func() { + cleanUp() + }() + + createdTime := time.Date(2024, 12, 1, 10, 0, 0, 0, time.UTC) + + var evidenceData = []EvidenceSummaryData{ + { + Subject: "cli-sigstore-test/commons-1.0.0.txt", + SubjectSha256: "", + PredicateType: "in-toto", + PredicateSlug: "in-toto", + Verified: true, + DisplayName: "cli-sigstore-test/commons-1.0.0.txt", + SubjectType: SubjectTypeArtifact, + RepoKey: "cli-sigstore-test/commons-1.0.0.txt", + CreatedAt: createdTime, + }, + } + + t.Run("Extended Summary", func(t *testing.T) { + StaticMarkdownConfig.setExtendedSummary(true) + res := evidenceSummary.generateEvidenceTable(evidenceData) + testMarkdownOutput(t, getTestDataFile(t, evidenceTable), res) + }) + + t.Run("Basic Summary", func(t *testing.T) { + StaticMarkdownConfig.setExtendedSummary(false) + res := evidenceSummary.generateEvidenceTable(evidenceData) + testMarkdownOutput(t, getTestDataFile(t, evidenceTable), res) + }) +} + +func TestFormatSubjectType(t *testing.T) { + evidenceSummary := &EvidenceSummary{} + + tests := []struct { + name string + subjectType SubjectType + expectedIcon string + }{ + { + name: "Artifact", + subjectType: SubjectTypeArtifact, + expectedIcon: "📄", + }, + { + name: "Package", + subjectType: SubjectTypePackage, + expectedIcon: "📦️", + }, + { + name: "Build", + subjectType: SubjectTypeBuild, + expectedIcon: "🛠️️", + }, + { + name: "Release Bundle", + subjectType: SubjectTypeReleaseBundle, + expectedIcon: "🧩", + }, + { + name: "Unknown", + subjectType: SubjectType("unknown"), + expectedIcon: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := evidenceSummary.formatSubjectType(tt.subjectType) + assert.Equal(t, tt.expectedIcon, result) + }) + } +} + +func TestFormatVerificationStatus(t *testing.T) { + evidenceSummary := &EvidenceSummary{} + + tests := []struct { + name string + verified bool + expected string + }{ + { + name: "Verified", + verified: true, + expected: "✅ Verified", + }, + { + name: "Not Verified", + verified: false, + expected: "❌ Not Verified", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := evidenceSummary.formatVerificationStatus(tt.verified) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestFormatEvidenceType(t *testing.T) { + evidenceSummary := &EvidenceSummary{} + + tests := []struct { + name string + evidence EvidenceSummaryData + expectedType string + }{ + { + name: "With PredicateSlug", + evidence: EvidenceSummaryData{ + PredicateSlug: "in-toto", + PredicateType: "in-toto", + }, + expectedType: "in-toto", + }, + { + name: "Without PredicateSlug but with PredicateType", + evidence: EvidenceSummaryData{ + PredicateSlug: "", + PredicateType: "https://slsa.dev/provenance/v0.2", + }, + expectedType: "https://slsa.dev/provenance/v0.2", + }, + { + name: "Without PredicateSlug and PredicateType", + evidence: EvidenceSummaryData{ + PredicateSlug: "", + PredicateType: "", + }, + expectedType: "⚠️ Unknown", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := evidenceSummary.formatEvidenceType(tt.evidence) + assert.Equal(t, tt.expectedType, result) + }) + } +} diff --git a/artifactory/utils/commandsummary/utils.go b/artifactory/utils/commandsummary/utils.go index 75b9541e9..a83457c0f 100644 --- a/artifactory/utils/commandsummary/utils.go +++ b/artifactory/utils/commandsummary/utils.go @@ -47,6 +47,7 @@ const ( artifactsSection summarySection = "artifacts" packagesSection summarySection = "packages" buildInfoSection summarySection = "buildInfo" + evidenceSection summarySection = "evidence" ) const ( diff --git a/artifactory/utils/container/buildinfo.go b/artifactory/utils/container/buildinfo.go index 5d2a6c446..74b69fe67 100644 --- a/artifactory/utils/container/buildinfo.go +++ b/artifactory/utils/container/buildinfo.go @@ -71,7 +71,7 @@ func newBuildInfoBuilder(image *Image, repository, buildName, buildNumber, proje repoDetails := &services.RepositoryDetails{} err = serviceManager.GetRepository(repository, &repoDetails) if err != nil { - return nil, errorutils.CheckErrorf("failed to get details for repository '" + repository + "'. Error:\n" + err.Error()) + return nil, errorutils.CheckErrorf("failed to get details for repository '%s'. Error:\n%s", repository, err.Error()) } builder.repositoryDetails.isRemote = repoDetails.GetRepoType() == "remote" @@ -324,11 +324,11 @@ func GetImageTagWithDigest(filePath string) (*Image, string, error) { // Try read Kaniko/oc file. splittedData := strings.Split(string(data), `@`) if len(splittedData) != 2 { - return nil, "", errorutils.CheckErrorf(`unexpected file format "` + filePath + `". The file should include one line in the following format: image-tag@sha256`) + return nil, "", errorutils.CheckErrorf(`unexpected file format "%s". The file should include one line in the following format: image-tag@sha256`, filePath) } tag, sha256 := splittedData[0], strings.Trim(splittedData[1], "\n") if tag == "" || sha256 == "" { - err = errorutils.CheckErrorf(`missing image-tag/sha256 in file: "` + filePath + `"`) + err = errorutils.CheckErrorf(`missing image-tag/sha256 in file: "%s"`, filePath) if err != nil { return nil, "", err } @@ -609,7 +609,7 @@ func getDependenciesFromManifestConfig(candidateLayers map[string]*utils.ResultI dependencies = append(dependencies, getManifestDependency(manifestSearchResults)) imageDetails, found := candidateLayers[digestToLayer(imageSha2)] if !found { - return nil, errorutils.CheckErrorf("failed to collect build-info. Image '" + imageSha2 + "' was not found in Artifactory") + return nil, errorutils.CheckErrorf("failed to collect build-info. Image '%s' was not found in Artifactory", imageSha2) } return append(dependencies, imageDetails.ToDependency()), nil diff --git a/artifactory/utils/container/containermanager.go b/artifactory/utils/container/containermanager.go index 464da9589..a9ec54405 100644 --- a/artifactory/utils/container/containermanager.go +++ b/artifactory/utils/container/containermanager.go @@ -84,7 +84,7 @@ func (containerManager *containerManager) OsCompatibility(image *Image) (string, content = strings.Trim(content, "\n") firstSeparator := strings.Index(content, ",") if firstSeparator == -1 { - return "", "", errorutils.CheckErrorf("couldn't find OS and architecture of image:" + image.name) + return "", "", errorutils.CheckErrorf("couldn't find OS and architecture of image: %s", image.name) } return content[:firstSeparator], content[firstSeparator+1:], err } diff --git a/artifactory/utils/container/image.go b/artifactory/utils/container/image.go index 81f3d5e3d..7738f9113 100644 --- a/artifactory/utils/container/image.go +++ b/artifactory/utils/container/image.go @@ -1,6 +1,7 @@ package container import ( + "errors" "net/http" "path" "strconv" @@ -154,15 +155,15 @@ func (image *Image) GetRemoteRepo(serviceManager artifactory.ArtifactoryServices return "", err } if resp.StatusCode == http.StatusForbidden { - return "", errorutils.CheckErrorf(getStatusForbiddenErrorMessage()) + return "", errors.New(getStatusForbiddenErrorMessage()) } if resp.StatusCode != http.StatusOK { - return "", errorutils.CheckErrorf("error while getting docker repository name. Artifactory response: " + resp.Status) + return "", errorutils.CheckErrorf("error while getting docker repository name. Artifactory response: %s", resp.Status) } if dockerRepo := resp.Header["X-Artifactory-Docker-Registry"]; len(dockerRepo) != 0 { return dockerRepo[0], nil } - return "", errorutils.CheckErrorf("couldn't find 'X-Artifactory-Docker-Registry' header docker repository in artifactory") + return "", errors.New("couldn't find 'X-Artifactory-Docker-Registry' header docker repository in artifactory") } // Returns the name of the repository containing the image in Artifactory. diff --git a/artifactory/utils/container/localagent.go b/artifactory/utils/container/localagent.go index 57c4ef573..7d44734a1 100644 --- a/artifactory/utils/container/localagent.go +++ b/artifactory/utils/container/localagent.go @@ -192,5 +192,5 @@ func handleForeignLayer(layerMediaType, layerFileName string) error { log.Info(fmt.Sprintf("Foreign layer: %s is missing in Artifactory and therefore will not be added to the build-info.", layerFileName)) return nil } - return errorutils.CheckErrorf("Could not find layer: " + layerFileName + " in Artifactory") + return errorutils.CheckErrorf("Could not find layer: %s in Artifactory", layerFileName) } diff --git a/artifactory/utils/container/remoteagent.go b/artifactory/utils/container/remoteagent.go index af2ff59e9..3bb6dbf22 100644 --- a/artifactory/utils/container/remoteagent.go +++ b/artifactory/utils/container/remoteagent.go @@ -65,7 +65,7 @@ func (rabib *RemoteAgentBuildInfoBuilder) handleManifest(resultMap map[string]*u log.Debug("Found manifest.json. Proceeding to create build-info.") return resultMap, manifest, nil } - return nil, nil, errorutils.CheckErrorf(`couldn't find image "` + rabib.buildInfoBuilder.image.name + `" manifest in Artifactory`) + return nil, nil, errorutils.CheckErrorf(`couldn't find image "%s" manifest in Artifactory`, rabib.buildInfoBuilder.image.name) } func (rabib *RemoteAgentBuildInfoBuilder) handleFatManifestImage(results map[string]*utils.ResultItem) (map[string][]*utils.ResultItem, *utils.ResultItem, *FatManifest, error) { @@ -79,7 +79,7 @@ func (rabib *RemoteAgentBuildInfoBuilder) handleFatManifestImage(results map[str multiPlatformImages, err := performMultiPlatformImageSearch(fatManifestRootPath, rabib.buildInfoBuilder.serviceManager) return multiPlatformImages, fatManifestResult, fatManifest, err } - return nil, nil, nil, errorutils.CheckErrorf(`couldn't find image "` + rabib.buildInfoBuilder.image.name + `" fat manifest in Artifactory`) + return nil, nil, nil, errorutils.CheckErrorf(`couldn't find image "%s" fat manifest in Artifactory`, rabib.buildInfoBuilder.image.name) } // Search image manifest or fat-manifest of and image. diff --git a/artifactory/utils/repositoryutils.go b/artifactory/utils/repositoryutils.go index e73c2a913..37b8e68e5 100644 --- a/artifactory/utils/repositoryutils.go +++ b/artifactory/utils/repositoryutils.go @@ -1,15 +1,16 @@ package utils import ( + "os" + "path" + "strings" + "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" "github.com/jfrog/jfrog-client-go/utils/log" "golang.org/x/exp/slices" - "os" - "path" - "strings" "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-client-go/artifactory/services" @@ -77,7 +78,7 @@ func IsRemoteRepo(repoName string, serviceManager artifactory.ArtifactoryService repoDetails := &services.RepositoryDetails{} err := serviceManager.GetRepository(repoName, &repoDetails) if err != nil { - return false, errorutils.CheckErrorf("failed to get details for repository '" + repoName + "'. Error:\n" + err.Error()) + return false, errorutils.CheckErrorf("failed to get details for repository '%s'. Error:\n%s", repoName, err.Error()) } return repoDetails.GetRepoType() == "remote", nil } diff --git a/artifactory/utils/testdata/command_summaries/basic/evidence.md b/artifactory/utils/testdata/command_summaries/basic/evidence.md new file mode 100644 index 000000000..b12858ec1 --- /dev/null +++ b/artifactory/utils/testdata/command_summaries/basic/evidence.md @@ -0,0 +1,3 @@ +
Evidence SubjectEvidence TypeVerification Status
%s%s%s
+ +
Evidence SubjectEvidence TypeVerification Status
📄 cli-sigstore-test/commons-1.0.0.txtin-toto✅ Verified
diff --git a/artifactory/utils/testdata/command_summaries/extended/evidence.md b/artifactory/utils/testdata/command_summaries/extended/evidence.md new file mode 100644 index 000000000..b12858ec1 --- /dev/null +++ b/artifactory/utils/testdata/command_summaries/extended/evidence.md @@ -0,0 +1,3 @@ + + +
Evidence SubjectEvidence TypeVerification Status
📄 cli-sigstore-test/commons-1.0.0.txtin-toto✅ Verified
diff --git a/artifactory/utils/utils.go b/artifactory/utils/utils.go index 485cac992..3fe79261f 100644 --- a/artifactory/utils/utils.go +++ b/artifactory/utils/utils.go @@ -22,6 +22,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-client-go/access" "github.com/jfrog/jfrog-client-go/artifactory" + artifactoryServices "github.com/jfrog/jfrog-client-go/artifactory/services" "github.com/jfrog/jfrog-client-go/auth" clientConfig "github.com/jfrog/jfrog-client-go/config" "github.com/jfrog/jfrog-client-go/distribution" @@ -86,10 +87,10 @@ func GetEncryptedPasswordFromArtifactory(artifactoryAuth auth.ServiceDetails, in if resp.StatusCode == http.StatusConflict { message := "\nYour Artifactory server is not configured to encrypt passwords.\n" + "You may use \"art config --enc-password=false\"" - return "", errorutils.CheckErrorf(message) + return "", errors.New(message) } - return "", errorutils.CheckErrorf("Artifactory response: " + resp.Status + "\n" + clientUtils.IndentJson(body)) + return "", errorutils.CheckErrorf("Artifactory response: %s\n%s", resp.Status, clientUtils.IndentJson(body)) } func CreateServiceManager(serverDetails *config.ServerDetails, httpRetries, httpRetryWaitMilliSecs int, isDryRun bool) (artifactory.ArtifactoryServicesManager, error) { @@ -341,7 +342,24 @@ func ValidateRepoExists(repoKey string, serviceDetails auth.ServiceDetails) erro } if !exists { - return errorutils.CheckErrorf("The repository '" + repoKey + "' does not exist.") + return errorutils.CheckErrorf("The repository '%s' does not exist.", repoKey) + } + return nil +} + +// ValidateRepoType checks if the repository exists and is of the expected package type (e.g., "vscode", "jetbrains"). +func ValidateRepoType(repoKey string, serviceDetails auth.ServiceDetails, expectedType string) error { + servicesManager, err := createServiceManager(serviceDetails) + if err != nil { + return err + } + repoDetails := &artifactoryServices.RepositoryDetails{} + err = servicesManager.GetRepository(repoKey, repoDetails) + if err != nil { + return fmt.Errorf("failed to fetch repository details for %q: %w", repoKey, err) + } + if !strings.EqualFold(repoDetails.PackageType, expectedType) { + return fmt.Errorf("repository '%s' is of type '%s', but expected type is '%s'", repoKey, repoDetails.PackageType, expectedType) } return nil } diff --git a/artifactory/utils/yarn/versionVerify.go b/artifactory/utils/yarn/versionVerify.go index acebfc922..897ecf5ab 100644 --- a/artifactory/utils/yarn/versionVerify.go +++ b/artifactory/utils/yarn/versionVerify.go @@ -1,10 +1,11 @@ package yarn import ( + "strings" + gofrogcmd "github.com/jfrog/gofrog/io" "github.com/jfrog/gofrog/version" "github.com/jfrog/jfrog-client-go/utils/errorutils" - "strings" ) const unsupportedYarnVersion = "4.0.0" @@ -22,8 +23,7 @@ func IsInstalledYarnVersionSupported(executablePath string) error { func IsVersionSupported(versionStr string) error { yarnVersion := version.NewVersion(versionStr) if yarnVersion.Compare(unsupportedYarnVersion) <= 0 { - return errorutils.CheckErrorf("Yarn version 4 is not supported. The current version is: " + versionStr + - ". Please downgrade to a compatible version to continue") + return errorutils.CheckErrorf("Yarn version 4 is not supported. The current version is: %s. Please downgrade to a compatible version to continue", versionStr) } return nil } diff --git a/common/build/buildinfoproperties.go b/common/build/buildinfoproperties.go index ea2a6aa1d..cfac03d27 100644 --- a/common/build/buildinfoproperties.go +++ b/common/build/buildinfoproperties.go @@ -184,7 +184,7 @@ func GetServerDetails(vConfig *viper.Viper) (*config.ServerDetails, error) { func CreateBuildInfoProps(buildArtifactsDetailsFile string, config *viper.Viper, projectType project.ProjectType) (map[string]string, error) { if config.GetString("type") != projectType.String() { - return nil, errorutils.CheckErrorf("Incompatible build config, expected: " + projectType.String() + " got: " + config.GetString("type")) + return nil, errorutils.CheckErrorf("Incompatible build config, expected: %s, got: %s", projectType.String(), config.GetString("type")) } if err := setServerDetailsToConfig(ResolverPrefix, config); err != nil { return nil, err @@ -300,7 +300,7 @@ func setServerDetailsToConfig(contextPrefix string, vConfig *viper.Viper) error return err } if artDetails.GetArtifactoryUrl() == "" { - return errorutils.CheckErrorf("Server ID " + serverId + ": URL is required.") + return errorutils.CheckErrorf("Server ID %s URL is required.", serverId) } vConfig.Set(contextPrefix+Url, artDetails.GetArtifactoryUrl()) diff --git a/common/commands/config.go b/common/commands/config.go index ca3c9da85..b34ae8d80 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -3,7 +3,6 @@ package commands import ( "errors" "fmt" - generic "github.com/jfrog/jfrog-cli-core/v2/general/token" "net/url" "os" "reflect" @@ -11,6 +10,8 @@ import ( "strings" "sync" + generic "github.com/jfrog/jfrog-cli-core/v2/general/token" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -134,7 +135,7 @@ func (cc *ConfigCommand) Run() (err error) { case Clear: err = cc.clear() default: - err = fmt.Errorf("Not supported config command type: " + string(cc.cmdType)) + err = fmt.Errorf("Not supported config command type: %s", string(cc.cmdType)) } return } diff --git a/common/commands/configfile.go b/common/commands/configfile.go index a9f45b2a5..db06a59ba 100644 --- a/common/commands/configfile.go +++ b/common/commands/configfile.go @@ -1,6 +1,7 @@ package commands import ( + "errors" "fmt" "os" "path/filepath" @@ -580,7 +581,7 @@ func validateRepositoryConfig(repository *project.Repository, errorPrefix string snapshotRepo := repository.SnapshotRepo if repository.ServerId != "" && repository.Repo == "" && releaseRepo == "" && snapshotRepo == "" { - return errorutils.CheckErrorf(errorPrefix + setRepositoryError) + return errors.New(errorPrefix + setRepositoryError) } // Server-id flag was not provided. if repository.ServerId == "" { @@ -601,7 +602,7 @@ func validateRepositoryConfig(repository *project.Repository, errorPrefix string if serverId == "" { // Repositories flags were provided. if repository.Repo != "" || releaseRepo != "" || snapshotRepo != "" { - return errorutils.CheckErrorf(errorPrefix + setServerIdError) + return errors.New(errorPrefix + setServerIdError) } } else if repository.Repo != "" || releaseRepo != "" || snapshotRepo != "" { // Server-id flag wasn't provided and repositories flags were provided - the default configured global server will be chosen. @@ -610,7 +611,7 @@ func validateRepositoryConfig(repository *project.Repository, errorPrefix string } // Release/snapshot repositories should be entangled to each other. if (releaseRepo == "" && snapshotRepo != "") || (releaseRepo != "" && snapshotRepo == "") { - return errorutils.CheckErrorf(errorPrefix + setSnapshotAndReleaseError) + return errors.New(errorPrefix + setSnapshotAndReleaseError) } return nil } @@ -632,7 +633,7 @@ func readArtifactoryServer(useArtifactoryQuestion string) (string, error) { return "", err } if len(serversIds) == 0 { - return "", errorutils.CheckErrorf("No Artifactory servers configured. Use the 'jfrog c add' command to set the Artifactory server details.") + return "", errors.New("No Artifactory servers configured. Use the 'jfrog c add' command to set the Artifactory server details.") } // Ask whether to use artifactory diff --git a/common/format/output.go b/common/format/output.go index a1ae5a6a5..01ded4abe 100644 --- a/common/format/output.go +++ b/common/format/output.go @@ -36,7 +36,7 @@ func GetOutputFormat(formatFlagVal string) (format OutputFormat, err error) { case string(CycloneDx): format = CycloneDx default: - err = errorutils.CheckErrorf("only the following output formats are supported: " + coreutils.ListToText(OutputFormats)) + err = errorutils.CheckErrorf("only the following output formats are supported: %s", coreutils.ListToText(OutputFormats)) } } return diff --git a/common/project/projectconfig.go b/common/project/projectconfig.go index a4ef3d93e..d00f9cd3b 100644 --- a/common/project/projectconfig.go +++ b/common/project/projectconfig.go @@ -219,7 +219,7 @@ func GetResolutionOnlyConfiguration(projectType ProjectType) (*RepositoryConfig, return nil, err } if !exists { - return nil, errorutils.CheckErrorf(projectType.String() + " Project configuration does not exist.") + return nil, errorutils.CheckErrorf("%s Project configuration does not exist.", projectType.String()) } return ReadResolutionOnlyConfiguration(confFilePath) } diff --git a/go.mod b/go.mod index 25bf141af..489e93072 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jfrog/jfrog-cli-core/v2 -go 1.23.7 +go 1.24.4 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) @@ -13,9 +13,9 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.6.5 - github.com/jfrog/build-info-go v1.10.14 + github.com/jfrog/build-info-go v1.10.15 github.com/jfrog/gofrog v1.7.6 - github.com/jfrog/jfrog-client-go v1.54.3 + github.com/jfrog/jfrog-client-go v1.54.4 github.com/magiconair/properties v1.8.9 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c diff --git a/go.sum b/go.sum index b40159050..315b9d1b4 100644 --- a/go.sum +++ b/go.sum @@ -109,12 +109,12 @@ github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3N github.com/jedib0t/go-pretty/v6 v6.6.5/go.mod h1:Uq/HrbhuFty5WSVNfjpQQe47x16RwVGXIveNGEyGtHs= 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.10.14 h1:PWnw+rBwiQTHZ5q+84+E8MHFjtAQkB3+Oc2sKwBSSGE= -github.com/jfrog/build-info-go v1.10.14/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= +github.com/jfrog/build-info-go v1.10.15 h1:y6E87iIBTofNy4mus6Ngv6AtVwg/bN/Rz+oaI3kpN4M= +github.com/jfrog/build-info-go v1.10.15/go.mod h1:+8u1CEGrr8XY5a5U6farFW3EKYk0ge0BMGZE3BAZBcE= 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.54.3 h1:tIhhDhM7rDMT1lzgeQy4nr6H2ihlqnumhiFybIWlLz0= -github.com/jfrog/jfrog-client-go v1.54.3/go.mod h1:1v0eih4thdPA4clBo9TuvAMT25sGDr1IQJ81DXQ/lBY= +github.com/jfrog/jfrog-client-go v1.54.4 h1:W5J2WAidEPghlvWl7FbrJUeRyVbNzC6GnihNACVaeEM= +github.com/jfrog/jfrog-client-go v1.54.4/go.mod h1:+pSVE7Co+ytwhOhmz84/Lpe5fSeTaWJXsP1qt+WVfw0= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= diff --git a/missioncontrol/commands/jpdadd.go b/missioncontrol/commands/jpdadd.go index 977d068d2..01b71ceba 100644 --- a/missioncontrol/commands/jpdadd.go +++ b/missioncontrol/commands/jpdadd.go @@ -23,7 +23,7 @@ func JpdAdd(flags *JpdAddFlags) error { return err } if resp.StatusCode != http.StatusCreated { - return errorutils.CheckErrorf(resp.Status + ". " + utils.ReadMissionControlHttpMessage(body)) + return errorutils.CheckErrorf("%s. %s", resp.Status, utils.ReadMissionControlHttpMessage(body)) } log.Debug("Mission Control response: " + resp.Status) diff --git a/missioncontrol/commands/jpddelete.go b/missioncontrol/commands/jpddelete.go index 52692a21e..418844481 100644 --- a/missioncontrol/commands/jpddelete.go +++ b/missioncontrol/commands/jpddelete.go @@ -1,12 +1,13 @@ package commands import ( + "net/http" + "github.com/jfrog/jfrog-cli-core/v2/missioncontrol/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/http/httpclient" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" - "net/http" ) func JpdDelete(jpdId string, serverDetails *config.ServerDetails) error { @@ -21,7 +22,7 @@ func JpdDelete(jpdId string, serverDetails *config.ServerDetails) error { return err } if resp.StatusCode != http.StatusNoContent { - return errorutils.CheckErrorf(resp.Status + ". " + utils.ReadMissionControlHttpMessage(body)) + return errorutils.CheckErrorf("%s. %s", resp.Status, utils.ReadMissionControlHttpMessage(body)) } log.Debug("Mission Control response: " + resp.Status) return nil diff --git a/missioncontrol/commands/licenseacquire.go b/missioncontrol/commands/licenseacquire.go index 56f659fb9..cce82c9a1 100644 --- a/missioncontrol/commands/licenseacquire.go +++ b/missioncontrol/commands/licenseacquire.go @@ -19,7 +19,7 @@ func LicenseAcquire(bucketId string, name string, serverDetails *config.ServerDe } requestContent, err := json.Marshal(postContent) if err != nil { - return errorutils.CheckErrorf("Failed to marshal json: " + err.Error()) + return errorutils.CheckErrorf("Failed to marshal json: %s", err.Error()) } missionControlUrl := serverDetails.MissionControlUrl + "api/v1/buckets/" + bucketId + "/acquire" httpClientDetails := utils.GetMissionControlHttpClientDetails(serverDetails) diff --git a/missioncontrol/commands/licensedeploy.go b/missioncontrol/commands/licensedeploy.go index b3f86dea1..0b311102a 100644 --- a/missioncontrol/commands/licensedeploy.go +++ b/missioncontrol/commands/licensedeploy.go @@ -20,7 +20,7 @@ func LicenseDeploy(bucketId, jpdId string, flags *LicenseDeployFlags) error { } requestContent, err := json.Marshal(postContent) if err != nil { - return errorutils.CheckErrorf("Failed to marshal json: " + err.Error()) + return errorutils.CheckErrorf("Failed to marshal json: %s", err.Error()) } missionControlUrl := flags.ServerDetails.MissionControlUrl + "api/v1/buckets/" + bucketId + "/deploy" httpClientDetails := utils.GetMissionControlHttpClientDetails(flags.ServerDetails) diff --git a/missioncontrol/commands/licenserelease.go b/missioncontrol/commands/licenserelease.go index a6854ba59..ec53abb06 100644 --- a/missioncontrol/commands/licenserelease.go +++ b/missioncontrol/commands/licenserelease.go @@ -17,7 +17,7 @@ func LicenseRelease(bucketId, jpdId string, mcDetails *config.ServerDetails) err Name: jpdId} requestContent, err := json.Marshal(postContent) if err != nil { - return errorutils.CheckErrorf("Failed to marshal json: " + err.Error()) + return errorutils.CheckErrorf("Failed to marshal json: %s", err.Error()) } missionControlUrl := mcDetails.MissionControlUrl + "api/v1/buckets/" + bucketId + "/release" httpClientDetails := utils.GetMissionControlHttpClientDetails(mcDetails) diff --git a/utils/config/config.go b/utils/config/config.go index d059c5d54..92dfe9fda 100644 --- a/utils/config/config.go +++ b/utils/config/config.go @@ -851,7 +851,7 @@ func (serverDetails *ServerDetails) GetAuthenticationCredentials() (string, stri } else if serverDetails.ArtifactoryUrl != "" { errMissingCredsMsg += serverDetails.ArtifactoryUrl } - return "", "", errorutils.CheckErrorf(errMissingCredsMsg) + return "", "", errors.New(errMissingCredsMsg) } func (missionControlDetails *MissionControlDetails) GetAccessToken() string { diff --git a/utils/config/encryption.go b/utils/config/encryption.go index 2c78afb7d..a9b8731d7 100644 --- a/utils/config/encryption.go +++ b/utils/config/encryption.go @@ -5,12 +5,13 @@ import ( "crypto/cipher" "crypto/rand" "encoding/base64" - ioutils "github.com/jfrog/gofrog/io" "io" "os" "strconv" "syscall" + ioutils "github.com/jfrog/gofrog/io" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -147,7 +148,7 @@ func encrypt(secret string, key string) (string, error) { return "", nil } if len(key) != 32 { - return "", errorutils.CheckErrorf(encryptErrorPrefix + "Wrong length for master key. Key should have a length of exactly: " + strconv.Itoa(masterKeyLength) + " bytes") + return "", errorutils.CheckErrorf("%s Wrong length for master key. Key should have a length of exactly: %s bytes", encryptErrorPrefix, strconv.Itoa(masterKeyLength)) } c, err := aes.NewCipher([]byte(key)) if err != nil { diff --git a/utils/config/tokenrefresh.go b/utils/config/tokenrefresh.go index e4362e2ea..5422db235 100644 --- a/utils/config/tokenrefresh.go +++ b/utils/config/tokenrefresh.go @@ -2,11 +2,12 @@ package config import ( "errors" + "sync" + "time" + "github.com/jfrog/jfrog-client-go/access" accessservices "github.com/jfrog/jfrog-client-go/access/services" "github.com/jfrog/jfrog-client-go/utils/errorutils" - "sync" - "time" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/lock" @@ -113,7 +114,7 @@ func tokenRefreshHandler(currentAccessToken string, tokenType TokenType) (newAcc newAccessToken, err = refreshAccessTokenAndWriteToConfig(serverConfiguration, currentAccessToken) return } - err = errorutils.CheckErrorf("unsupported refreshable token type: " + string(tokenType)) + err = errorutils.CheckErrorf("unsupported refreshable token type: %s", string(tokenType)) return } @@ -151,7 +152,7 @@ func refreshAccessTokenAndWriteToConfig(serverConfiguration *ServerDetails, curr // Try refreshing tokens newToken, err := refreshExpiredAccessToken(serverConfiguration, currentAccessToken, serverConfiguration.RefreshToken) if err != nil { - return "", errorutils.CheckErrorf("Refresh access token failed: " + err.Error()) + return "", errorutils.CheckErrorf("Refresh access token failed: %s", err.Error()) } err = writeNewTokens(serverConfiguration, tokenRefreshServerId, newToken.AccessToken, newToken.RefreshToken, AccessToken) return newToken.AccessToken, err diff --git a/utils/ioutils/ioutils.go b/utils/ioutils/ioutils.go index c410c4d25..76f4c3f2a 100644 --- a/utils/ioutils/ioutils.go +++ b/utils/ioutils/ioutils.go @@ -4,16 +4,17 @@ import ( "bufio" "errors" "fmt" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - "golang.org/x/term" "io" "os" "path/filepath" "strings" "syscall" + + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "golang.org/x/term" ) // disallowUsingSavedPassword - Prevent changing username or url without changing the password. @@ -145,7 +146,7 @@ func createRestoreFileFunc(filePath, backupFileName string) func() error { } return errorutils.CheckError(err) } - return errorutils.CheckErrorf(createRestoreErrorPrefix(filePath, backupPath) + err.Error()) + return errors.New(createRestoreErrorPrefix(filePath, backupPath) + err.Error()) } if err := fileutils.MoveFile(backupPath, filePath); err != nil { diff --git a/utils/reposnapshot/snapshotmanager.go b/utils/reposnapshot/snapshotmanager.go index 2e92c2868..99ccd4174 100644 --- a/utils/reposnapshot/snapshotmanager.go +++ b/utils/reposnapshot/snapshotmanager.go @@ -92,7 +92,7 @@ func (sm *RepoSnapshotManager) CalculateTransferredFilesAndSize() (totalFilesCou // Returns the node corresponding to the directory in the provided relative path. Path should be provided without the repository name. func (sm *RepoSnapshotManager) LookUpNode(relativePath string) (requestedNode *Node, err error) { if relativePath == "" { - return nil, errorutils.CheckErrorf(getLookUpNodeError(relativePath) + "- unexpected empty path provided to look up") + return nil, errorutils.CheckErrorf("%s- unexpected empty path provided to look up", getLookUpNodeError(relativePath)) } relativePath = strings.TrimSuffix(relativePath, "/") if relativePath == "." { @@ -107,7 +107,7 @@ func (sm *RepoSnapshotManager) LookUpNode(relativePath string) (requestedNode *N return nil, err } if requestedNode == nil { - return nil, errorutils.CheckErrorf(getLookUpNodeError(relativePath)) + return nil, errors.New(getLookUpNodeError(relativePath)) } return }