diff --git a/build/npm/v2-jf/package-lock.json b/build/npm/v2-jf/package-lock.json index 4870c7042..3ce4d2472 100644 --- a/build/npm/v2-jf/package-lock.json +++ b/build/npm/v2-jf/package-lock.json @@ -1,5 +1,5 @@ { "name": "jfrog-cli-v2-jf", - "version": "2.65.0", + "version": "2.67.0", "lockfileVersion": 1 } diff --git a/build/npm/v2-jf/package.json b/build/npm/v2-jf/package.json index 9e27082a3..06c48efe5 100644 --- a/build/npm/v2-jf/package.json +++ b/build/npm/v2-jf/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2-jf", - "version": "2.65.0", + "version": "2.67.0", "description": "🐸 Command-line interface for JFrog Artifactory, Xray, Distribution, Pipelines and Mission Control 🐸", "homepage": "https://github.com/jfrog/jfrog-cli", "preferGlobal": true, diff --git a/build/npm/v2/package-lock.json b/build/npm/v2/package-lock.json index 828d134ff..a5a3de881 100644 --- a/build/npm/v2/package-lock.json +++ b/build/npm/v2/package-lock.json @@ -1,5 +1,5 @@ { "name": "jfrog-cli-v2", - "version": "2.65.0", + "version": "2.67.0", "lockfileVersion": 2 } diff --git a/build/npm/v2/package.json b/build/npm/v2/package.json index 2bb68be8f..99087673d 100644 --- a/build/npm/v2/package.json +++ b/build/npm/v2/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2", - "version": "2.65.0", + "version": "2.67.0", "description": "🐸 Command-line interface for JFrog Artifactory, Xray, Distribution, Pipelines and Mission Control 🐸", "homepage": "https://github.com/jfrog/jfrog-cli", "preferGlobal": true, diff --git a/buildtools/cli.go b/buildtools/cli.go index 9dfc3de4b..155717b49 100644 --- a/buildtools/cli.go +++ b/buildtools/cli.go @@ -3,6 +3,7 @@ package buildtools import ( "errors" "fmt" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "os" "strconv" "strings" @@ -91,7 +92,10 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: MvnCmd, + Action: func(c *cli.Context) (err error) { + cmdName, _ := getCommandName(c.Args()) + return securityCLI.WrapCmdWithCurationPostFailureRun(c, MvnCmd, techutils.Maven, cmdName) + }, }, { Name: "gradle-config", @@ -215,7 +219,10 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: GoCmd, + Action: func(c *cli.Context) (err error) { + cmdName, _ := getCommandName(c.Args()) + return securityCLI.WrapCmdWithCurationPostFailureRun(c, GoCmd, techutils.Go, cmdName) + }, }, { Name: "go-publish", @@ -252,7 +259,10 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: PipCmd, + Action: func(c *cli.Context) (err error) { + cmdName, _ := getCommandName(c.Args()) + return securityCLI.WrapCmdWithCurationPostFailureRun(c, PipCmd, techutils.Pip, cmdName) + }, }, { Name: "pipenv-config", @@ -325,9 +335,13 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc("install", "i", "isntall", "add", "ci", "publish", "p"), Category: buildToolsCategory, - Action: func(c *cli.Context) error { + Action: func(c *cli.Context) (errFromCmd error) { cmdName, _ := getCommandName(c.Args()) - return npmGenericCmd(c, cmdName, false) + return securityCLI.WrapCmdWithCurationPostFailureRun(c, + func(c *cli.Context) error { + return npmGenericCmd(c, cmdName, false) + }, + techutils.Npm, cmdName) }, }, { @@ -831,6 +845,7 @@ func npmGenericCmd(c *cli.Context, cmdName string, collectBuildInfoIfRequested b // Run generic npm command. npmCmd := npm.NewNpmCommand(cmdName, collectBuildInfoIfRequested) + configFilePath, args, err := GetNpmConfigAndArgs(c) if err != nil { return err diff --git a/docs/general/summary/help.go b/docs/general/summary/help.go new file mode 100644 index 000000000..6bb556945 --- /dev/null +++ b/docs/general/summary/help.go @@ -0,0 +1,9 @@ +package summary + +var Usage = []string{"csm"} + +func GetDescription() string { + return `Generates a Summary of recorded CLI commands there were executed on the current machine. + The report is generated in Markdown format and saved in the directory stored in the JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR environment variable. +` +} diff --git a/general/summary/cli.go b/general/summary/cli.go new file mode 100644 index 000000000..495b5a34a --- /dev/null +++ b/general/summary/cli.go @@ -0,0 +1,313 @@ +package summary + +import ( + "errors" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary" + "github.com/jfrog/jfrog-cli/utils/cliutils" + "os" + "path/filepath" + "strings" + + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" + coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + securityUtils "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/urfave/cli" +) + +type MarkdownSection string + +const ( + Security MarkdownSection = "security" + BuildInfo MarkdownSection = "build-info" + Upload MarkdownSection = "upload" +) + +const ( + markdownFileName = "markdown.md" + finalSarifFileName = "final.sarif" +) + +var markdownSections = []MarkdownSection{Security, BuildInfo, Upload} + +func (ms MarkdownSection) String() string { + return string(ms) +} + +// Generates a combined markdown from all sections, and aggregates multiple SARIF files into one. +func FinalizeCommandSummaries(c *cli.Context) error { + if !shouldGenerateSummary() { + return fmt.Errorf("unable to generate the command summary because the output directory is not specified."+ + " Please ensure that the environment variable '%s' is set before running your commands to enable summary generation", coreutils.SummaryOutputDirPathEnv) + } + + if err := generateSummaryMarkdown(c); err != nil { + return err + } + + return aggregatedCodeScanningSarifs() +} + +// generateSummaryMarkdown creates a summary of recorded CLI commands in Markdown format. +func generateSummaryMarkdown(c *cli.Context) error { + // Get URL and Version to generate summary links + serverUrl, majorVersion, err := extractServerUrlAndVersion(c) + if err != nil { + return fmt.Errorf("failed to get server URL or major version: %v. This means markdown URLs will be invalid", err) + } + + if err = commandsummary.InitMarkdownGenerationValues(serverUrl, majorVersion); err != nil { + return fmt.Errorf("failed to initialize command summary values: %w", err) + } + + // Invoke each section's markdown generation function + for _, section := range markdownSections { + if err := invokeSectionMarkdownGeneration(section); err != nil { + log.Warn("Failed to generate markdown for section:", section, err) + } + } + + // Combine all sections into a single Markdown file + finalMarkdown, err := mergeMarkdownFiles() + if err != nil { + return fmt.Errorf("error combining markdown files: %w", err) + } + + // Saves the final Markdown to the root directory of the command summaries + return saveMarkdownToFileSystem(finalMarkdown) +} + +func aggregatedCodeScanningSarifs() error { + files, err := getSarifFiles() + if err != nil { + return err + } + if len(files) == 0 { + log.Debug("No sarif reports were found") + return nil + } + finalSarif, err := securityUtils.CombineSarifOutputFiles(files) + if err != nil { + return err + } + return saveFinalSarifToFileSystem(string(finalSarif)) +} + +func getSarifReportsDir() string { + return filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(Security), string(commandsummary.SarifReport)) +} + +// The CLI generates summaries in sections, with each section as a separate Markdown file. +// This function merges all sections into a single Markdown file and saves it in the root of the +// command summary output directory. +func mergeMarkdownFiles() (string, error) { + var combinedMarkdown strings.Builder + for _, section := range markdownSections { + sectionContent, err := getSectionMarkdownContent(section) + if err != nil { + return "", fmt.Errorf("error getting markdown content for section %s: %w", section, err) + } + if _, err := combinedMarkdown.WriteString(sectionContent); err != nil { + return "", fmt.Errorf("error writing markdown content for section %s: %w", section, err) + } + } + return combinedMarkdown.String(), nil +} + +// saveMarkdownToFileSystem saves markdown content in the specified directory. +func saveMarkdownToFileSystem(finalMarkdown string) (err error) { + if finalMarkdown == "" { + return nil + } + filePath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, markdownFileName) + return saveFile(finalMarkdown, filePath) +} + +func saveFile(content, filePath string) (err error) { + if content == "" { + return nil + } + file, err := os.Create(filePath) + if err != nil { + return err + } + defer func() { + err = errors.Join(err, file.Close()) + }() + if _, err = file.WriteString(content); err != nil { + return err + } + return nil +} + +func getSectionMarkdownContent(section MarkdownSection) (string, error) { + sectionFilepath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(section), markdownFileName) + if _, err := os.Stat(sectionFilepath); os.IsNotExist(err) { + return "", nil + } + + contentBytes, err := os.ReadFile(sectionFilepath) + if err != nil { + return "", fmt.Errorf("error reading markdown file for section %s: %w", section, err) + } + if len(contentBytes) == 0 { + return "", nil + } + return string(contentBytes), nil +} + +func getSarifFiles() (files []string, err error) { + indexedFiles, err := commandsummary.GetIndexedDataFilesPaths() + if err != nil { + return + } + sarifsMap := indexedFiles[commandsummary.SarifReport] + for i := range sarifsMap { + files = append(files, sarifsMap[i]) + } + return +} + +func saveFinalSarifToFileSystem(finalSarif string) (err error) { + filePath := filepath.Join(getSarifReportsDir(), finalSarifFileName) + return saveFile(finalSarif, filePath) +} + +// Initiate the desired command summary implementation and invoke its Markdown generation. +func invokeSectionMarkdownGeneration(section MarkdownSection) error { + switch section { + case Security: + return generateSecurityMarkdown() + case BuildInfo: + return generateBuildInfoMarkdown() + case Upload: + return generateUploadMarkdown() + default: + return fmt.Errorf("unknown section: %s", section) + } +} + +func generateSecurityMarkdown() error { + securitySummary, err := securityUtils.NewSecurityJobSummary() + if err != nil { + return fmt.Errorf("error generating security markdown: %w", err) + } + return securitySummary.GenerateMarkdown() +} + +func generateBuildInfoMarkdown() error { + buildInfoSummary, err := commandsummary.NewBuildInfoSummary() + if err != nil { + return fmt.Errorf("error generating build-info markdown: %w", err) + } + if err = mapScanResults(); err != nil { + return fmt.Errorf("error mapping scan results: %w", err) + } + return buildInfoSummary.GenerateMarkdown() +} + +func generateUploadMarkdown() error { + if should, err := shouldGenerateUploadSummary(); err != nil || !should { + log.Debug("Skipping upload summary generation due build-info data to avoid duplications...") + return err + } + uploadSummary, err := commandsummary.NewUploadSummary() + if err != nil { + return fmt.Errorf("error generating upload markdown: %w", err) + } + return uploadSummary.GenerateMarkdown() +} + +// mapScanResults maps the scan results saved during runtime into scan components. +func mapScanResults() (err error) { + // Gets the saved scan results file paths. + indexedFiles, err := commandsummary.GetIndexedDataFilesPaths() + if err != nil { + return err + } + securityJobSummary := &securityUtils.SecurityJobSummary{} + // Init scan result map + scanResultsMap := make(map[string]commandsummary.ScanResult) + // Set default not scanned component view + scanResultsMap[commandsummary.NonScannedResult] = securityJobSummary.GetNonScannedResult() + commandsummary.StaticMarkdownConfig.SetScanResultsMapping(scanResultsMap) + // Process each scan result file by its type and append to map + for index, keyValue := range indexedFiles { + for scannedEntityName, scanResultDataFilePath := range keyValue { + scanResultsMap, err = processScan(index, scanResultDataFilePath, scannedEntityName, securityJobSummary, scanResultsMap) + if err != nil { + return + } + } + } + return +} + +// Each scan result should be processed according to its index. +// To generate custom view for each scan type. +func processScan(index commandsummary.Index, filePath string, scannedName string, sec *securityUtils.SecurityJobSummary, scanResultsMap map[string]commandsummary.ScanResult) (map[string]commandsummary.ScanResult, error) { + var res commandsummary.ScanResult + var err error + switch index { + case commandsummary.DockerScan: + res, err = sec.DockerScan([]string{filePath}) + case commandsummary.BuildScan: + res, err = sec.BuildScan([]string{filePath}) + case commandsummary.BinariesScan: + res, err = sec.BinaryScan([]string{filePath}) + } + scanResultsMap[scannedName] = res + if err != nil { + return nil, err + } + return scanResultsMap, nil +} + +// shouldGenerateUploadSummary checks if upload summary should be generated. +func shouldGenerateUploadSummary() (bool, error) { + buildInfoPath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(BuildInfo)) + if _, err := os.Stat(buildInfoPath); os.IsNotExist(err) { + return true, nil + } + dirEntries, err := os.ReadDir(buildInfoPath) + if err != nil { + return false, fmt.Errorf("error reading directory: %w", err) + } + return len(dirEntries) == 0, nil +} + +func createPlatformDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) { + platformDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, true, commonCliUtils.Platform) + if err != nil { + return nil, fmt.Errorf("error creating platform details: %w", err) + } + if platformDetails.Url == "" { + return nil, errors.New("platform URL is mandatory for access token creation") + } + return platformDetails, nil +} + +func extractServerUrlAndVersion(c *cli.Context) (platformUrl string, platformMajorVersion int, err error) { + serverDetails, err := createPlatformDetailsByFlags(c) + if err != nil { + return "", 0, fmt.Errorf("error extracting server details: %w", err) + } + platformUrl = serverDetails.Url + + servicesManager, err := utils.CreateServiceManager(serverDetails, -1, 0, false) + if err != nil { + return "", 0, fmt.Errorf("error creating services manager: %w", err) + } + if platformMajorVersion, err = utils.GetRtMajorVersion(servicesManager); err != nil { + return "", 0, fmt.Errorf("error getting Artifactory major platformMajorVersion: %w", err) + } + return +} + +// shouldGenerateSummary checks if the summary should be generated. +func shouldGenerateSummary() bool { + return os.Getenv(coreutils.SummaryOutputDirPathEnv) != "" +} diff --git a/go.mod b/go.mod index eb3507d97..f97e42df8 100644 --- a/go.mod +++ b/go.mod @@ -19,10 +19,10 @@ require ( github.com/jfrog/build-info-go v1.9.35 github.com/jfrog/gofrog v1.7.5 github.com/jfrog/jfrog-cli-artifactory v0.1.6 - github.com/jfrog/jfrog-cli-core/v2 v2.55.5 + github.com/jfrog/jfrog-cli-core/v2 v2.55.7 github.com/jfrog/jfrog-cli-platform-services v1.3.0 - github.com/jfrog/jfrog-cli-security v1.7.1 - github.com/jfrog/jfrog-client-go v1.46.0 + github.com/jfrog/jfrog-cli-security v1.8.0 + github.com/jfrog/jfrog-client-go v1.46.1 github.com/jszwec/csvutil v1.10.0 github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.33.0 @@ -59,6 +59,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/forPelevin/gomoji v1.2.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -170,12 +171,12 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/eyalbe4/jfrog-cli-core/v2 v2.55.3-0.20240821161232-d9ee8b2b6e9c +// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/RobiNino/jfrog-cli-core/v2 v2.0.0-20240904105726-775a1614224e -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240806162439-01bb7dcd43fc +// replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20240904061406-f368939ce3a0 -// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240804091815-7407ceb49077 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240806162439-01bb7dcd43fc -// replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.6.3-0.20240729081816-371509c205d6 +// replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240819133117-c3f52700927d // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog dev diff --git a/go.sum b/go.sum index 45934aeda..6c23b575e 100644 --- a/go.sum +++ b/go.sum @@ -737,8 +737,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -941,14 +941,14 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= github.com/jfrog/jfrog-cli-artifactory v0.1.6 h1:bMfJsrLQJw0dZp4nqUf1xOmtY0rpCatW/I5q88x+fhQ= github.com/jfrog/jfrog-cli-artifactory v0.1.6/go.mod h1:jbNb22ebtupcjdhrdGq0VBew2vWG6VUK04xxGNDfynE= -github.com/jfrog/jfrog-cli-core/v2 v2.55.5 h1:lcs30UfSlePaZ+Wf2COvtXypfbfAh3krJv3R9zIxuIo= -github.com/jfrog/jfrog-cli-core/v2 v2.55.5/go.mod h1:INuQHK1sEdPpCVJwiC71+nd3Pv32j8NXSECjN0GnqCQ= +github.com/jfrog/jfrog-cli-core/v2 v2.55.7 h1:V4dO2FMNIH49lov3dMj3jYRg8KBTG7hyhHI8ftYByf8= +github.com/jfrog/jfrog-cli-core/v2 v2.55.7/go.mod h1:DPO5BfWAeOByahFMMy+PcjmbPlcyoRy7Bf2C5sGKVi0= github.com/jfrog/jfrog-cli-platform-services v1.3.0 h1:IblSDZFBjL7WLRi37Ni2DmHrXJJ6ysSMxx7t41AvyDA= github.com/jfrog/jfrog-cli-platform-services v1.3.0/go.mod h1:Ky4SDXuMeaiNP/5zMT1YSzIuXG+cNYYOl8BaEA7Awbc= -github.com/jfrog/jfrog-cli-security v1.7.1 h1:wPyKdtcKctjEsCqNpumog65zBrjfPXnz61B/vBdXmz4= -github.com/jfrog/jfrog-cli-security v1.7.1/go.mod h1:QBKxbPse37zj/IMJjmgm0c9CIT6ev8ZTng/5m6CAQys= -github.com/jfrog/jfrog-client-go v1.46.0 h1:lyzJCpLN9NIp4raHw48D12+g42/Aa8SHxBbuNp4Yflk= -github.com/jfrog/jfrog-client-go v1.46.0/go.mod h1:UCu2JNBfMp9rypEmCL84DCooG79xWIHVadZQR3Ab+BQ= +github.com/jfrog/jfrog-cli-security v1.8.0 h1:jp/AVaQcItUNXRCud5PMyl8VVjPuzfrNHJWQvWAMnms= +github.com/jfrog/jfrog-cli-security v1.8.0/go.mod h1:DjufYZpsTwILOFJlx7tR/y63oLBRmtPtFIz1WgiP/X4= +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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jszwec/csvutil v1.10.0 h1:upMDUxhQKqZ5ZDCs/wy+8Kib8rZR8I8lOR34yJkdqhI= diff --git a/main.go b/main.go index c8389f1de..82af701a2 100644 --- a/main.go +++ b/main.go @@ -21,9 +21,11 @@ import ( "github.com/jfrog/jfrog-cli/docs/common" aiDocs "github.com/jfrog/jfrog-cli/docs/general/ai" loginDocs "github.com/jfrog/jfrog-cli/docs/general/login" + summaryDocs "github.com/jfrog/jfrog-cli/docs/general/summary" tokenDocs "github.com/jfrog/jfrog-cli/docs/general/token" "github.com/jfrog/jfrog-cli/general/ai" "github.com/jfrog/jfrog-cli/general/login" + "github.com/jfrog/jfrog-cli/general/summary" "github.com/jfrog/jfrog-cli/general/token" "github.com/jfrog/jfrog-cli/lifecycle" "github.com/jfrog/jfrog-cli/missioncontrol" @@ -68,7 +70,7 @@ func main() { log.SetDefaultLogger() err := execMain() if cleanupErr := fileutils.CleanOldDirs(); cleanupErr != nil { - clientlog.Warn(cleanupErr) + clientlog.Warn("failed while attempting to cleanup old CLI temp directories:", cleanupErr) } coreutils.ExitOnErr(err) } @@ -292,6 +294,14 @@ func getCommands() ([]cli.Command, error) { Category: otherCategory, Action: token.AccessTokenCreateCmd, }, + { + Name: "generate-summary-markdown", + Aliases: []string{"gsm"}, + Usage: summaryDocs.GetDescription(), + HelpName: corecommon.CreateUsage("gsm", summaryDocs.GetDescription(), summaryDocs.Usage), + Category: otherCategory, + Action: summary.FinalizeCommandSummaries, + }, } securityCmds, err := ConvertEmbeddedPlugin(securityCLI.GetJfrogCliSecurityApp()) diff --git a/transfer_test.go b/transfer_test.go index 592dc9ea3..2fe91bd22 100644 --- a/transfer_test.go +++ b/transfer_test.go @@ -369,6 +369,7 @@ func generateTestRepoSnapshotFile(t *testing.T, repoKey, repoSnapshotFilePath st func addChildWithFiles(t *testing.T, parent *reposnapshot.Node, dirName string, explored, checkCompleted bool, filesCount int) *reposnapshot.Node { childNode := reposnapshot.CreateNewNode(dirName, nil) for i := 0; i < filesCount; i++ { + //#nosec G115 assert.NoError(t, childNode.IncrementFilesCount(uint64(i))) } diff --git a/utils/cliutils/cli_consts.go b/utils/cliutils/cli_consts.go index 071d9b292..c830e94bb 100644 --- a/utils/cliutils/cli_consts.go +++ b/utils/cliutils/cli_consts.go @@ -4,7 +4,7 @@ import "time" const ( // General CLI constants - CliVersion = "2.65.0" + CliVersion = "2.67.0" ClientAgent = "jfrog-cli-go" // CLI base commands constants: diff --git a/utils/cliutils/commandsflags.go b/utils/cliutils/commandsflags.go index f37b33bcb..2c656a237 100644 --- a/utils/cliutils/commandsflags.go +++ b/utils/cliutils/commandsflags.go @@ -1829,7 +1829,7 @@ var commandFlags = map[string][]string{ }, Docker: { buildName, buildNumber, module, Project, - serverId, skipLogin, threads, detailedSummary, watches, repoPath, licenses, xrOutput, fail, ExtendedTable, BypassArchiveLimits, MinSeverity, FixableOnly, + serverId, skipLogin, threads, detailedSummary, watches, repoPath, licenses, xrOutput, fail, ExtendedTable, BypassArchiveLimits, MinSeverity, FixableOnly, vuln, }, DockerPush: { buildName, buildNumber, module, Project, diff --git a/utils/cliutils/utils.go b/utils/cliutils/utils.go index 5894d023a..f8bc4f592 100644 --- a/utils/cliutils/utils.go +++ b/utils/cliutils/utils.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - "github.com/jfrog/jfrog-cli-core/v2/commandsummary" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary" "io" "net/http" "os"