diff --git a/.github/workflows/pythonTests.yml b/.github/workflows/pythonTests.yml index ccedde64d..926dc4444 100644 --- a/.github/workflows/pythonTests.yml +++ b/.github/workflows/pythonTests.yml @@ -38,6 +38,10 @@ jobs: if: ${{ matrix.suite == 'pipenv' }} run: python -m pip install pipenv + - name: Setup Twine + if: ${{ matrix.suite == 'pip' }} + run: python -m pip install twine + - name: Setup Go with cache uses: jfrog/.github/actions/install-go-with-cache@main diff --git a/Jenkinsfile b/Jenkinsfile index 9a9a552dd..1397513c3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,7 +31,7 @@ node("docker-xxlarge") { repo = 'jfrog-cli' sh 'rm -rf temp' sh 'mkdir temp' - def goRoot = tool 'go-1.22.5' + def goRoot = tool 'go-1.23.1' env.GOROOT="$goRoot" env.PATH+=":${goRoot}/bin:/tmp/node-${nodeVersion}-linux-x64/bin" env.GO111MODULE="on" diff --git a/README.md b/README.md index e50c09c5f..4a7a31fd6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Scanned by Frogbot](https://raw.github.com/jfrog/frogbot/master/images/frogbot-badge.svg)](https://github.com/jfrog/frogbot#readme) [![Go Report Card](https://goreportcard.com/badge/github.com/jfrog/jfrog-cli)](https://goreportcard.com/report/github.com/jfrog/jfrog-cli) [![license](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/jfrog/jfrog-cli/v2/LICENSE) [![](https://img.shields.io/badge/Docs-%F0%9F%93%96-blue)](https://docs.jfrog-applications.jfrog.io/jfrog-applications/jfrog-cli) -[![Go version](https://img.shields.io/github/go-mod/go-version/jfrog/jfrog-cli)](https://tip.golang.org/doc/go1.22) +[![Go version](https://img.shields.io/github/go-mod/go-version/jfrog/jfrog-cli)](https://tip.golang.org/doc/go1.23) diff --git a/build/docker/full/Dockerfile b/build/docker/full/Dockerfile index 289eecb3f..9ba205b95 100644 --- a/build/docker/full/Dockerfile +++ b/build/docker/full/Dockerfile @@ -1,6 +1,6 @@ ARG repo_name_21 # Remove ${repo_name_21} to pull from Docker Hub. -FROM ${repo_name_21}/jfrog-docker/golang:1.22 as builder +FROM ${repo_name_21}/jfrog-docker/golang:1.23 as builder ARG image_name=jfrog-cli-full ARG cli_executable_name WORKDIR /${image_name} diff --git a/build/docker/slim/Dockerfile b/build/docker/slim/Dockerfile index 5233a175c..713051960 100644 --- a/build/docker/slim/Dockerfile +++ b/build/docker/slim/Dockerfile @@ -1,6 +1,6 @@ ARG repo_name_21 # Remove ${repo_name_21} to pull from Docker Hub. -FROM ${repo_name_21}/jfrog-docker/golang:1.22-alpine as builder +FROM ${repo_name_21}/jfrog-docker/golang:1.23.1-alpine as builder ARG image_name=jfrog-cli ARG cli_executable_name WORKDIR /${image_name} diff --git a/build/npm/v2-jf/package-lock.json b/build/npm/v2-jf/package-lock.json index 3ce4d2472..757511226 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.67.0", + "version": "2.68.0", "lockfileVersion": 1 } diff --git a/build/npm/v2-jf/package.json b/build/npm/v2-jf/package.json index 06c48efe5..1489097a4 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.67.0", + "version": "2.68.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 a5a3de881..b912b0afb 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.67.0", + "version": "2.68.0", "lockfileVersion": 2 } diff --git a/build/npm/v2/package.json b/build/npm/v2/package.json index 99087673d..da60ed7d0 100644 --- a/build/npm/v2/package.json +++ b/build/npm/v2/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2", - "version": "2.67.0", + "version": "2.68.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 155717b49..80404a382 100644 --- a/buildtools/cli.go +++ b/buildtools/cli.go @@ -33,6 +33,7 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/scan" terraformdocs "github.com/jfrog/jfrog-cli/docs/artifactory/terraform" "github.com/jfrog/jfrog-cli/docs/artifactory/terraformconfig" + twinedocs "github.com/jfrog/jfrog-cli/docs/artifactory/twine" "github.com/jfrog/jfrog-cli/docs/buildtools/docker" dotnetdocs "github.com/jfrog/jfrog-cli/docs/buildtools/dotnet" "github.com/jfrog/jfrog-cli/docs/buildtools/dotnetconfig" @@ -402,6 +403,18 @@ func GetCommands() []cli.Command { Category: buildToolsCategory, Action: terraformCmd, }, + { + Name: "twine", + Flags: cliutils.GetCommandFlags(cliutils.Twine), + Usage: twinedocs.GetDescription(), + HelpName: corecommon.CreateUsage("twine", twinedocs.GetDescription(), twinedocs.Usage), + UsageText: twinedocs.GetArguments(), + ArgsUsage: common.CreateEnvVars(), + SkipFlagParsing: true, + BashComplete: corecommon.CreateBashCompletionFunc(), + Category: buildToolsCategory, + Action: twineCmd, + }, }) } @@ -410,13 +423,11 @@ func MvnCmd(c *cli.Context) (err error) { return err } - configFilePath, exists, err := project.GetProjectConfFilePath(project.Maven) + configFilePath, err := getProjectConfigPathOrThrow(project.Maven, "mvn", "mvn-config") if err != nil { return err } - if !exists { - return errors.New("no config file was found! Before running the mvn command on a project for the first time, the project should be configured with the mvn-config command") - } + if c.NArg() < 1 { return cliutils.WrongNumberOfArgumentsHandler(c) } @@ -469,13 +480,11 @@ func GradleCmd(c *cli.Context) (err error) { return err } - configFilePath, exists, err := project.GetProjectConfFilePath(project.Gradle) + configFilePath, err := getProjectConfigPathOrThrow(project.Gradle, "gradle", "gradle-config") if err != nil { return err } - if !exists { - return errors.New("no config file was found! Before running the gradle command on a project for the first time, the project should be configured with the gradle-config command") - } + // Found a config file. Continue as native command. if c.NArg() < 1 { return cliutils.WrongNumberOfArgumentsHandler(c) @@ -525,13 +534,10 @@ func YarnCmd(c *cli.Context) error { return err } - configFilePath, exists, err := project.GetProjectConfFilePath(project.Yarn) + configFilePath, err := getProjectConfigPathOrThrow(project.Yarn, "yarn", "yarn-config") if err != nil { return err } - if !exists { - return fmt.Errorf("no config file was found! Before running the yarn command on a project for the first time, the project should be configured using the yarn-config command") - } yarnCmd := yarn.NewYarnCommand().SetConfigFilePath(configFilePath).SetArgs(c.Args()) return commands.Exec(yarnCmd) @@ -544,15 +550,12 @@ func NugetCmd(c *cli.Context) error { if c.NArg() < 1 { return cliutils.WrongNumberOfArgumentsHandler(c) } - configFilePath, exists, err := project.GetProjectConfFilePath(project.Nuget) + + configFilePath, err := getProjectConfigPathOrThrow(project.Nuget, "nuget", "nuget-config") if err != nil { return err } - if !exists { - return fmt.Errorf("no config file was found! Before running the nuget command on a project for the first time, the project should be configured using the nuget-config command") - } - rtDetails, targetRepo, useNugetV2, err := getNugetAndDotnetConfigFields(configFilePath) if err != nil { return err @@ -584,13 +587,10 @@ func DotnetCmd(c *cli.Context) error { } // Get configuration file path. - configFilePath, exists, err := project.GetProjectConfFilePath(project.Dotnet) + configFilePath, err := getProjectConfigPathOrThrow(project.Dotnet, "dotnet", "dotnet-config") if err != nil { return err } - if !exists { - return fmt.Errorf("no config file was found! Before running the dotnet command on a project for the first time, the project should be configured using the dotnet-config command") - } rtDetails, targetRepo, useNugetV2, err := getNugetAndDotnetConfigFields(configFilePath) if err != nil { @@ -690,14 +690,12 @@ func goCmdVerification(c *cli.Context) (string, error) { if c.NArg() < 1 { return "", cliutils.WrongNumberOfArgumentsHandler(c) } - configFilePath, exists, err := project.GetProjectConfFilePath(project.Go) + + configFilePath, err := getProjectConfigPathOrThrow(project.Go, "go", "go-config") if err != nil { return "", err } - // Verify config file is found. - if !exists { - return "", fmt.Errorf("no config file was found! Before running the go command on a project for the first time, the project should be configured using the go-config command") - } + log.Debug("Go config file was found in:", configFilePath) return configFilePath, nil } @@ -887,13 +885,9 @@ func NpmPublishCmd(c *cli.Context) (err error) { } func GetNpmConfigAndArgs(c *cli.Context) (configFilePath string, args []string, err error) { - configFilePath, exists, err := project.GetProjectConfFilePath(project.Npm) + configFilePath, err = getProjectConfigPathOrThrow(project.Npm, "npm", "npm-config") if err != nil { - return "", nil, err - } - - if !exists { - return "", nil, errorutils.CheckErrorf("no config file was found! Before running the npm command on a project for the first time, the project should be configured using the npm-config command") + return } _, args = getCommandName(c.Args()) return @@ -970,13 +964,9 @@ func terraformCmd(c *cli.Context) error { } func getTerraformConfigAndArgs(c *cli.Context) (configFilePath string, args []string, err error) { - configFilePath, exists, err := project.GetProjectConfFilePath(project.Terraform) + configFilePath, err = getProjectConfigPathOrThrow(project.Terraform, "terraform", "terraform-config") if err != nil { - return "", nil, err - } - - if !exists { - return "", nil, errors.New("no config file was found! Before running the terraform command on a project for the first time, the project should be configured using the terraform-config command") + return } args = cliutils.ExtractCommand(c) return @@ -992,3 +982,63 @@ func terraformPublishCmd(configFilePath string, args []string, c *cli.Context) e result := terraformCmd.Result() return cliutils.PrintBriefSummaryReport(result.SuccessCount(), result.FailCount(), cliutils.IsFailNoOp(c), err) } + +func getProjectConfigPathOrThrow(projectType project.ProjectType, cmdName, configCmdName string) (configFilePath string, err error) { + configFilePath, exists, err := project.GetProjectConfFilePath(projectType) + if err != nil { + return + } + if !exists { + return "", errorutils.CheckErrorf(getMissingConfigErrMsg(cmdName, configCmdName)) + } + return +} + +func getMissingConfigErrMsg(cmdName, configCmdName string) string { + return fmt.Sprintf("no config file was found! Before running the 'jf %s' command on a project for the first time, the project should be configured with the 'jf %s' command", cmdName, configCmdName) +} + +func twineCmd(c *cli.Context) error { + if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil { + return err + } + serverDetails, targetRepo, err := getTwineConfigAndArgs() + if err != nil { + return err + } + cmdName, filteredArgs := getCommandName(cliutils.ExtractCommand(c)) + return python.NewTwineCommand(cmdName).SetServerDetails(serverDetails).SetTargetRepo(targetRepo).SetArgs(filteredArgs).Run() +} + +func getTwineConfigAndArgs() (serverDetails *coreConfig.ServerDetails, targetRepo string, err error) { + configFilePath, err := getTwineConfigPath() + if err != nil { + return + } + + vConfig, err := project.ReadConfigFile(configFilePath, project.YAML) + if err != nil { + return nil, "", fmt.Errorf("failed while reading configuration file '%s'. Error: %s", configFilePath, err.Error()) + } + projectConfig, err := project.GetRepoConfigByPrefix(configFilePath, project.ProjectConfigDeployerPrefix, vConfig) + if err != nil { + return nil, "", err + } + serverDetails, err = projectConfig.ServerDetails() + if err != nil { + return nil, "", err + } + targetRepo = projectConfig.TargetRepo() + return +} + +func getTwineConfigPath() (configFilePath string, err error) { + var exists bool + for _, projectType := range []project.ProjectType{project.Pip, project.Pipenv} { + configFilePath, exists, err = project.GetProjectConfFilePath(projectType) + if err != nil || exists { + return + } + } + return "", errorutils.CheckErrorf(getMissingConfigErrMsg("twine", "pip-config OR pipenv-config")) +} diff --git a/docs/artifactory/twine/help.go b/docs/artifactory/twine/help.go new file mode 100644 index 000000000..9fb5af93d --- /dev/null +++ b/docs/artifactory/twine/help.go @@ -0,0 +1,12 @@ +package twinedocs + +var Usage = []string{"twine [command options]"} + +func GetDescription() string { + return "Runs twine " +} + +func GetArguments() string { + return ` twine commands + Arguments and options for the twine command.` +} diff --git a/general/ai/cli.go b/general/ai/cli.go index 979fadac1..a7e1c5b27 100644 --- a/general/ai/cli.go +++ b/general/ai/cli.go @@ -12,6 +12,7 @@ import ( "github.com/jfrog/jfrog-client-go/http/httpclient" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/manifoldco/promptui" "github.com/urfave/cli" "io" "net/http" @@ -22,13 +23,16 @@ import ( type ApiCommand string const ( - cliAiAskApiPath = "https://cli-ai-app.jfrog.info/api/ask" - apiHeader = "X-JFrog-CLI-AI" + cliAiAppApiUrl = "https://cli-ai-app-stg.jfrog.info/api/" + askRateLimitHeader = "X-JFrog-CLI-AI" ) -type QuestionBody struct { - Question string `json:"question"` -} +type ApiType string + +const ( + ask ApiType = "ask" + feedback ApiType = "feedback" +) func HowCmd(c *cli.Context) error { if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil { @@ -37,7 +41,7 @@ func HowCmd(c *cli.Context) error { if c.NArg() > 0 { return cliutils.WrongNumberOfArgumentsHandler(c) } - log.Output(coreutils.PrintTitle("This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands.\n" + + log.Output(coreutils.PrintLink("This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands.\n" + "NOTE: This is an experimental version and it supports mostly Artifactory and Xray commands.\n")) for { @@ -53,18 +57,68 @@ func HowCmd(c *cli.Context) error { break } } - fmt.Print("\nšŸ¤– Generated command:\n ") + fmt.Print("\nšŸ¤– Generated command:\n") llmAnswer, err := askQuestion(question) if err != nil { return err } - log.Output(coreutils.PrintLink(llmAnswer)) + // Print the generated command within a styled table frame. + coreutils.PrintMessageInsideFrame(coreutils.PrintBoldTitle(llmAnswer), " ") + + log.Output() + if err = sendFeedback(); err != nil { + return err + } + log.Output("\n" + coreutils.PrintComment("-------------------") + "\n") } } +type questionBody struct { + Question string `json:"question"` +} + func askQuestion(question string) (response string, err error) { - contentBytes, err := json.Marshal(QuestionBody{Question: question}) + return sendRestAPI(ask, questionBody{Question: question}) +} + +type feedbackBody struct { + IsGoodResponse bool `json:"is_good_response"` +} + +func sendFeedback() (err error) { + isGoodResponse, err := getUserFeedback() + if err != nil { + return err + } + _, err = sendRestAPI(feedback, feedbackBody{IsGoodResponse: isGoodResponse}) + return err +} + +func getUserFeedback() (bool, error) { + // Customize the template to place the options on the same line as the question + templates := &promptui.SelectTemplates{ + Label: "{{ . }}", + Active: " šŸ‘‰ {{ . | cyan }}", + Inactive: " {{ . }}", + Selected: "šŸ™ Thanks for your feedback!", + } + + prompt := promptui.Select{ + Label: "ā­ Rate this response:", + Items: []string{"šŸ‘ Good response!", "šŸ‘Ž Could be better..."}, + Templates: templates, + HideHelp: true, + } + selected, _, err := prompt.Run() + if err != nil { + return false, err + } + return selected == 0, nil +} + +func sendRestAPI(apiType ApiType, content interface{}) (response string, err error) { + contentBytes, err := json.Marshal(content) if errorutils.CheckError(err) != nil { return } @@ -72,12 +126,14 @@ func askQuestion(question string) (response string, err error) { if errorutils.CheckError(err) != nil { return } - req, err := http.NewRequest(http.MethodPost, cliAiAskApiPath, bytes.NewBuffer(contentBytes)) + req, err := http.NewRequest(http.MethodPost, cliAiAppApiUrl+string(apiType), bytes.NewBuffer(contentBytes)) if errorutils.CheckError(err) != nil { return } req.Header.Set("Content-Type", "application/json") - req.Header.Set(apiHeader, "true") + if apiType == ask { + req.Header.Set(askRateLimitHeader, "true") + } log.Debug(fmt.Sprintf("Sending HTTP %s request to: %s", req.Method, req.URL)) resp, err := client.GetClient().Do(req) if err != nil { @@ -100,6 +156,12 @@ func askQuestion(question string) (response string, err error) { } return } + + if apiType == feedback { + // If the API is feedback, no response is expected + return + } + defer func() { if resp.Body != nil { err = errors.Join(err, errorutils.CheckError(resp.Body.Close())) diff --git a/go.mod b/go.mod index f97e42df8..c5fbbaaab 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jfrog/jfrog-cli -go 1.22.3 +go 1.23.1 replace ( // Should not be updated to 0.2.6 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372) @@ -13,22 +13,23 @@ replace ( require ( github.com/agnivade/levenshtein v1.1.1 github.com/buger/jsonparser v1.1.1 - github.com/docker/docker v27.1.2+incompatible + github.com/docker/docker v27.2.1+incompatible github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jfrog/archiver/v3 v3.6.1 - github.com/jfrog/build-info-go v1.9.35 - github.com/jfrog/gofrog v1.7.5 + github.com/jfrog/build-info-go v1.10.0 + github.com/jfrog/gofrog v1.7.6 github.com/jfrog/jfrog-cli-artifactory v0.1.6 - github.com/jfrog/jfrog-cli-core/v2 v2.55.7 + github.com/jfrog/jfrog-cli-core/v2 v2.56.0 github.com/jfrog/jfrog-cli-platform-services v1.3.0 - github.com/jfrog/jfrog-cli-security v1.8.0 - github.com/jfrog/jfrog-client-go v1.46.1 + github.com/jfrog/jfrog-cli-security v1.9.0 + github.com/jfrog/jfrog-client-go v1.47.0 github.com/jszwec/csvutil v1.10.0 + github.com/manifoldco/promptui v0.9.0 github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.33.0 github.com/urfave/cli v1.22.15 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 gopkg.in/yaml.v2 v2.4.0 ) @@ -59,7 +60,6 @@ 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 @@ -94,7 +94,6 @@ require ( github.com/ktrysmt/go-bitbucket v0.9.73 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect @@ -155,14 +154,14 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.28.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.34.2 // indirect @@ -171,12 +170,12 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -// 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-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20240918150651-0d4ff6b567ce // replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20240904061406-f368939ce3a0 -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240806162439-01bb7dcd43fc +// 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 dev diff --git a/go.sum b/go.sum index 6c23b575e..f04c83146 100644 --- a/go.sum +++ b/go.sum @@ -707,8 +707,8 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.1.2+incompatible h1:AhGzR1xaQIy53qCkxARaFluI00WPGtXn0AJuoQsVYTY= -github.com/docker/docker v27.1.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -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.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +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/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= @@ -931,24 +931,24 @@ 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/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/froggit-go v1.16.1 h1:FBIM1qevX/ag9unfmpGzfmZ36D8ulOJ+DPTSFUk3l5U= github.com/jfrog/froggit-go v1.16.1/go.mod h1:TEJSzgiV+3D/GVGE8Y6j46ut1jrBLD1FL6WdMdKwwCE= -github.com/jfrog/gofrog v1.7.5 h1:dFgtEDefJdlq9cqTRoe09RLxS5Bxbe1Ev5+E6SmZHcg= -github.com/jfrog/gofrog v1.7.5/go.mod h1:jyGiCgiqSSR7k86hcUSu67XVvmvkkgWTmPsH25wI298= +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-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY= 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.7 h1:V4dO2FMNIH49lov3dMj3jYRg8KBTG7hyhHI8ftYByf8= -github.com/jfrog/jfrog-cli-core/v2 v2.55.7/go.mod h1:DPO5BfWAeOByahFMMy+PcjmbPlcyoRy7Bf2C5sGKVi0= +github.com/jfrog/jfrog-cli-core/v2 v2.56.0 h1:rCNKhfESgsq0o6//gU1mNCvuCboE5BMfycj/RM/gq8k= +github.com/jfrog/jfrog-cli-core/v2 v2.56.0/go.mod h1:D8m0L8GCZiYCY9MjhnWY4egCqyVlU2iZsVA0yysBsVw= 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.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/jfrog/jfrog-cli-security v1.9.0 h1:D98FqJlavmxI5FNln1+Y6W1944dxVd/b59cI8orlaLE= +github.com/jfrog/jfrog-cli-security v1.9.0/go.mod h1:QIHSX8FiuQWYtM6e0JPaREldPk8goNpUFtu9ZF2oG+U= +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/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= @@ -1232,8 +1232,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -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/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-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1249,8 +1249,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -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/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/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1293,8 +1293,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1356,8 +1356,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1503,8 +1503,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1516,8 +1516,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1535,8 +1535,8 @@ 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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1608,8 +1608,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -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= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pip_test.go b/pip_test.go index 34267df70..c4199eded 100644 --- a/pip_test.go +++ b/pip_test.go @@ -166,7 +166,11 @@ func assertDependencyChecksums(t *testing.T, checksum buildinfo.Checksum) { } func createPipProject(t *testing.T, outFolder, projectName string) string { - projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "pip", projectName) + return createPypiProject(t, outFolder, projectName, "pip") +} + +func createPypiProject(t *testing.T, outFolder, projectName, projectSrcDir string) string { + projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), projectSrcDir, projectName) projectTarget := filepath.Join(tests.Out, outFolder+"-"+projectName) err := fileutils.CreateDirIfNotExist(projectTarget) assert.NoError(t, err) @@ -176,7 +180,7 @@ func createPipProject(t *testing.T, outFolder, projectName string) string { assert.NoError(t, err) // Copy pip-config file. - configSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "pip", "pip.yaml") + configSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), projectSrcDir, "pip.yaml") configTarget := filepath.Join(projectTarget, ".jfrog", "projects") _, err = tests.ReplaceTemplateVariables(configSrc, configTarget) assert.NoError(t, err) @@ -187,6 +191,80 @@ func initPipTest(t *testing.T) { if !*tests.TestPip { t.Skip("Skipping Pip test. To run Pip test add the '-test.pip=true' option.") } + require.True(t, isRepoExist(tests.PypiLocalRepo), "Pypi test local repository doesn't exist.") require.True(t, isRepoExist(tests.PypiRemoteRepo), "Pypi test remote repository doesn't exist.") require.True(t, isRepoExist(tests.PypiVirtualRepo), "Pypi test virtual repository doesn't exist.") } + +func TestTwine(t *testing.T) { + // Init pip. + initPipTest(t) + + // Populate cli config with 'default' server. + oldHomeDir, newHomeDir := prepareHomeDir(t) + defer func() { + clientTestUtils.SetEnvAndAssert(t, coreutils.HomeDir, oldHomeDir) + clientTestUtils.RemoveAllAndAssert(t, newHomeDir) + }() + + // Create test cases. + allTests := []struct { + name string + project string + outputFolder string + expectedModuleId string + args []string + expectedArtifacts int + }{ + {"twine", "pyproject", "twine", "jfrog-python-example:1.0", []string{}, 2}, + {"twine-with-module", "pyproject", "twine-with-module", "twine-with-module", []string{"--module=twine-with-module"}, 2}, + } + + // Run test cases. + for testNumber, test := range allTests { + t.Run(test.name, func(t *testing.T) { + cleanVirtualEnv, err := prepareVirtualEnv(t) + assert.NoError(t, err) + + buildNumber := strconv.Itoa(100 + testNumber) + test.args = append([]string{"twine", "upload", "dist/*", "--build-name=" + tests.PipBuildName, "--build-number=" + buildNumber}, test.args...) + testTwineCmd(t, createPypiProject(t, test.outputFolder, test.project, "twine"), buildNumber, test.expectedModuleId, test.expectedArtifacts, test.args) + + // cleanup + cleanVirtualEnv() + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.PipBuildName, artHttpDetails) + }) + } +} + +func testTwineCmd(t *testing.T, projectPath, buildNumber, expectedModuleId string, expectedArtifacts int, args []string) { + wd, err := os.Getwd() + assert.NoError(t, err, "Failed to get current dir") + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + err = jfrogCli.Exec(args...) + if err != nil { + assert.Fail(t, "Failed executing twine upload command", err.Error()) + return + } + + assert.NoError(t, artifactoryCli.Exec("bp", tests.PipBuildName, buildNumber)) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.PipBuildName, buildNumber) + if err != nil { + assert.NoError(t, err) + return + } + if !found { + assert.True(t, found, "build info was expected to be found") + return + } + buildInfo := publishedBuildInfo.BuildInfo + require.Len(t, buildInfo.Modules, 1) + twineModule := buildInfo.Modules[0] + assert.Equal(t, buildinfo.Python, twineModule.Type) + assert.Len(t, twineModule.Artifacts, expectedArtifacts) + assert.Equal(t, expectedModuleId, twineModule.Id) +} diff --git a/testdata/pypi_local_repository_config.json b/testdata/pypi_local_repository_config.json new file mode 100644 index 000000000..ab4952816 --- /dev/null +++ b/testdata/pypi_local_repository_config.json @@ -0,0 +1,5 @@ +{ + "key": "${PYPI_LOCAL_REPO}", + "rclass": "local", + "packageType": "pypi" +} diff --git a/testdata/pypi_virtual_repository_config.json b/testdata/pypi_virtual_repository_config.json index 574fad282..0c8a751d0 100644 --- a/testdata/pypi_virtual_repository_config.json +++ b/testdata/pypi_virtual_repository_config.json @@ -2,5 +2,6 @@ "key": "${PYPI_VIRTUAL_REPO}", "rclass": "virtual", "packageType": "pypi", - "repositories": ["${PYPI_REMOTE_REPO}"] + "repositories": ["${PYPI_REMOTE_REPO}", "${PYPI_LOCAL_REPO}"], + "defaultDeploymentRepo": "${PYPI_LOCAL_REPO}" } diff --git a/testdata/twine/pip.yaml b/testdata/twine/pip.yaml new file mode 100644 index 000000000..226862f66 --- /dev/null +++ b/testdata/twine/pip.yaml @@ -0,0 +1,8 @@ +version: 1 +type: pip +resolver: + repo: ${PYPI_VIRTUAL_REPO} + serverId: default +deployer: + repo: ${PYPI_VIRTUAL_REPO} + serverId: default \ No newline at end of file diff --git a/testdata/twine/pyproject/dist/jfrog_python_example-1.0-py3-none-any.whl b/testdata/twine/pyproject/dist/jfrog_python_example-1.0-py3-none-any.whl new file mode 100644 index 000000000..be3eea646 Binary files /dev/null and b/testdata/twine/pyproject/dist/jfrog_python_example-1.0-py3-none-any.whl differ diff --git a/testdata/twine/pyproject/dist/jfrog_python_example-1.0.tar.gz b/testdata/twine/pyproject/dist/jfrog_python_example-1.0.tar.gz new file mode 100644 index 000000000..657cf23e5 Binary files /dev/null and b/testdata/twine/pyproject/dist/jfrog_python_example-1.0.tar.gz differ diff --git a/testdata/twine/pyproject/pyproject.toml b/testdata/twine/pyproject/pyproject.toml new file mode 100644 index 000000000..792971df4 --- /dev/null +++ b/testdata/twine/pyproject/pyproject.toml @@ -0,0 +1,15 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "jfrog-python-example" +version = "1.0" +description = "Project example for building Python project with JFrog products" +authors = [ + { name="JFrog", email="jfrog@jfrog.com" } +] +dependencies = [ + "PyYAML>3.11", + "nltk" +] diff --git a/utils/cliutils/cli_consts.go b/utils/cliutils/cli_consts.go index c830e94bb..80bb1f5ce 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.67.0" + CliVersion = "2.68.0" ClientAgent = "jfrog-cli-go" // CLI base commands constants: diff --git a/utils/cliutils/commandsflags.go b/utils/cliutils/commandsflags.go index 2c656a237..787068a53 100644 --- a/utils/cliutils/commandsflags.go +++ b/utils/cliutils/commandsflags.go @@ -66,6 +66,7 @@ const ( PipConfig = "pip-config" TerraformConfig = "terraform-config" Terraform = "terraform" + Twine = "twine" Pipenv = "pipenv" PipenvConfig = "pipenv-config" PipenvInstall = "pipenv-install" @@ -1897,6 +1898,9 @@ var commandFlags = map[string][]string{ namespace, provider, tag, exclusions, buildName, buildNumber, module, Project, }, + Twine: { + buildName, buildNumber, module, Project, + }, TransferConfig: { Force, Verbose, IncludeRepos, ExcludeRepos, SourceWorkingDir, TargetWorkingDir, PreChecks, }, @@ -1911,13 +1915,13 @@ var commandFlags = map[string][]string{ serverId, }, PipConfig: { - global, serverIdResolve, repoResolve, + global, serverIdResolve, serverIdDeploy, repoResolve, repoDeploy, }, PipInstall: { buildName, buildNumber, module, Project, }, PipenvConfig: { - global, serverIdResolve, repoResolve, + global, serverIdResolve, serverIdDeploy, repoResolve, repoDeploy, }, PipenvInstall: { buildName, buildNumber, module, Project, diff --git a/utils/tests/consts.go b/utils/tests/consts.go index de4152d01..e9d88bab9 100644 --- a/utils/tests/consts.go +++ b/utils/tests/consts.go @@ -94,6 +94,7 @@ const ( PipenvVirtualRepositoryConfig = "pipenv_virtual_repository_config.json" ProdRepo1RepositoryConfig = "prod_repo1_repository_config.json" ProdRepo2RepositoryConfig = "prod_repo2_repository_config.json" + PypiLocalRepositoryConfig = "pypi_local_repository_config.json" PypiRemoteRepositoryConfig = "pypi_remote_repository_config.json" PypiVirtualRepositoryConfig = "pypi_virtual_repository_config.json" ReplicationTempCreate = "replication_push_create.json" @@ -182,6 +183,7 @@ var ( NpmRemoteRepo = "cli-npm-remote" NugetRemoteRepo = "cli-nuget-remote" YarnRemoteRepo = "cli-yarn-remote" + PypiLocalRepo = "cli-pypi-local" PypiRemoteRepo = "cli-pypi-remote" PypiVirtualRepo = "cli-pypi-virtual" PipenvRemoteRepo = "cli-pipenv-pypi-remote" diff --git a/utils/tests/utils.go b/utils/tests/utils.go index e1e6b6396..91f3cdd6b 100644 --- a/utils/tests/utils.go +++ b/utils/tests/utils.go @@ -255,6 +255,7 @@ var reposConfigMap = map[*string]string{ &NpmRemoteRepo: NpmRemoteRepositoryConfig, &NugetRemoteRepo: NugetRemoteRepositoryConfig, &YarnRemoteRepo: YarnRemoteRepositoryConfig, + &PypiLocalRepo: PypiLocalRepositoryConfig, &PypiRemoteRepo: PypiRemoteRepositoryConfig, &PypiVirtualRepo: PypiVirtualRepositoryConfig, &PipenvRemoteRepo: PipenvRemoteRepositoryConfig, @@ -316,7 +317,7 @@ func GetNonVirtualRepositories() map[*string]string { TestMaven: {&MvnRepo1, &MvnRepo2, &MvnRemoteRepo}, TestNpm: {&NpmRepo, &NpmRemoteRepo}, TestNuget: {&NugetRemoteRepo}, - TestPip: {&PypiRemoteRepo}, + TestPip: {&PypiLocalRepo, &PypiRemoteRepo}, TestPipenv: {&PipenvRemoteRepo}, TestPlugins: {&RtRepo1}, TestXray: {&NpmRemoteRepo, &NugetRemoteRepo, &YarnRemoteRepo, &GradleRemoteRepo, &MvnRemoteRepo, &GoRepo, &GoRemoteRepo, &PypiRemoteRepo}, @@ -421,6 +422,7 @@ func getSubstitutionMap() map[string]string { "${PASSWORD}": *JfrogPassword, "${RT_CREDENTIALS_BASIC_AUTH}": base64.StdEncoding.EncodeToString([]byte(*JfrogUser + ":" + *JfrogPassword)), "${ACCESS_TOKEN}": *JfrogAccessToken, + "${PYPI_LOCAL_REPO}": PypiLocalRepo, "${PYPI_REMOTE_REPO}": PypiRemoteRepo, "${PYPI_VIRTUAL_REPO}": PypiVirtualRepo, "${PIPENV_REMOTE_REPO}": PipenvRemoteRepo, @@ -479,6 +481,7 @@ func AddTimestampToGlobalVars() { NpmRemoteRepo += uniqueSuffix NugetRemoteRepo += uniqueSuffix YarnRemoteRepo += uniqueSuffix + PypiLocalRepo += uniqueSuffix PypiRemoteRepo += uniqueSuffix PypiVirtualRepo += uniqueSuffix PipenvRemoteRepo += uniqueSuffix