diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f10575440..cca3d0c4e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,6 @@ -- [ ] All [tests](https://github.com/jfrog/jfrog-cli#tests) passed. If this feature is not already covered by the tests, I added new tests. -- [ ] All [static analysis checks](https://github.com/jfrog/jfrog-cli/actions/workflows/analysis.yml) passed. -- [ ] This pull request is on the dev branch. -- [ ] I used gofmt for formatting the code before submitting the pull request. ------ +- [ ] All [tests](https://github.com/jfrog/jfrog-cli/CONTRIBUTING.md#tests) have passed. If this feature is not already covered by the tests, new tests have been added. +- [ ] The pull request is targeting the `dev` branch. +- [ ] The code has been validated to compile successfully by running `go vet ./...`. +- [ ] The code has been formatted properly using `go fmt ./...`. + +--- diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 69e89ffe3..d3957b0d4 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -34,6 +34,7 @@ jobs: restore-keys: ${{ runner.os }}-go - name: Run Go vet run: go vet -v ./... + Static-Check: name: Static Check ubuntu-latest runs-on: ubuntu-latest @@ -45,9 +46,11 @@ jobs: with: go-version: 1.20.x - name: Static Code Analysis - uses: dominikh/staticcheck-action@v1 + uses: golangci/golangci-lint-action@v3 with: - install-go: false + args: | + --timeout 5m --out-${NO_FUTURE}format colored-line-number --enable errcheck,gosimple,govet,ineffassign,staticcheck,typecheck,unused,gocritic,asasalint,asciicheck,errchkjson,exportloopref,forcetypeassert,makezero,nilerr,unparam,unconvert,wastedassign,usestdlibvars + Go-Sec: name: Go-Sec ubuntu-latest runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..d9bd3949d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,297 @@ +# ๐Ÿ“– Guidelines + +- Ensure that your changes are covered by existing tests. If not, please add new tests. +- Create pull requests on the `dev` branch. +- Before submitting the pull request, format the code by running `go fmt ./...`. +- Before submitting the pull request, ensure the code compiles by running `go vet ./...`. + +# โš’๏ธ Building and Testing the Sources + +## Building JFrog CLI + +To build JFrog CLI, first, make sure Go is installed by running the following command: + +```sh +go version +``` + +Next, clone the project sources and navigate to the root directory: + +```sh +git clone https://github.com/jfrog/jfrog-cli.git +cd jfrog-cli +``` + +To build the sources on Unix-based systems, run: + +```sh +./build/build.sh +``` + +On Windows, run: + +```sh +.\build\build.bat +``` + +After the build process completes, you will find the `jf` or `jf.exe` executable in the current directory. + +### Dependencies in other JFrog modules + +This project heavily depends on the following modules: + +- [github.com/jfrog/jfrog-client-go](https://github.com/jfrog/jfrog-client-go) +- [github.com/jfrog/jfrog-cli-core](github.com/jfrog/jfrog-cli-core) +- [github.com/jfrog/build-info-go](github.com/jfrog/build-info-go) +- [github.com/jfrog/gofrog](github.com/jfrog/gofrog) + +#### Local Development + +During local development, if you come across code that needs to be modified in one of the mentioned modules, it is advisable to replace the dependency with a local clone of the module. + +For instance, let's assume you wish to modify files from `jfrog-cli-core`. Clone the `jfrog-cli-core` repository (preferably your fork) to your local development machine, placing it at `/local/path/in/your/machine/jfrog-cli-core`. + +To include this local dependency, modify the `go.mod` file as follows: + +``` +replace github.com/jfrog/jfrog-cli-core/v2 => /local/path/in/your/machine/jfrog-cli-core +``` + +Afterward, execute `go mod tidy` to ensure the Go module files are updated. Note that Go will automatically adjust the version in the `go.mod` file. + +#### Pull Requests + +Once you have completed your coding changes, it is recommended to push the modifications made to the other modules first. Once these changes are pushed, you can update this project to resolve dependencies from your GitHub fork or branch. To achieve this, modify the `go.mod` file to point the dependency to your repository and branch, as shown in the example below: + +``` +replace github.com/jfrog/jfrog-cli-core/v2 => github.com/galusben/jfrog-cli-core/v2 dev +``` + +Finally, execute `go mod tidy` to update the Go module files. Please note that Go will automatically update the version in the `go.mod` file. + +## Tests + +### Usage + +To run tests, use the following command: + +``` +go test -v github.com/jfrog/jfrog-cli [test-types] [flags] +``` + +The available flags are: + +| Flag | Description | +| ------------------- | ----------------------------------------------------------------------------------------------- | +| `-jfrog.url` | [Default: http://localhost:8081] JFrog platform URL | +| `-jfrog.user` | [Default: admin] JFrog platform username | +| `-jfrog.password` | [Default: password] JFrog platform password | +| `-jfrog.adminToken` | [Optional] JFrog platform admin token | +| `-ci.runId` | [Optional] A unique identifier used as a suffix to create repositories and builds in the tests. | + +The available test types are: + +| Type | Description | +| -------------------- | ------------------ | +| `-test.artifactory` | Artifactory tests | +| `-test.access` | Access tests | +| `-test.npm` | Npm tests | +| `-test.maven` | Maven tests | +| `-test.gradle` | Gradle tests | +| `-test.docker` | Docker tests | +| `-test.dockerScan` | Docker scan tests | +| `-test.podman` | Podman tests | +| `-test.go` | Go tests | +| `-test.pip` | Pip tests | +| `-test.pipenv` | Pipenv tests | +| `-test.poetry` | Poetry tests | +| `-test.nuget` | Nuget tests | +| `-test.plugins` | Plugins tests | +| `-test.distribution` | Distribution tests | +| `-test.transfer` | Transfer tests | +| `-test.xray` | Xray tests | + +When running the tests, builds and repositories with timestamps will be created, for example: `cli-rt1-1592990748` and `cli-rt2-1592990748`. The content of these repositories will be deleted once the tests are completed. + +#### Artifactory tests + +In addition to the [general optional flags](#Usage), you can use the following optional Artifactory flags: + +| Flag | Description | +| ---------------------- | --------------------------------------------------------------------------------------------------------------- | +| `-jfrog.sshKeyPath` | [Optional] Path to the SSH key file. Use this flag only if the Artifactory URL format is `ssh://[domain]:port`. | +| `-jfrog.sshPassphrase` | [Optional] Passphrase for the SSH key. | + +##### Examples + +To run Artifactory tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.artifactory [flags] +``` + +#### Npm tests + +##### Requirements + +- The _npm_ executables should be included in the system's `PATH` environment variable. +- The tests are compatible with npm 7 and higher. + +##### Limitations + +- Currently, npm integration only supports HTTP(S) connections to Artifactory using username and password. + +##### Examples + +To run Npm tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.npm [flags] +``` + +#### Maven tests + +##### Requirements + +- The _java_ executable should be included in the system's `PATH` environment variable. Alternatively, set the `_JAVA_HOME` environment variable. + +##### Limitations + +- Currently, Maven integration only supports HTTP(S) connections to Artifactory using username and password. + +##### Examples + +To run Maven tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.maven [flags] +``` + +#### Gradle tests + +##### Requirements + +- The _gradle_ and _java_ executables should be included in the system's `PATH` environment variable. Alternatively, set the `JAVA_HOME` environment variable. + +##### Limitations + +- Currently, Gradle integration only supports HTTP(S) connections to Artifactory using username and password. + +##### Examples + +To run Gradle tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.gradle [flags] +``` + +#### Docker tests + +##### Requirements + +- Make sure the `RTLIC` environment variable is configured with a valid license. +- You can start an Artifactory container by running the `startArtifactory.sh` script located in the `testdata/docker/artifactory` directory. Before running the tests, wait for Artifactory to finish booting up in the container. + +| Flag | Description | +| ------------------------- | ----------------------------------- | +| `-test.containerRegistry` | Artifactory Docker registry domain. | + +##### Examples + +To run Docker tests, execute the following command (replace the missing parameters as described below): + +``` +go test -v github.com/jfrog/jfrog-cli -test.docker [flags] +``` + +#### Podman tests + +| Flag | Description | +| ------------------------- | -------------------------------------- | +| `-test.containerRegistry` | Artifactory container registry domain. | + +##### Examples + +To run Podman tests, execute the following command (replace the missing parameters as described below): + +``` +go test -v github.com/jfrog/jfrog-cli -test.podman [flags] +``` + +#### Go commands tests + +##### + +Requirements + +- The tests are compatible with Artifactory 6.10 and higher. +- To run Go tests, use the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.go [flags] +``` + +#### NuGet tests + +##### Requirements + +- Add the NuGet executable to the system's `PATH` environment variable. +- Run the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.nuget [flags] +``` + +#### Pip tests + +##### Requirements + +- Add the Python and pip executables to the system's `PATH` environment variable. +- Run the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.pip [flags] +``` + +#### Plugins tests + +To run Plugins tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.plugins +``` + +#### Distribution tests + +To run Distribution tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.distribution [flags] +``` + +#### Transfer tests + +##### Requirement + +The Transfer tests execute `transfer-files` commands between a local Artifactory server and a remote SaaS instance. In addition to the [general optional flags](#Usage), you _must_ use the following flags: + +| Flag | Description | +| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `-jfrog.targetUrl` | JFrog target platform URL. | +| `-jfrog.targetAdminToken` | JFrog target platform admin token. | +| `-jfrog.jfrogHome` | The JFrog home directory of the local Artifactory installation. | +| `-jfrog.installDataTransferPlugin` | Set this flag to `true` if you want the test to automatically install the data-transfer plugin in the source Artifactory server. | + +To run Transfer tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.transfer [flags] +``` + +### Xray tests + +To run Xray tests, execute the following command: + +``` +go test -v github.com/jfrog/jfrog-cli -test.xray -test.dockerScan [flags] +``` diff --git a/Jenkinsfile b/Jenkinsfile index b06ee2698..3140b8ea2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -25,7 +25,7 @@ node("docker") { repo = 'jfrog-cli' sh 'rm -rf temp' sh 'mkdir temp' - def goRoot = tool 'go-1.20.4' + def goRoot = tool 'go-1.20.5' env.GOROOT="$goRoot" env.PATH+=":${goRoot}/bin" env.GO111MODULE="on" @@ -133,7 +133,7 @@ def runRelease(architectures) { } } if (identifier == "v2") { - createTagAndRelease() + createTag() } } } finally { @@ -141,7 +141,7 @@ def runRelease(architectures) { } } -def createTagAndRelease() { +def createTag() { stage('Create a tag and a GitHub release') { dir("$jfrogCliRepoDir") { releaseTag = "v$RELEASE_VERSION" @@ -149,13 +149,6 @@ def createTagAndRelease() { sh """#!/bin/bash git tag $releaseTag git push "https://$GITHUB_ACCESS_TOKEN@github.com/jfrog/jfrog-cli.git" --tags - curl -L \ - -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN"\ - -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/jfrog/jfrog-cli/releases \ - -d '{"tag_name":"$releaseTag","target_commitish":"$BRANCH","name":"$RELEASE_VERSION","generate_release_notes":true}' """ } } @@ -418,9 +411,9 @@ def publishNpmPackage(jfrogCliRepoDir) { } def publishChocoPackageWithRetries(version, jfrogCliRepoDir, architectures) { - def maxAttempts = 3 + def maxAttempts = 10 def currentAttempt = 1 - def waitSeconds = 20 + def waitSeconds = 18 while (currentAttempt <= maxAttempts) { try { diff --git a/README.md b/README.md index c6112be75..16955cb4e 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ [![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://www.jfrog.com/confluence/display/CLI/JFrog+CLI) [![Go version](https://img.shields.io/github/go-mod/go-version/jfrog/jfrog-cli)](https://tip.golang.org/doc/go1.20) +
@@ -235,8 +236,6 @@ - [Overview](#overview) - [Download and Installation](#download-and-installation) -- [Building the Executable](#building-the-executable) -- [Tests](#tests) - [Code Contributions](#code-contributions) - [Using JFrog CLI](#using-jfrog-cli) - [JFrog CLI Plugins](#jfrog-cli-plugins) @@ -260,325 +259,9 @@ Several features of the JFrog CLI makes your scripts more efficient and reliable You can either install JFrog CLI using one of the supported installers or download its executable directly. Visit the [Install JFrog CLI Page](https://jfrog.com/getcli/) for details. -# Building the Executable - -JFrog CLI is written in the [Go programming language](https://golang.org/), so to build the CLI yourself, you first need -to have Go installed and configured on your machine. - -## Install Go - -To download and install `Go`, please refer to the [Go documentation](https://golang.org/doc/install). -Please download `Go 1.14.x` or above. - -## Download and Build the CLI - -Navigate to a directory where you want to create the jfrog-cli project, **outside** the `$GOPATH` tree. - -If the `GOPATH` variable is unset, it's default value is the go folder under the user home. - -Verify that the `GO111MODULE` variable is either unset, or explicitly set to `auto`. - -Clone the jfrog-cli project by executing the following command: - -``` -git clone https://github.com/jfrog/jfrog-cli -``` - -Build the project by navigating to the jfrog folder and executing the following commands. -On Unix based systems run: - -``` -cd jfrog-cli -build/build.sh -``` - -On Windows run: - -``` -cd jfrog-cli -build\build.bat -``` - -Once completed, you will find the JFrog CLI executable at your current directory. - -# Tests - -### Usage - -``` -go test -v github.com/jfrog/jfrog-cli [test-types] [flags] -``` - -The flags are: - -| Flag | Description | -|---------------------|-------------------------------------------------------------------------------------------------| -| `-jfrog.url` | [Default: http://localhost:8081] JFrog platform URL. | -| `-jfrog.user` | [Default: admin] JFrog platform username. | -| `-jfrog.password` | [Default: password] JFrog platform password. | -| `-jfrog.adminToken` | [Optional] JFrog platform admin token. | -| `-ci.runId` | [Optional] A unique identifier used as a suffix to create repositories and builds in the tests. | - -The types are: - -| Type | Description | -|----------------------|--------------------| -| `-test.artifactory` | Artifactory tests | -| `-test.access` | Access tests | -| `-test.npm` | Npm tests | -| `-test.maven` | Maven tests | -| `-test.gradle` | Gradle tests | -| `-test.docker` | Docker tests | -| `-test.dockerScan` | Docker scan tests | -| `-test.podman` | Podman tests | -| `-test.go` | Go tests | -| `-test.pip` | Pip tests | -| `-test.pipenv` | Pipenv tests | -| `-test.poetry` | Poetry tests | -| `-test.nuget` | Nuget tests | -| `-test.plugins` | Plugins tests | -| `-test.distribution` | Distribution tests | -| `-test.transfer` | Transfer tests | -| `-test.xray` | Xray tests | - -- Running the tests will create builds and repositories with timestamps, - for example: `cli-rt1-1592990748` and `cli-rt2-1592990748`.
- Once the tests are completed, the content of these repositories will be deleted. - -#### Artifactory tests - -In addition to [general optional flags](#Usage) you can use the following optional artifactory flags. - -| Flag | Description | -|------------------------|---------------------------------------------------------------------------------------------------------| -| `-jfrog.sshKeyPath` | [Optional] Ssh key file path. Should be used only if the Artifactory URL format is ssh://[domain]:port. | -| `-jfrog.sshPassphrase` | [Optional] Ssh key passphrase. | - -##### Examples - -To run artifactory tests execute the following command. - -``` -go test -v github.com/jfrog/jfrog-cli -test.artifactory [flags] -``` - -#### Npm tests - -##### Requirements - -- The _npm_ executables should be included as part of the _PATH_ environment variable. -- The tests are compatible with npm 7 and higher. - -##### Limitation - -- Currently, npm integration support only http(s) connections to Artifactory using username and password. - -##### Examples - -To run npm tests execute the following command. - -``` -go test -v github.com/jfrog/jfrog-cli -test.npm [flags] -``` - -#### Maven tests - -##### Requirements - -- The _java_ executable should be included as part of the _PATH_ environment variable. Alternatively, set the - _JAVA_HOME_ environment variable. - -##### Limitation - -- Currently, maven integration support only http(s) connections to Artifactory using username and password. - -##### Examples - -To run maven tests execute the following command. - -``` -go test -v github.com/jfrog/jfrog-cli -test.maven [flags] -``` - -#### Gradle tests - -##### Requirements - -- The _gradle_ executables should be included as part of the _PATH_ environment variable. -- The _java_ executable should be included as part of the _PATH_ environment variable. Alternatively, set the - _JAVA_HOME_ environment variable. - -##### Limitation - -- Currently, gradle integration support only http(s) connections to Artifactory using username and password. - -##### Examples - -To run gradle tests execute the following command. - -``` -go test -v github.com/jfrog/jfrog-cli -test.gradle [flags] -``` - -#### Docker tests - -##### Requirements - -- Make sure the environment variable `RTLIC` is configured with a valid license. -- You can start an Artifactory container by running the `startArtifactory.sh` script under - the `testdata/docker/artifactory` directory. Before running the tests, wait for Artifactory to finish booting up in - the container. - -| Flag | Description | -|---------------------------|-------------------------------------| -| `-test.containerRegistry` | Artifactory Docker registry domain. | - -##### Examples - -To run docker tests execute the following command (fill out the missing parameters as described below). - -``` -go test -v github.com/jfrog/jfrog-cli -test.docker [flags] -``` - -#### Podman tests - -| Flag | Description | -|---------------------------|----------------------------------------| -| `-test.containerRegistry` | Artifactory container registry domain. | - -##### Examples - -To run podman tests execute the following command (fill out the missing parameters as described below). - -``` -go test -v github.com/jfrog/jfrog-cli -test.podman [flags] -``` - -#### Go commands tests - -##### Requirements - -- The tests are compatible with Artifactory 6.10 and higher. -- To run go tests run the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.go [flags] -``` - -#### NuGet tests - -##### Requirements - -- Add NuGet executable to the system search path (PATH environment variable). -- Run the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.nuget [flags] -``` - -#### Pip tests - -##### Requirements - -- Add Python and pip executables to the system search path (PATH environment variable). -- Run the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.pip [flags] -``` - -#### Plugins tests - -To run Plugins tests execute the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.plugins -``` - -### Distribution tests - -To run Distribution tests execute the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.distribution [flags] -``` - -### Transfer tests - -##### Requirement - -The transfer tests execute `transfer-files` commands between a local Artifactory server and a remote SaaS instance. -In addition to [general optional flags](#Usage) you _must_ use the following flags: - -| Flag | Description | -|------------------------------------|----------------------------------------------------------------------------------------------------------------| -| `-jfrog.targetUrl` | JFrog target platform URL. | -| `-jfrog.targetAdminToken` | JFrog target platform admin token. | -| `-jfrog.jfrogHome` | The JFrog home directory of the local Artifactory installation. | -| `-jfrog.installDataTransferPlugin` | Set to true if you'd like the test to install the data-transfer automatically in the source Artifactory server | - -To run transfer tests execute the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.transfer [flags] -``` - -### Xray tests - -To run Xray tests execute the following command: - -``` -go test -v github.com/jfrog/jfrog-cli -test.xray -test.dockerScan [flags] -``` - # Code Contributions -We welcome code contributions through pull requests from the community. - -## Pull Requests Guidelines - -- If the existing tests do not already cover your changes, please add tests.. -- Pull requests should be created on the _dev_ branch. -- Please use [gofmt](https://golang.org/cmd/gofmt/) for formatting the code before submitting the pull request. - -## Dependencies in other JFrog modules - -This project heavily depends on: - -- github.com/jfrog/jfrog-client-go -- github.com/jfrog/build-info-go -- github.com/jfrog/jfrog-cli-core - -### Local Development - -During local development, when you encounter code that needs to be changed from one of the above modules, it is -recommended to replace the dependency to work with a local clone of the dependency. - -For example, assuming you would like to change files from jfrog-cli-core. -Clone jfrog-cli-core (preferably your fork) to your local development machine -(assuming it will be cloned to `/repos/jfrog-cli-core`). - -Change go.mod to include the following: - -``` -replace github.com/jfrog/jfrog-cli-core/v2 => /repos/jfrog-cli-core -``` - -### Pull Requests - -Once done with your coding, you should push the changes you made to the other modules first. Once pushed, you can change -this -project to resolve the dependencies from your GitHub fork / branch. -This is done by pointing the dependency in go.mod to your repository and branch. For example: - -``` -replace github.com/jfrog/jfrog-cli-core/v2 => github.com/galusben/jfrog-cli-core/v2 dev -``` - -Then run `go mod tidy` - -Notice that go will change the version in the go.mod file. +We welcome pull requests from the community. To help us improve this project, please read our [contribution](CONTRIBUTING.md) guide. # Using JFrog CLI diff --git a/access_test.go b/access_test.go index 2dc77a5f8..919eba11c 100644 --- a/access_test.go +++ b/access_test.go @@ -64,7 +64,7 @@ func TestRefreshableAccessTokens(t *testing.T) { // Upload a file and assert the refreshable tokens were generated. artifactoryCommandExecutor := tests.NewJfrogCli(execMain, "jfrog rt", "") uploadedFiles := 1 - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/a1.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/a1.in", uploadedFiles) if !assert.NoError(t, err) { return } @@ -80,11 +80,11 @@ func TestRefreshableAccessTokens(t *testing.T) { // Upload a file and assert tokens were refreshed. uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/a2.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/a2.in", uploadedFiles) if !assert.NoError(t, err) { return } - curAccessToken, curRefreshToken, err = assertTokensChanged(t, tests.ServerId, curAccessToken, curRefreshToken) + curAccessToken, curRefreshToken, err = assertTokensChanged(t, curAccessToken, curRefreshToken) if !assert.NoError(t, err) { return } @@ -92,11 +92,11 @@ func TestRefreshableAccessTokens(t *testing.T) { // Make the token not refresh. Verify Tokens did not refresh. auth.InviteRefreshBeforeExpiryMinutes = 0 uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/b/b2.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/b/b2.in", uploadedFiles) if !assert.NoError(t, err) { return } - newAccessToken, newRefreshToken, err := getArtifactoryTokensFromConfig(t, tests.ServerId) + newAccessToken, newRefreshToken, err := getArtifactoryTokensFromConfig(t) if !assert.NoError(t, err) { return } diff --git a/artifactory/cli.go b/artifactory/cli.go index 427b3ab1b..065205971 100644 --- a/artifactory/cli.go +++ b/artifactory/cli.go @@ -128,9 +128,7 @@ func GetCommands() []cli.Command { UsageText: upload.GetArguments(), ArgsUsage: common.CreateEnvVars(upload.EnvVar...), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return uploadCmd(c) - }, + Action: uploadCmd, }, { Name: "download", @@ -141,9 +139,7 @@ func GetCommands() []cli.Command { UsageText: download.GetArguments(), ArgsUsage: common.CreateEnvVars(download.EnvVar...), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return downloadCmd(c) - }, + Action: downloadCmd, }, { Name: "move", @@ -154,9 +150,7 @@ func GetCommands() []cli.Command { UsageText: move.GetArguments(), ArgsUsage: common.CreateEnvVars(move.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return moveCmd(c) - }, + Action: moveCmd, }, { Name: "copy", @@ -167,9 +161,7 @@ func GetCommands() []cli.Command { UsageText: copydocs.GetArguments(), ArgsUsage: common.CreateEnvVars(copydocs.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return copyCmd(c) - }, + Action: copyCmd, }, { Name: "delete", @@ -180,9 +172,7 @@ func GetCommands() []cli.Command { UsageText: delete.GetArguments(), ArgsUsage: common.CreateEnvVars(delete.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return deleteCmd(c) - }, + Action: deleteCmd, }, { Name: "search", @@ -193,9 +183,7 @@ func GetCommands() []cli.Command { UsageText: search.GetArguments(), ArgsUsage: common.CreateEnvVars(search.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return searchCmd(c) - }, + Action: searchCmd, }, { Name: "set-props", @@ -206,9 +194,7 @@ func GetCommands() []cli.Command { UsageText: setprops.GetArguments(), ArgsUsage: common.CreateEnvVars(setprops.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return setPropsCmd(c) - }, + Action: setPropsCmd, }, { Name: "delete-props", @@ -219,9 +205,7 @@ func GetCommands() []cli.Command { UsageText: deleteprops.GetArguments(), ArgsUsage: common.CreateEnvVars(deleteprops.EnvVar), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return deletePropsCmd(c) - }, + Action: deletePropsCmd, }, { Name: "build-publish", @@ -232,9 +216,7 @@ func GetCommands() []cli.Command { UsageText: buildpublish.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildPublishCmd(c) - }, + Action: buildPublishCmd, }, { Name: "build-collect-env", @@ -245,9 +227,7 @@ func GetCommands() []cli.Command { UsageText: buildcollectenv.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildCollectEnvCmd(c) - }, + Action: buildCollectEnvCmd, }, { Name: "build-append", @@ -258,9 +238,7 @@ func GetCommands() []cli.Command { UsageText: buildappend.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildAppendCmd(c) - }, + Action: buildAppendCmd, }, { Name: "build-add-dependencies", @@ -271,9 +249,7 @@ func GetCommands() []cli.Command { UsageText: buildadddependencies.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildAddDependenciesCmd(c) - }, + Action: buildAddDependenciesCmd, }, { Name: "build-add-git", @@ -284,9 +260,7 @@ func GetCommands() []cli.Command { UsageText: buildaddgit.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildAddGitCmd(c) - }, + Action: buildAddGitCmd, }, { Name: "build-scan", @@ -309,9 +283,7 @@ func GetCommands() []cli.Command { UsageText: buildclean.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildCleanCmd(c) - }, + Action: buildCleanCmd, }, { Name: "build-promote", @@ -322,9 +294,7 @@ func GetCommands() []cli.Command { UsageText: buildpromote.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildPromoteCmd(c) - }, + Action: buildPromoteCmd, }, { Name: "build-discard", @@ -335,9 +305,7 @@ func GetCommands() []cli.Command { UsageText: builddiscard.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return buildDiscardCmd(c) - }, + Action: buildDiscardCmd, }, { Name: "git-lfs-clean", @@ -348,9 +316,7 @@ func GetCommands() []cli.Command { UsageText: gitlfsclean.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return gitLfsCleanCmd(c) - }, + Action: gitLfsCleanCmd, }, { Name: "mvn-config", @@ -411,9 +377,7 @@ func GetCommands() []cli.Command { UsageText: dockerpromote.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return dockerPromoteCmd(c) - }, + Action: dockerPromoteCmd, }, { Name: "docker-push", @@ -476,9 +440,7 @@ func GetCommands() []cli.Command { UsageText: builddockercreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return BuildDockerCreateCmd(c) - }, + Action: BuildDockerCreateCmd, }, { Name: "oc", // Only 'oc start-build' is supported @@ -489,9 +451,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return ocStartBuildCmd(c) - }, + Action: ocStartBuildCmd, }, { Name: "npm-config", @@ -602,9 +562,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("rt nuget-deps-tree", nugettree.GetDescription(), nugettree.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return nugetDepsTreeCmd(c) - }, + Action: nugetDepsTreeCmd, }, { Name: "dotnet-config", @@ -677,9 +635,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("rt ping", ping.GetDescription(), ping.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return pingCmd(c) - }, + Action: pingCmd, }, { Name: "curl", @@ -691,9 +647,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), SkipFlagParsing: true, - Action: func(c *cli.Context) error { - return curlCmd(c) - }, + Action: curlCmd, }, { Name: "pip-config", @@ -729,9 +683,7 @@ func GetCommands() []cli.Command { UsageText: repotemplate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return repoTemplateCmd(c) - }, + Action: repoTemplateCmd, }, { Name: "repo-create", @@ -742,9 +694,7 @@ func GetCommands() []cli.Command { UsageText: repocreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return repoCreateCmd(c) - }, + Action: repoCreateCmd, }, { Name: "repo-update", @@ -755,9 +705,7 @@ func GetCommands() []cli.Command { UsageText: repoupdate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return repoUpdateCmd(c) - }, + Action: repoUpdateCmd, }, { Name: "repo-delete", @@ -768,9 +716,7 @@ func GetCommands() []cli.Command { UsageText: repodelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return repoDeleteCmd(c) - }, + Action: repoDeleteCmd, }, { Name: "replication-template", @@ -781,9 +727,7 @@ func GetCommands() []cli.Command { UsageText: replicationtemplate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return replicationTemplateCmd(c) - }, + Action: replicationTemplateCmd, }, { Name: "replication-create", @@ -794,9 +738,7 @@ func GetCommands() []cli.Command { UsageText: replicationcreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return replicationCreateCmd(c) - }, + Action: replicationCreateCmd, }, { Name: "replication-delete", @@ -807,9 +749,7 @@ func GetCommands() []cli.Command { UsageText: replicationdelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return replicationDeleteCmd(c) - }, + Action: replicationDeleteCmd, }, { Name: "permission-target-template", @@ -819,9 +759,7 @@ func GetCommands() []cli.Command { UsageText: permissiontargettemplate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return permissionTargetTemplateCmd(c) - }, + Action: permissionTargetTemplateCmd, }, { Name: "permission-target-create", @@ -832,9 +770,7 @@ func GetCommands() []cli.Command { UsageText: permissiontargetcreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return permissionTargetCreateCmd(c) - }, + Action: permissionTargetCreateCmd, }, { Name: "permission-target-update", @@ -845,9 +781,7 @@ func GetCommands() []cli.Command { UsageText: permissiontargetupdate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return permissionTargetUpdateCmd(c) - }, + Action: permissionTargetUpdateCmd, }, { Name: "permission-target-delete", @@ -858,9 +792,7 @@ func GetCommands() []cli.Command { UsageText: permissiontargetdelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return permissionTargetDeleteCmd(c) - }, + Action: permissionTargetDeleteCmd, }, { Name: "user-create", @@ -869,9 +801,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("rt user-create", usercreate.GetDescription(), usercreate.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return userCreateCmd(c) - }, + Action: userCreateCmd, }, { Name: "users-create", @@ -881,9 +811,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("rt uc", userscreate.GetDescription(), userscreate.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return usersCreateCmd(c) - }, + Action: usersCreateCmd, }, { Name: "users-delete", @@ -894,9 +822,7 @@ func GetCommands() []cli.Command { UsageText: usersdelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return usersDeleteCmd(c) - }, + Action: usersDeleteCmd, }, { Name: "group-create", @@ -907,9 +833,7 @@ func GetCommands() []cli.Command { UsageText: groupcreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return groupCreateCmd(c) - }, + Action: groupCreateCmd, }, { Name: "group-add-users", @@ -920,9 +844,7 @@ func GetCommands() []cli.Command { UsageText: groupaddusers.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return groupAddUsersCmd(c) - }, + Action: groupAddUsersCmd, }, { Name: "group-delete", @@ -933,9 +855,7 @@ func GetCommands() []cli.Command { UsageText: groupdelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return groupDeleteCmd(c) - }, + Action: groupDeleteCmd, }, { Name: "access-token-create", @@ -946,9 +866,7 @@ func GetCommands() []cli.Command { UsageText: accesstokencreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return accessTokenCreateCmd(c) - }, + Action: accessTokenCreateCmd, }, { Name: "transfer-settings", @@ -956,9 +874,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("rt transfer-settings", transfersettings.GetDescription(), transfersettings.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return transferSettingsCmd() - }, + Action: transferSettingsCmd, }, { Name: "transfer-config", @@ -968,9 +884,7 @@ func GetCommands() []cli.Command { UsageText: transferconfig.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return transferConfigCmd(c) - }, + Action: transferConfigCmd, }, { Name: "transfer-config-merge", @@ -980,9 +894,7 @@ func GetCommands() []cli.Command { UsageText: transferconfigmerge.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return transferConfigMergeCmd(c) - }, + Action: transferConfigMergeCmd, }, { Name: "transfer-files", @@ -992,9 +904,7 @@ func GetCommands() []cli.Command { UsageText: transferfiles.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return transferFilesCmd(c) - }, + Action: transferFilesCmd, }, { Name: "transfer-plugin-install", @@ -1004,9 +914,7 @@ func GetCommands() []cli.Command { UsageText: transferplugininstall.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return dataTransferPluginInstallCmd(c) - }, + Action: dataTransferPluginInstallCmd, }, }) } @@ -1062,12 +970,14 @@ func getRetryWaitTime(c *cli.Context) (waitMilliSecs int, err error) { waitTimeStringValue := c.String("retry-wait-time") useSeconds := false if waitTimeStringValue != "" { - if strings.HasSuffix(waitTimeStringValue, "ms") { + switch { + case strings.HasSuffix(waitTimeStringValue, "ms"): waitTimeStringValue = strings.TrimSuffix(waitTimeStringValue, "ms") - } else if strings.HasSuffix(waitTimeStringValue, "s") { + + case strings.HasSuffix(waitTimeStringValue, "s"): useSeconds = true waitTimeStringValue = strings.TrimSuffix(waitTimeStringValue, "s") - } else { + default: err = getRetryWaitTimeVerificationError() return } @@ -1078,7 +988,7 @@ func getRetryWaitTime(c *cli.Context) (waitMilliSecs int, err error) { } // Convert seconds to milliseconds if useSeconds { - waitMilliSecs = waitMilliSecs * 1000 + waitMilliSecs *= 1000 } } return @@ -1119,7 +1029,7 @@ func containerPushCmd(c *cli.Context, containerManagerType containerutils.Contai targetRepo := c.Args().Get(1) skipLogin := c.Bool("skip-login") - buildConfiguration, err := buildtools.CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return } @@ -1154,7 +1064,7 @@ func containerPullCmd(c *cli.Context, containerManagerType containerutils.Contai imageTag := c.Args().Get(0) sourceRepo := c.Args().Get(1) skipLogin := c.Bool("skip-login") - buildConfiguration, err := buildtools.CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return err } @@ -1180,7 +1090,7 @@ func BuildDockerCreateCmd(c *cli.Context) error { if imageNameWithDigestFile == "" { return cliutils.PrintHelpAndReturnError("The '--image-file' command option was not provided.", c) } - buildConfiguration, err := buildtools.CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return err } @@ -1307,7 +1217,7 @@ func downloadCmd(c *cli.Context) error { if err != nil { return err } - buildConfiguration, err := buildtools.CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return err } @@ -1364,7 +1274,7 @@ func uploadCmd(c *cli.Context) (err error) { if err != nil { return } - buildConfiguration, err := buildtools.CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return } @@ -1388,7 +1298,7 @@ func uploadCmd(c *cli.Context) (err error) { "You can avoid this confirmation message by adding --quiet to the command.", false) { return nil } - // This error is being checked latter on because we need to generate summary report before return. + // This error is being checked later on because we need to generate summary report before return. err = progressbar.ExecWithProgress(uploadCmd) result := uploadCmd.Result() defer cliutils.CleanupResult(result, &err) @@ -2478,7 +2388,7 @@ func getTransferIncludeExcludeProjects(c *cli.Context) (includeProjectsPatterns, return } -func transferSettingsCmd() error { +func transferSettingsCmd(_ *cli.Context) error { transferSettingsCmd := transfer.NewTransferSettingsCommand() return commands.Exec(transferSettingsCmd) } @@ -2502,7 +2412,7 @@ func createDefaultCopyMoveSpec(c *cli.Context) (*spec.SpecFiles, error) { Props(c.String("props")). ExcludeProps(c.String("exclude-props")). Build(c.String("build")). - Project(getProject(c)). + Project(cliutils.GetProject(c)). ExcludeArtifacts(c.Bool("exclude-artifacts")). IncludeDeps(c.Bool("include-deps")). Bundle(c.String("bundle")). @@ -2529,7 +2439,7 @@ func createDefaultDeleteSpec(c *cli.Context) (*spec.SpecFiles, error) { Props(c.String("props")). ExcludeProps(c.String("exclude-props")). Build(c.String("build")). - Project(getProject(c)). + Project(cliutils.GetProject(c)). ExcludeArtifacts(c.Bool("exclude-artifacts")). IncludeDeps(c.Bool("include-deps")). Bundle(c.String("bundle")). @@ -2553,7 +2463,7 @@ func createDefaultSearchSpec(c *cli.Context) (*spec.SpecFiles, error) { Props(c.String("props")). ExcludeProps(c.String("exclude-props")). Build(c.String("build")). - Project(getProject(c)). + Project(cliutils.GetProject(c)). ExcludeArtifacts(c.Bool("exclude-artifacts")). IncludeDeps(c.Bool("include-deps")). Bundle(c.String("bundle")). @@ -2580,7 +2490,7 @@ func createDefaultPropertiesSpec(c *cli.Context) (*spec.SpecFiles, error) { Props(c.String("props")). ExcludeProps(c.String("exclude-props")). Build(c.String("build")). - Project(getProject(c)). + Project(cliutils.GetProject(c)). ExcludeArtifacts(c.Bool("exclude-artifacts")). IncludeDeps(c.Bool("include-deps")). Bundle(c.String("bundle")). @@ -2619,7 +2529,7 @@ func createBuildPromoteConfiguration(c *cli.Context) services.PromotionParams { promotionParamsImpl.IncludeDependencies = c.Bool("include-dependencies") promotionParamsImpl.Copy = c.Bool("copy") promotionParamsImpl.Properties = c.String("props") - promotionParamsImpl.ProjectKey = c.String("project") + promotionParamsImpl.ProjectKey = cliutils.GetProject(c) promotionParamsImpl.FailFast = c.BoolT("fail-fast") // If the command received 3 args, read the build name, build number @@ -2644,7 +2554,7 @@ func createBuildDiscardConfiguration(c *cli.Context) services.DiscardBuildsParam discardParamsImpl.ExcludeBuilds = c.String("exclude-builds") discardParamsImpl.Async = c.Bool("async") discardParamsImpl.BuildName = cliutils.GetBuildName(c.Args().Get(0)) - discardParamsImpl.ProjectKey = c.String("project") + discardParamsImpl.ProjectKey = cliutils.GetProject(c) return discardParamsImpl } @@ -2676,7 +2586,7 @@ func createDefaultDownloadSpec(c *cli.Context) (*spec.SpecFiles, error) { Props(c.String("props")). ExcludeProps(c.String("exclude-props")). Build(c.String("build")). - Project(getProject(c)). + Project(cliutils.GetProject(c)). ExcludeArtifacts(c.Bool("exclude-artifacts")). IncludeDeps(c.Bool("include-deps")). Bundle(c.String("bundle")). @@ -2812,12 +2722,3 @@ func getOffsetAndLimitValues(c *cli.Context) (offset, limit int, err error) { return } - -// Get project key from flag or environment variable -func getProject(c *cli.Context) string { - project := c.String("project") - if project == "" { - project = os.Getenv(coreutils.Project) - } - return project -} diff --git a/artifactory/cli_test.go b/artifactory/cli_test.go index fb848c0d4..e951be591 100644 --- a/artifactory/cli_test.go +++ b/artifactory/cli_test.go @@ -2,15 +2,12 @@ package artifactory import ( "bytes" - "flag" "github.com/jfrog/jfrog-cli-core/v2/common/spec" - "path/filepath" - "strings" - "testing" - "github.com/jfrog/jfrog-cli/utils/tests" "github.com/stretchr/testify/assert" "github.com/urfave/cli" + "path/filepath" + "testing" ) func TestPrepareSearchDownloadDeleteCommands(t *testing.T) { @@ -34,7 +31,7 @@ func TestPrepareSearchDownloadDeleteCommands(t *testing.T) { for _, test := range testRuns { t.Run(test.name, func(t *testing.T) { - context, buffer := createContext(t, test.flags, test.args) + context, buffer := tests.CreateContext(t, test.flags, test.args) funcArray := []func(c *cli.Context) (*spec.SpecFiles, error){ prepareSearchCommand, prepareDownloadCommand, prepareDeleteCommand, } @@ -67,7 +64,7 @@ func TestPrepareCopyMoveCommand(t *testing.T) { for _, test := range testRuns { t.Run(test.name, func(t *testing.T) { - context, buffer := createContext(t, test.flags, test.args) + context, buffer := tests.CreateContext(t, test.flags, test.args) specFiles, err := prepareCopyMoveCommand(context) assertGenericCommand(t, err, buffer, test.expectError, test.expectedPattern, test.expectedBuild, test.expectedBundle, specFiles) }) @@ -96,7 +93,7 @@ func TestPreparePropsCmd(t *testing.T) { for _, test := range testRuns { t.Run(test.name, func(t *testing.T) { - context, buffer := createContext(t, test.flags, test.args) + context, buffer := tests.CreateContext(t, test.flags, test.args) propsCommand, err := preparePropsCmd(context) var actualSpec *spec.SpecFiles if propsCommand != nil { @@ -119,27 +116,6 @@ func assertGenericCommand(t *testing.T, err error, buffer *bytes.Buffer, expectE } } -func createContext(t *testing.T, testFlags, testArgs []string) (*cli.Context, *bytes.Buffer) { - flagSet := createFlagSet(t, testFlags, testArgs) - app := cli.NewApp() - app.Writer = &bytes.Buffer{} - return cli.NewContext(app, flagSet, nil), &bytes.Buffer{} -} - func getSpecPath(spec string) string { return filepath.Join("..", "testdata", "filespecs", spec) } - -// Create flag set with input flags and arguments. -func createFlagSet(t *testing.T, flags []string, args []string) *flag.FlagSet { - flagSet := flag.NewFlagSet("TestFlagSet", flag.ContinueOnError) - flags = append(flags, "url=http://127.0.0.1:8081/artifactory") - var cmdFlags []string - for _, curFlag := range flags { - flagSet.String(strings.Split(curFlag, "=")[0], "", "") - cmdFlags = append(cmdFlags, "--"+curFlag) - } - cmdFlags = append(cmdFlags, args...) - assert.NoError(t, flagSet.Parse(cmdFlags)) - return flagSet -} diff --git a/artifactory_test.go b/artifactory_test.go index b8a9ae04a..9a5fbe194 100644 --- a/artifactory_test.go +++ b/artifactory_test.go @@ -123,7 +123,7 @@ func authenticate(configCli bool) string { // Removed the ssh-passphrase flag that cannot be passed to with a config command func createConfigJfrogCLI(cred string) *tests.JfrogCli { if strings.Contains(cred, " --ssh-passphrase=") { - cred = strings.Replace(cred, " --ssh-passphrase="+*tests.JfrogSshPassphrase, "", -1) + cred = strings.ReplaceAll(cred, " --ssh-passphrase="+*tests.JfrogSshPassphrase, "") } return tests.NewJfrogCli(execMain, "jfrog config", cred) } @@ -1248,10 +1248,10 @@ func TestArtifactoryDownloadAndExplodeSpecialChars(t *testing.T) { cleanArtifactoryTest() } -func verifyExistAndCleanDir(t *testing.T, GetExtractedDownload func() []string) { +func verifyExistAndCleanDir(t *testing.T, getExtractedDownload func() []string) { paths, err := fileutils.ListFilesRecursiveWalkIntoDirSymlink(tests.Out, false) assert.NoError(t, err) - tests.VerifyExistLocally(GetExtractedDownload(), paths, t) + tests.VerifyExistLocally(getExtractedDownload(), paths, t) clientTestUtils.RemoveAllAndAssert(t, tests.Out) assert.NoError(t, fileutils.CreateDirIfNotExist(tests.Out)) } @@ -4216,7 +4216,7 @@ func TestArtifactoryBuildDiscard(t *testing.T) { jsonResponse = getAllBuildsByBuildName(client, tests.RtBuildName1, t, http.StatusNotFound) assert.Zero(t, jsonResponse, "Incorrect operation of build-discard by max-days.") - //Cleanup + // Cleanup inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.RtBuildName1, artHttpDetails) cleanArtifactoryTest() } @@ -4549,7 +4549,7 @@ func validateArtifactoryVersion(t *testing.T, minVersion string) { return } if !rtVersion.AtLeast(minVersion) { - t.Skip("Skipping artifactory project test. Artifactory version not supported.") + t.Skip("Skipping test. Artifactory version not supported.") } } @@ -5255,11 +5255,11 @@ func TestRefreshableArtifactoryTokens(t *testing.T) { // Upload a file and assert the refreshable tokens were generated. artifactoryCommandExecutor := tests.NewJfrogCli(execMain, "jfrog rt", "") uploadedFiles := 1 - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/a1.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/a1.in", uploadedFiles) if err != nil { return } - curAccessToken, curRefreshToken, err := getArtifactoryTokensFromConfig(t, tests.ServerId) + curAccessToken, curRefreshToken, err := getArtifactoryTokensFromConfig(t) if err != nil { return } @@ -5271,11 +5271,11 @@ func TestRefreshableArtifactoryTokens(t *testing.T) { // Upload a file and assert tokens were refreshed. uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/a2.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/a2.in", uploadedFiles) if err != nil { return } - curAccessToken, curRefreshToken, err = assertTokensChanged(t, tests.ServerId, curAccessToken, curRefreshToken) + curAccessToken, curRefreshToken, err = assertTokensChanged(t, curAccessToken, curRefreshToken) if err != nil { return } @@ -5286,11 +5286,11 @@ func TestRefreshableArtifactoryTokens(t *testing.T) { return } uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/a3.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/a3.in", uploadedFiles) if err != nil { return } - curAccessToken, curRefreshToken, err = assertTokensChanged(t, tests.ServerId, curAccessToken, curRefreshToken) + curAccessToken, curRefreshToken, err = assertTokensChanged(t, curAccessToken, curRefreshToken) if err != nil { return } @@ -5301,11 +5301,11 @@ func TestRefreshableArtifactoryTokens(t *testing.T) { return } uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/b/b1.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/b/b1.in", uploadedFiles) if err != nil { return } - curAccessToken, curRefreshToken, err = assertTokensChanged(t, tests.ServerId, curAccessToken, curRefreshToken) + curAccessToken, curRefreshToken, err = assertTokensChanged(t, curAccessToken, curRefreshToken) if err != nil { return } @@ -5313,11 +5313,11 @@ func TestRefreshableArtifactoryTokens(t *testing.T) { // Make the token not refresh. Verify Tokens did not refresh. auth.RefreshBeforeExpiryMinutes = 0 uploadedFiles++ - err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, tests.ServerId, "testdata/a/b/b2.in", uploadedFiles) + err = uploadWithSpecificServerAndVerify(t, artifactoryCommandExecutor, "testdata/a/b/b2.in", uploadedFiles) if err != nil { return } - newAccessToken, newRefreshToken, err := getArtifactoryTokensFromConfig(t, tests.ServerId) + newAccessToken, newRefreshToken, err := getArtifactoryTokensFromConfig(t) if err != nil { return } @@ -5358,8 +5358,8 @@ func setPasswordInConfig(t *testing.T, serverId, password string) error { return nil } -func getArtifactoryTokensFromConfig(t *testing.T, serverId string) (accessToken, refreshToken string, err error) { - details, err := config.GetSpecificConfig(serverId, false, false) +func getArtifactoryTokensFromConfig(t *testing.T) (accessToken, refreshToken string, err error) { + details, err := config.GetSpecificConfig(tests.ServerId, false, false) if err != nil { assert.NoError(t, err) return "", "", err @@ -5367,8 +5367,8 @@ func getArtifactoryTokensFromConfig(t *testing.T, serverId string) (accessToken, return details.AccessToken, details.ArtifactoryRefreshToken, nil } -func assertTokensChanged(t *testing.T, serverId, curAccessToken, curRefreshToken string) (newAccessToken, newRefreshToken string, err error) { - newAccessToken, newRefreshToken, err = getArtifactoryTokensFromConfig(t, serverId) +func assertTokensChanged(t *testing.T, curAccessToken, curRefreshToken string) (newAccessToken, newRefreshToken string, err error) { + newAccessToken, newRefreshToken, err = getArtifactoryTokensFromConfig(t) if err != nil { assert.NoError(t, err) return "", "", err @@ -5378,8 +5378,8 @@ func assertTokensChanged(t *testing.T, serverId, curAccessToken, curRefreshToken return newAccessToken, newRefreshToken, nil } -func uploadWithSpecificServerAndVerify(t *testing.T, cli *tests.JfrogCli, serverId string, source string, expectedResults int) error { - err := cli.Exec("upload", source, tests.RtRepo1, "--server-id="+serverId) +func uploadWithSpecificServerAndVerify(t *testing.T, cli *tests.JfrogCli, source string, expectedResults int) error { + err := cli.Exec("upload", source, tests.RtRepo1, "--server-id="+tests.ServerId) if err != nil { assert.NoError(t, err) return err diff --git a/build/docker/full/Dockerfile b/build/docker/full/Dockerfile index 76e3f5c69..6198ce57b 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.20.4 as builder +FROM ${repo_name_21}/jfrog-docker/golang:1.20 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 b9d93b469..ae69bd4c7 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.20.4-alpine as builder +FROM ${repo_name_21}/jfrog-docker/golang:1.20-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 3ccfed708..738e730cd 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.40.0", + "version": "2.44.0", "lockfileVersion": 1 } diff --git a/build/npm/v2-jf/package.json b/build/npm/v2-jf/package.json index 4419ecaf0..9d43c22dc 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.40.0", + "version": "2.44.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 21d8687c0..d3e36fd1a 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.40.0", + "version": "2.44.0", "lockfileVersion": 1 } diff --git a/build/npm/v2/package.json b/build/npm/v2/package.json index bd5cba97f..0ca1a13ed 100644 --- a/build/npm/v2/package.json +++ b/build/npm/v2/package.json @@ -1,6 +1,6 @@ { "name": "jfrog-cli-v2", - "version": "2.40.0", + "version": "2.44.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/buildinfo_test.go b/buildinfo_test.go index 9231d3d7f..a04443559 100644 --- a/buildinfo_test.go +++ b/buildinfo_test.go @@ -199,7 +199,7 @@ func TestBuildPublishDetailedSummary(t *testing.T) { assert.NoError(t, err) runRt(t, "upload", "--spec="+specFile, "--build-name="+tests.RtBuildName1, "--build-number="+buildNumber) // Verify build dir is not empty - assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber, "")) + assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber)) buffer, _, previousLog := coretests.RedirectLogOutputToBuffer() // Restore previous logger when the function returns @@ -224,7 +224,7 @@ func TestBuildPublishDryRun(t *testing.T) { assert.NoError(t, err) runRt(t, "upload", "--spec="+specFile, "--build-name="+tests.RtBuildName1, "--build-number="+buildNumber) // Verify build dir is not empty - assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber, "")) + assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber)) buffer, _, previousLog := coretests.RedirectLogOutputToBuffer() // Restore previous logger when the function returns @@ -235,7 +235,7 @@ func TestBuildPublishDryRun(t *testing.T) { verifyBuildPublishOutput(t, buffer, true) // Verify build dir is not empty. - assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber, "")) + assert.NotEmpty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber)) // Verify build was not published. _, found, err := tests.GetBuildInfo(serverDetails, tests.RtBuildName1, buildNumber) if err != nil { @@ -252,7 +252,7 @@ func TestBuildPublishDryRun(t *testing.T) { verifyBuildPublishOutput(t, buffer, false) // Verify build dir is empty - assert.Empty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber, "")) + assert.Empty(t, getFilesFromBuildDir(t, tests.RtBuildName1, buildNumber)) // Verify build was published publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.RtBuildName1, buildNumber) if err != nil { @@ -282,7 +282,10 @@ func verifyBuildPublishOutput(t *testing.T, buffer *bytes.Buffer, dryRun bool) { } } -func getFilesFromBuildDir(t *testing.T, buildName, buildNumber, projectKey string) []os.DirEntry { +// The linter has an issue with buildNumber that is always the same number, but we do it on purpose. +// +//nolint:unparam +func getFilesFromBuildDir(t *testing.T, buildName, buildNumber string) []os.DirEntry { buildDir, err := utils.GetBuildDir(buildName, buildNumber, "") assert.NoError(t, err) @@ -867,7 +870,8 @@ func validateBuildAddDepsBuildInfo(t *testing.T, buildInfoTestParams buildAddDep } buildInfo := publishedBuildInfo.BuildInfo if buildInfo.Modules == nil || len(buildInfo.Modules) == 0 { - buildInfoString, _ := json.Marshal(buildInfo) + buildInfoString, err := json.Marshal(buildInfo) + assert.NoError(t, err) // Case no module was not created assert.Failf(t, "%s test with the command: \nrt bad %s \nexpected to have module with the following dependencies: \n%s \nbut has no modules: \n%s", buildInfoTestParams.description, buildInfoTestParams.commandArgs, buildInfoTestParams.expectedDependencies, buildInfoString) diff --git a/buildtools/cli.go b/buildtools/cli.go index 8ef8f3c8d..508edb996 100644 --- a/buildtools/cli.go +++ b/buildtools/cli.go @@ -84,9 +84,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return MvnCmd(c) - }, + Action: MvnCmd, }, { Name: "gradle-config", @@ -111,9 +109,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return GradleCmd(c) - }, + Action: GradleCmd, }, { Name: "yarn-config", @@ -137,9 +133,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return YarnCmd(c) - }, + Action: YarnCmd, }, { Name: "nuget-config", @@ -164,9 +158,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return NugetCmd(c) - }, + Action: NugetCmd, }, { Name: "dotnet-config", @@ -191,9 +183,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return DotnetCmd(c) - }, + Action: DotnetCmd, }, { Name: "go-config", @@ -219,9 +209,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return GoCmd(c) - }, + Action: GoCmd, }, { Name: "go-publish", @@ -233,9 +221,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return GoPublishCmd(c) - }, + Action: GoPublishCmd, }, { Name: "pip-config", @@ -260,9 +246,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return PipCmd(c) - }, + Action: PipCmd, }, { Name: "pipenv-config", @@ -287,9 +271,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return PipenvCmd(c) - }, + Action: PipenvCmd, }, { Name: "poetry-config", @@ -314,9 +296,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return PoetryCmd(c) - }, + Action: PoetryCmd, }, { Name: "npm-config", @@ -361,9 +341,7 @@ func GetCommands() []cli.Command { }(), BashComplete: corecommon.CreateBashCompletionFunc("push", "pull", "scan"), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return dockerCmd(c) - }, + Action: dockerCmd, }, { Name: "terraform-config", @@ -389,9 +367,7 @@ func GetCommands() []cli.Command { SkipFlagParsing: true, BashComplete: corecommon.CreateBashCompletionFunc(), Category: buildToolsCategory, - Action: func(c *cli.Context) error { - return terraformCmd(c) - }, + Action: terraformCmd, }, }) } @@ -653,14 +629,14 @@ func GoPublishCmd(c *cli.Context) (err error) { if err != nil { return err } - buildConfiguration, err := CreateBuildConfigurationWithModule(c) + buildConfiguration, err := cliutils.CreateBuildConfigurationWithModule(c) if err != nil { return err } version := c.Args().Get(0) printDeploymentView, detailedSummary := log.IsStdErrTerminal(), c.Bool("detailed-summary") goPublishCmd := golang.NewGoPublishCommand() - goPublishCmd.SetConfigFilePath(configFilePath).SetBuildConfiguration(buildConfiguration).SetVersion(version).SetDetailedSummary(detailedSummary || printDeploymentView) + goPublishCmd.SetConfigFilePath(configFilePath).SetBuildConfiguration(buildConfiguration).SetVersion(version).SetDetailedSummary(detailedSummary || printDeploymentView).SetExcludedPatterns(cliutils.GetStringsArrFlagValue(c, "exclusions")) err = commands.Exec(goPublishCmd) result := goPublishCmd.Result() defer cliutils.CleanupResult(result, &err) @@ -687,12 +663,6 @@ func goCmdVerification(c *cli.Context) (string, error) { return configFilePath, nil } -func CreateBuildConfigurationWithModule(c *cli.Context) (buildConfigConfiguration *utils.BuildConfiguration, err error) { - buildConfigConfiguration = new(utils.BuildConfiguration) - err = buildConfigConfiguration.SetBuildName(c.String("build-name")).SetBuildNumber(c.String("build-number")).SetProject(c.String("project")).SetModule(c.String("module")).ValidateBuildAndModuleParams() - return -} - func dockerCmd(c *cli.Context) error { args := cliutils.ExtractCommand(c) var cmd, image string diff --git a/config/cli.go b/config/cli.go index 8f7ab75aa..b55d5dadc 100644 --- a/config/cli.go +++ b/config/cli.go @@ -31,9 +31,7 @@ func GetCommands() []cli.Command { Flags: cliutils.GetCommandFlags(cliutils.AddConfig), HelpName: corecommon.CreateUsage("c add", add.GetDescription(), add.Usage), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return addCmd(c) - }, + Action: addCmd, }, { Name: "edit", @@ -41,9 +39,7 @@ func GetCommands() []cli.Command { Flags: cliutils.GetCommandFlags(cliutils.EditConfig), HelpName: corecommon.CreateUsage("c edit", edit.GetDescription(), edit.Usage), BashComplete: corecommon.CreateBashCompletionFunc(commands.GetAllServerIds()...), - Action: func(c *cli.Context) error { - return editCmd(c) - }, + Action: editCmd, }, { Name: "show", @@ -51,9 +47,7 @@ func GetCommands() []cli.Command { Usage: show.GetDescription(), HelpName: corecommon.CreateUsage("c show", show.GetDescription(), show.Usage), BashComplete: corecommon.CreateBashCompletionFunc(commands.GetAllServerIds()...), - Action: func(c *cli.Context) error { - return showCmd(c) - }, + Action: showCmd, }, { Name: "remove", @@ -62,9 +56,7 @@ func GetCommands() []cli.Command { Flags: cliutils.GetCommandFlags(cliutils.DeleteConfig), HelpName: corecommon.CreateUsage("c rm", remove.GetDescription(), remove.Usage), BashComplete: corecommon.CreateBashCompletionFunc(commands.GetAllServerIds()...), - Action: func(c *cli.Context) error { - return deleteCmd(c) - }, + Action: deleteCmd, }, { Name: "import", @@ -72,9 +64,7 @@ func GetCommands() []cli.Command { Usage: importcmd.GetDescription(), HelpName: corecommon.CreateUsage("c import", importcmd.GetDescription(), importcmd.Usage), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return importCmd(c) - }, + Action: importCmd, }, { Name: "export", @@ -82,18 +72,14 @@ func GetCommands() []cli.Command { Usage: exportcmd.GetDescription(), HelpName: corecommon.CreateUsage("c export", exportcmd.GetDescription(), exportcmd.Usage), BashComplete: corecommon.CreateBashCompletionFunc(commands.GetAllServerIds()...), - Action: func(c *cli.Context) error { - return exportCmd(c) - }, + Action: exportCmd, }, { Name: "use", Usage: use.GetDescription(), HelpName: corecommon.CreateUsage("c use", use.GetDescription(), use.Usage), BashComplete: corecommon.CreateBashCompletionFunc(commands.GetAllServerIds()...), - Action: func(c *cli.Context) error { - return useCmd(c) - }, + Action: useCmd, }, }) } diff --git a/distribution/cli.go b/distribution/cli.go index 875af521c..682156767 100644 --- a/distribution/cli.go +++ b/distribution/cli.go @@ -28,68 +28,58 @@ func GetCommands() []cli.Command { return cliutils.GetSortedCommands(cli.CommandsByName{ { Name: "release-bundle-create", - Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleCreate), + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleV1Create), Aliases: []string{"rbc"}, Usage: releasebundlecreate.GetDescription(), HelpName: coreCommonDocs.CreateUsage("ds rbc", releasebundlecreate.GetDescription(), releasebundlecreate.Usage), UsageText: releasebundlecreate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: coreCommonDocs.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return releaseBundleCreateCmd(c) - }, + Action: releaseBundleCreateCmd, }, { Name: "release-bundle-update", - Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleUpdate), + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleV1Update), Aliases: []string{"rbu"}, Usage: releasebundleupdate.GetDescription(), HelpName: coreCommonDocs.CreateUsage("ds rbu", releasebundleupdate.GetDescription(), releasebundleupdate.Usage), UsageText: releasebundleupdate.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: coreCommonDocs.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return releaseBundleUpdateCmd(c) - }, + Action: releaseBundleUpdateCmd, }, { Name: "release-bundle-sign", - Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleSign), + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleV1Sign), Aliases: []string{"rbs"}, Usage: releasebundlesign.GetDescription(), HelpName: coreCommonDocs.CreateUsage("ds rbs", releasebundlesign.GetDescription(), releasebundlesign.Usage), UsageText: releasebundlesign.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: coreCommonDocs.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return releaseBundleSignCmd(c) - }, + Action: releaseBundleSignCmd, }, { Name: "release-bundle-distribute", - Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleDistribute), + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleV1Distribute), Aliases: []string{"rbd"}, Usage: releasebundledistribute.GetDescription(), HelpName: coreCommonDocs.CreateUsage("ds rbd", releasebundledistribute.GetDescription(), releasebundledistribute.Usage), UsageText: releasebundledistribute.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: coreCommonDocs.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return releaseBundleDistributeCmd(c) - }, + Action: releaseBundleDistributeCmd, }, { Name: "release-bundle-delete", - Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleDelete), + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleV1Delete), Aliases: []string{"rbdel"}, Usage: releasebundledelete.GetDescription(), HelpName: coreCommonDocs.CreateUsage("ds rbdel", releasebundledelete.GetDescription(), releasebundledelete.Usage), UsageText: releasebundledelete.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: coreCommonDocs.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return releaseBundleDeleteCmd(c) - }, + Action: releaseBundleDeleteCmd, }, }) } @@ -338,7 +328,7 @@ func populateReleaseNotesSyntax(c *cli.Context) (distributionServicesUtils.Relea return distributionServicesUtils.PlainText, errorutils.CheckErrorf("--release-notes-syntax must be one of: markdown, asciidoc or plain_text.") } } - // If the file extension is ".md" or ".markdown", use the markdown syntax + // If the file extension is ".md" or ".markdown", use the Markdown syntax extension := strings.ToLower(filepath.Ext(c.String("release-notes-path"))) if extension == ".md" || extension == ".markdown" { return distributionServicesUtils.Markdown, nil diff --git a/docker_test.go b/docker_test.go index f418dc2d5..f0c76ef12 100644 --- a/docker_test.go +++ b/docker_test.go @@ -209,10 +209,8 @@ func TestPushFatManifestImage(t *testing.T) { // Docker daemon take times to load. In order to check if it's available we wait for a log message to indications that the Docker daemon has finished initializing. WaitFor(wait.ForLog("API listen on /var/run/docker.sock").WithStartupTimeout(5*time.Minute)). Remove(). - Build(ctx, t, true) - if err != nil { - t.Errorf("Couldn't run create buildx image. Error: %s", err.Error()) - } + Build(ctx, true) + assert.NoError(t, err, "Couldn't run create buildx image.") defer func() { assert.NoError(t, testContainer.Terminate(ctx)) }() // Enable the builder util in the container. @@ -495,7 +493,7 @@ func runKaniko(t *testing.T, imageToPush string) string { Mount(credentialsFile, "/kaniko/.docker/config.json", true). Cmd("--dockerfile="+dockerFile, "--destination="+imageToPush, "--insecure", "--skip-tls-verify", "--image-name-with-digest-file="+KanikoOutputFile). WaitFor(wait.ForExit().WithExitTimeout(300000*time.Millisecond)). - Build(context.Background(), t, true) + Build(context.Background(), true) assert.NoError(t, err) // Return a file contains the image metadata which was built by Kaniko. diff --git a/docs/artifactory/releasebundlecreate/help.go b/docs/artifactory/releasebundlecreate/help.go index 5448b96ed..91df44ceb 100644 --- a/docs/artifactory/releasebundlecreate/help.go +++ b/docs/artifactory/releasebundlecreate/help.go @@ -4,7 +4,7 @@ var Usage = []string{"ds rbc [command options] [command options] "} func GetDescription() string { - return "Create a release bundle." + return "Create a release bundle v1." } func GetArguments() string { diff --git a/docs/artifactory/releasebundledelete/help.go b/docs/artifactory/releasebundledelete/help.go index ce377d18b..ec9e1fe7a 100644 --- a/docs/artifactory/releasebundledelete/help.go +++ b/docs/artifactory/releasebundledelete/help.go @@ -3,7 +3,7 @@ package releasebundledelete var Usage = []string{"ds rbdel [command options] "} func GetDescription() string { - return "Delete a release bundle." + return "Delete a release bundle v1." } func GetArguments() string { diff --git a/docs/artifactory/releasebundledistribute/help.go b/docs/artifactory/releasebundledistribute/help.go index 0fe5459ec..b277a84d3 100644 --- a/docs/artifactory/releasebundledistribute/help.go +++ b/docs/artifactory/releasebundledistribute/help.go @@ -3,7 +3,7 @@ package releasebundledistribute var Usage = []string{"ds rbd [command options] "} func GetDescription() string { - return "Distribute a release bundle." + return "Distribute a release bundle v1." } func GetArguments() string { diff --git a/docs/artifactory/releasebundlesign/help.go b/docs/artifactory/releasebundlesign/help.go index d576353a6..977874bd8 100644 --- a/docs/artifactory/releasebundlesign/help.go +++ b/docs/artifactory/releasebundlesign/help.go @@ -3,7 +3,7 @@ package releasebundlesign var Usage = []string{"ds rbs [command options] "} func GetDescription() string { - return "Sign a release bundle." + return "Sign a release bundle v1." } func GetArguments() string { diff --git a/docs/artifactory/releasebundleupdate/help.go b/docs/artifactory/releasebundleupdate/help.go index 0f80fc4af..d7cd5541f 100644 --- a/docs/artifactory/releasebundleupdate/help.go +++ b/docs/artifactory/releasebundleupdate/help.go @@ -4,7 +4,7 @@ var Usage = []string{"ds rbu [command options] [command options] "} func GetDescription() string { - return "Updates an existing unsigned release bundle version." + return "Updates an existing unsigned release bundle v1 version." } func GetArguments() string { diff --git a/docs/common/env.go b/docs/common/env.go index 7e016e24c..105b74148 100644 --- a/docs/common/env.go +++ b/docs/common/env.go @@ -129,5 +129,5 @@ func GetGlobalEnvVars() string { func CreateEnvVars(envVars ...string) string { var s []string s = append(s, envVars...) - return strings.Join(s[:], "\n\n") + return strings.Join(s, "\n\n") } diff --git a/docs/general/login/help.go b/docs/general/login/help.go new file mode 100644 index 000000000..2b5a82c06 --- /dev/null +++ b/docs/general/login/help.go @@ -0,0 +1,7 @@ +package login + +var Usage = []string{"login"} + +func GetDescription() string { + return "Log in to a JFrog Platform via your web browser. Available for Artifactory 7.63.1 and above" +} diff --git a/docs/lifecycle/create/help.go b/docs/lifecycle/create/help.go new file mode 100644 index 000000000..c7079e3f2 --- /dev/null +++ b/docs/lifecycle/create/help.go @@ -0,0 +1,15 @@ +package create + +var Usage = []string{"rbc [command options] "} + +func GetDescription() string { + return "Create a release bundle from builds or from existing release bundles" +} + +func GetArguments() string { + return ` release bundle name + Name of the newly created Release Bundle. + + release bundle version + Version of the newly created Release Bundle.` +} diff --git a/docs/lifecycle/promote/help.go b/docs/lifecycle/promote/help.go new file mode 100644 index 000000000..b4954a8cf --- /dev/null +++ b/docs/lifecycle/promote/help.go @@ -0,0 +1,18 @@ +package promote + +var Usage = []string{"rbp [command options] "} + +func GetDescription() string { + return "Promote a release bundle" +} + +func GetArguments() string { + return ` release bundle name + Name of the Release Bundle to promote. + + release bundle version + Version of the Release Bundle to promote. + + environment + Name of the target environment for the promotion.` +} diff --git a/documentation/CLI-for-JFrog-Curation.md b/documentation/CLI-for-JFrog-Curation.md new file mode 100644 index 000000000..651068ab3 --- /dev/null +++ b/documentation/CLI-for-JFrog-Curation.md @@ -0,0 +1,68 @@ +JFrog CLI : CLI for JFrog Curation +====================================== + + +Overview +-------- +JFrog Curation enables you to block malicious or risky open-source packages entering your software supply chain. +What can you do with Curation? +* Track the open-source packages downloaded by your organization to gain centralized visibility and control. +* Prevent harmful packages from getting into your software development pipelines. +* Protect against known and unknown threats, allowing only trusted software packages into your SDLC. +* Create policies to block packages with known vulnerabilities, malicious code, operational risk, or license compliance issues. + +For more information on JFrog Curation and how to set it up, see the JFrog Curation general documentation at https://jfrog.com/help. + +JFrog Curation requires [Xray version 3.78.9](https://jfrog.com/help/r/jfrog-release-information/xray-3.78.9) and above, and [Artifactory version 7.63.5](https://jfrog.com/help/r/jfrog-release-information/artifactory-7.63) and above. It also requires Enterprise X and Enterprise + subscriptions. + +--- + +### Commands + +Audit your Project with JFrog Curation + + +**Note** +> The **curation-audit** command currently only supports npm projects. + +The **jf curation-audit** command enables developers to scan project dependencies to find packages that were blocked by the JFrog curation service. This command provides developers with more detailed information, such as whether the blocked package is the projectโ€™s direct dependency or is a transitive dependency. This information helps developers to resolve blocked packages more efficiently as they will be able to make a more informative decision based on what Policy violation occurred and what exactly needs to be resolved. + +For each blocked package the CLI provides the violated Curation Policies. The command builds a deep dependencies graph for the project, and requests the Curation status by a HEAD request for each node in the tree. It uses the package manager that is used in the project to build the dependencies graph. + +Before running the command, do the following: +1) Connect the JFrog CLI to your JFrog Platform instance by running the **jf c add** command. +2) Ensure your project is configured in the JFrog CLI with the repository you would like to resolve dependencies from. Set the repository with the **jf npmc** command inside the project directory. +

+ + +| | | +|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------| +| **Command name** | curation-audit | +| **Abbreviation** | ca | +| **Command options** | | +| --format | \[Default: table\]

Defines the output format of the command. Acceptable values are: table and json. | +| --working-dirs | \[Optional\]

A comma separated list of relative working directories, to determine the audit targets locations. | +| --threads | \[Default: 10\]

The number of parallel threads used to determine the curation status for each package in the project tree. | | + +#### **Output Example** + +![image](images/jf-ca-output.png) + + +**Example 1** + +Audit the project in the current directory. Displays all known packages that were blocked by Curation Policies. + + jf curation-audit + +**Example 2** + +Audit the projects according to the specific paths defined in the "working-dirs" option. Displays all known packages that were blocked by Curation Policies for all projects. The data is displayed in separate tables. + + jf curation-audit --working-dirs="/path/to/project/npm_project1,/path/to/project/npm_project2" + +**Example 3** + +Audit the project in the current directory using 5 threads to check the packages Curation status in parallel. Displays all known packages blocked by Curation Policies. + + jf curation-audit --threads=5 diff --git a/documentation/CLI-for-JFrog-Lifecycle.md b/documentation/CLI-for-JFrog-Lifecycle.md new file mode 100644 index 000000000..f81b7c817 --- /dev/null +++ b/documentation/CLI-for-JFrog-Lifecycle.md @@ -0,0 +1,133 @@ +JFrog CLI : CLI for JFrog Release Lifecycle Management +====================================== + + +Overview +-------- + +This page describes how to use JFrog CLI with [JFrog Release Lifecycle Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/jfrog-release-lifecycle-management-solution). + +Read more about JFrog CLI [here](https://jfrog.com/help/r/jfrog-cli). + +--- +**Note** +> JFrog Release Lifecycle Management is only available since [Artifactory 7.63.2](https://jfrog.com/help/r/jfrog-release-information/artifactory-7.63.2-cloud). +--- + +### Syntax + +When used with JFrog Release Lifecycle Management, JFrog CLI uses the following syntax: + + $ jf command-name global-options command-options arguments + +### Commands + +The following sections describe the commands available in JFrog CLI for use with JFrog Release Lifecycle Management. + +### Creating a release bundle from builds or from existing release bundles + +This commands allows creating a release bundle from one of two sources: +1. Published build infos. To use, provide the `--builds` option, which accepts a path to a JSON file of the following syntax: + ```json + { + "builds": [ + { + "name": "build name", + "number": "build number", + "project": "project" + } + ] + } + ``` + `number` is optional, latest build will be used if empty. + + `project` is optional, default project will be used if empty. + +2. Existing release bundles. To use, provide the `--release-bundles` option, which accepts a path to a JSON file of the following syntax: + ```json + { + "releaseBundles": [ + { + "name": "release bundle name", + "version": "release bundle version", + "project": "project" + } + ] + } + ``` + `project` is optional, default project will be used if empty. + +| | | +|------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Command-name | release-bundle-create | +| Abbreviation | rbc | +| Command options | | +| --builds | \[Optional\]

Path to a JSON file containing information of the source builds from which to create a release bundle. | +| --project | \[Optional\]

Project key associated with the Release Bundle version. | +| --release-bundles | \[Optional\]

Path to a JSON file containing information of the source release bundles from which to create a release bundle. | +| --server-id | \[Optional\]

Platform server ID configured using the config command. | +| --signing-key | \[Mandatory\]

The GPG/RSA key-pair name given in Artifactory. | +| --sync | \[Default: false\]

Set to true to run synchronously. | +| Command arguments | | +| release bundle name | Name of the newly created Release Bundle. | +| release bundle version | Version of the newly created Release Bundle. | + +##### Examples + +##### Example 1 + +Create a release bundle with name "myApp" and version "1.0.0", with signing key pair "myKeyPair". +The release bundle will include artifacts of the builds that were provided in the builds spec. + + jf rbc --builds=/path/to/builds-spec.json --signing-key=myKeyPair myApp 1.0.0 + +##### Example 2 + +Create a release bundle with name "myApp" and version "1.0.0", with signing key pair "myKeyPair". +The release bundle will include artifacts of the release bundles that were provided in the release bundles spec. + + jf ds rbc --spec=/path/to/release-bundles-spec.json --signing-key=myKeyPair myApp 1.0.0 + +##### Example 3 + +Create a release bundle synchronously with name "myApp" and version "1.0.0", in project "project0", with signing key pair "myKeyPair". +The release bundle will include artifacts of the release bundles that were provided in the release bundles spec. + + jf ds rbc --spec=/path/to/release-bundles-spec.json --signing-key=myKeyPair --sync=true --project=project0 myApp 1.0.0 + +### Promoting a release bundle + +This commands allows promoting a release bundle to a target environment. + +| | | +|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Command-name | release-bundle-promote | +| Abbreviation | rbp | +| Command options | | +| --overwrite | \[Default: false\]

Set to true to replace artifacts with the same name but a different checksum if such already exist at the promotion targets. By default, the promotion is stopped in a case of such conflict | +| --project | \[Optional\]

Project key associated with the Release Bundle version. | +| --server-id | \[Optional\]

Platform server ID configured using the config command. | +| --signing-key | \[Mandatory\]

The GPG/RSA key-pair name given in Artifactory. | +| --sync | \[Default: false\]

Set to true to run synchronously. | +| Command arguments | | +| release bundle name | Name of the Release Bundle to promote. | +| release bundle version | Version of the Release Bundle to promote. | +| environment | Name of the target environment for the promotion. | + + +##### Examples + +##### Example 1 + +Promote a release bundle named "myApp" version "1.0.0" to environment "PROD". +Use signing key pair "myKeyPair". + + jf rbp --signing-key=myKeyPair myApp 1.0.0 PROD + +##### Example 2 + +Promote a release bundle synchronously to environment "PROD". +The release bundle is named "myApp", version "1.0.0", of project "project0". +Use signing key pair "myKeyPair" and overwrite at conflict. + + jf rbp --signing-key=myKeyPair --project=project0 --overwrite=true --sync=true myApp 1.0.0 PROD diff --git a/documentation/cli.ftmap b/documentation/cli.ftmap index 8a14c4de4..b64bc4a40 100644 --- a/documentation/cli.ftmap +++ b/documentation/cli.ftmap @@ -13,6 +13,10 @@ - + + + + + diff --git a/documentation/images/jf-ca-output.png b/documentation/images/jf-ca-output.png new file mode 100644 index 000000000..43b12a4b5 Binary files /dev/null and b/documentation/images/jf-ca-output.png differ diff --git a/general/cisetup/cisetup.go b/general/cisetup/cisetup.go index 1396c8559..450c04ad5 100644 --- a/general/cisetup/cisetup.go +++ b/general/cisetup/cisetup.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "golang.org/x/exp/slices" "os" "path" "path/filepath" @@ -170,8 +171,8 @@ func (cc *CiSetupCommand) Run() error { return err } // Ask the user which CI he tries to setup - err = cc.ciProviderPhase() - err = saveIfNoError(err, cc.data) + cc.ciProviderPhase() + err = saveVcsConf(cc.data) if err != nil { return err } @@ -298,6 +299,7 @@ func getPipelinesToken() (string, error) { if err != nil { return "", err } + //nolint:unconvert byteToken, err = term.ReadPassword(int(syscall.Stdin)) if err != nil { return "", errorutils.CheckError(err) @@ -494,7 +496,7 @@ func (cc *CiSetupCommand) getGithubActionsCompletionInstruction(githubActionFile } func (cc *CiSetupCommand) logCompletionInstruction(ciSpecificInstructions []string) error { - instructions := append(ciSpecificInstructions, + instructions := append(slices.Clone(ciSpecificInstructions), coreutils.PrintTitle("Allowing developers to access this pipeline from their IDE"), "You have the option of viewing the new pipeline's runs from within IntelliJ IDEA.", "To achieve this, follow these steps:", @@ -519,7 +521,7 @@ func getPipelineUiPath(pipelinesUrl, pipelineName string) string { func (cc *CiSetupCommand) publishFirstBuild() (err error) { cc.data.BuildName = fmt.Sprintf("%s-%s", cc.data.RepositoryName, cc.data.GitBranch) // Run BAG Command (in order to publish the first, empty, build info) - buildAddGitConfigurationCmd := buildinfo.NewBuildAddGitCommand().SetDotGitPath(cc.data.LocalDirPath).SetServerId(cisetup.ConfigServerId) //.SetConfigFilePath(c.String("config")) + buildAddGitConfigurationCmd := buildinfo.NewBuildAddGitCommand().SetDotGitPath(cc.data.LocalDirPath).SetServerId(cisetup.ConfigServerId) buildConfiguration := rtutils.NewBuildConfiguration(cc.data.BuildName, DefaultFirstBuildNumber, "", "") buildAddGitConfigurationCmd = buildAddGitConfigurationCmd.SetBuildConfiguration(buildConfiguration) log.Info("Generating an initial build-info...") @@ -567,10 +569,10 @@ func (cc *CiSetupCommand) xrayConfigPhase() (err error) { err = xrayManager.CreatePolicy(policyParams) if err != nil { // In case the error is from type PolicyAlreadyExistsError, we should continue with the regular flow. - if _, ok := err.(*xrayservices.PolicyAlreadyExistsError); !ok { + if paeErr, ok := err.(*xrayservices.PolicyAlreadyExistsError); !ok { return err } else { - log.Debug(err.(*xrayservices.PolicyAlreadyExistsError).InnerError) + log.Debug(paeErr.InnerError) } } // Create new default watcher. @@ -589,10 +591,10 @@ func (cc *CiSetupCommand) xrayConfigPhase() (err error) { err = xrayManager.CreateWatch(watchParams) if err != nil { // In case the error is from type WatchAlreadyExistsError, we should continue with the regular flow. - if _, ok := err.(*xrayservices.WatchAlreadyExistsError); !ok { + if waeErr, ok := err.(*xrayservices.WatchAlreadyExistsError); !ok { return err } else { - log.Debug(err.(*xrayservices.WatchAlreadyExistsError).InnerError) + log.Debug(waeErr.InnerError) err = nil } } @@ -963,6 +965,7 @@ func (cc *CiSetupCommand) gitPhase() (err error) { if err != nil { return err } + //nolint:unconvert byteToken, err := term.ReadPassword(int(syscall.Stdin)) if err != nil { log.Error(err) @@ -986,10 +989,9 @@ func (cc *CiSetupCommand) gitPhase() (err error) { } } -func (cc *CiSetupCommand) ciProviderPhase() (err error) { - var ciType string +func (cc *CiSetupCommand) ciProviderPhase() { for { - ciType, err = promptCiProviderSelection() + ciType, err := promptCiProviderSelection() if err != nil { log.Error(err) continue @@ -1027,7 +1029,7 @@ func (cc *CiSetupCommand) ciProviderPhase() (err error) { _, err = pipelinesMgr.GetSystemInfo() if err == nil { cc.data.CiType = cisetup.CiType(ciType) - return nil + return } log.Error(err) if _, ok := err.(*pipelinesservices.PipelinesNotAvailableError); ok { @@ -1038,7 +1040,7 @@ func (cc *CiSetupCommand) ciProviderPhase() (err error) { } } else { // The user doesn't choose Pipelines. cc.data.CiType = cisetup.CiType(ciType) - return nil + return } } } diff --git a/general/login/cli.go b/general/login/cli.go new file mode 100644 index 000000000..437142240 --- /dev/null +++ b/general/login/cli.go @@ -0,0 +1,14 @@ +package login + +import ( + coreLogin "github.com/jfrog/jfrog-cli-core/v2/general/login" + "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/urfave/cli" +) + +func LoginCmd(c *cli.Context) error { + if c.NArg() > 0 { + return cliutils.WrongNumberOfArgumentsHandler(c) + } + return coreLogin.NewLoginCommand().Run() +} diff --git a/general/project/cli.go b/general/project/cli.go index 64c32726c..f1a3dd758 100644 --- a/general/project/cli.go +++ b/general/project/cli.go @@ -23,9 +23,7 @@ func GetCommands() []cli.Command { Flags: cliutils.GetCommandFlags(cliutils.InitProject), HelpName: corecommon.CreateUsage("project init", projectinit.GetDescription(), projectinit.Usage), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return initProject(c) - }, + Action: initProject, }, }) } diff --git a/go.mod b/go.mod index c91291965..8567954b4 100644 --- a/go.mod +++ b/go.mod @@ -6,27 +6,27 @@ require ( github.com/agnivade/levenshtein v1.1.1 github.com/buger/jsonparser v1.1.1 github.com/go-git/go-git/v5 v5.7.0 - github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602 + github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d github.com/jfrog/build-info-go v1.9.6 github.com/jfrog/gofrog v1.3.0 - github.com/jfrog/jfrog-cli-core/v2 v2.35.0 - github.com/jfrog/jfrog-client-go v1.30.0 + github.com/jfrog/jfrog-cli-core/v2 v2.39.2 + github.com/jfrog/jfrog-client-go v1.31.2 github.com/jszwec/csvutil v1.8.0 github.com/mholt/archiver/v3 v3.5.1 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.8.4 - github.com/testcontainers/testcontainers-go v0.20.1 - github.com/urfave/cli v1.22.13 + github.com/testcontainers/testcontainers-go v0.21.0 + github.com/urfave/cli v1.22.14 github.com/vbauerster/mpb/v7 v7.5.3 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/term v0.8.0 + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df + golang.org/x/term v0.9.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/BurntSushi/toml v1.2.1 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/CycloneDX/cyclonedx-go v0.7.1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect @@ -77,7 +77,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/patternmatcher v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect + github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/nwaples/rardecode v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -108,13 +108,13 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect golang.org/x/crypto v0.9.0 // indirect - golang.org/x/mod v0.10.0 // indirect + golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.9.0 // indirect golang.org/x/text v0.9.0 // indirect - google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect - google.golang.org/grpc v1.52.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.53.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -123,8 +123,8 @@ require ( // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go -replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230613104333-33061fa53a01 +//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 dev // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.2.6-0.20230418122323-2bf299dd6d27 -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230614081045-ef833fcb4fdd +//replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230717090738-b2e0c7bcc026 diff --git a/go.sum b/go.sum index 35e394b39..0dc8a1067 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CycloneDX/cyclonedx-go v0.7.1 h1:5w1SxjGm9MTMNTuRbEPyw21ObdbaagTWF/KfF0qHTRE= github.com/CycloneDX/cyclonedx-go v0.7.1/go.mod h1:N/nrdWQI2SIjaACyyDs/u7+ddCkyl/zkNs8xFsHF2Ps= @@ -102,7 +102,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -147,8 +147,8 @@ github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhc github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602 h1:HSpPf+lPYwzoJNup34uegmOQk5Qm83S+wpu8anTDJkg= -github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= +github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw= +github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -238,10 +238,10 @@ github.com/jfrog/build-info-go v1.9.6 h1:lCJ2j5uXAlJsSwDe5J8WD7Co1f/hUlZvMfwfb5A github.com/jfrog/build-info-go v1.9.6/go.mod h1:GbuFS+viHCKZYx9nWHYu7ab1DgQkFdtVN3BJPUNb2D4= github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk= github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0= -github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230613104333-33061fa53a01 h1:MvKxuFsgCeIL74qeXJ7Z6rbDO0tfE15M3D24U0kGgFs= -github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20230613104333-33061fa53a01/go.mod h1:Kzh4oTlJu1iYFNQcgAHgKIMvsvgC5LN2DlV/NHWCXZM= -github.com/jfrog/jfrog-client-go v1.28.1-0.20230614081045-ef833fcb4fdd h1:/X2eIts0BRy3Y6AhzBnM+8Dmrl0assoBFG1iyW6Jq8U= -github.com/jfrog/jfrog-client-go v1.28.1-0.20230614081045-ef833fcb4fdd/go.mod h1:qEJxoe68sUtqHJ1YhXv/7pKYP/9p1D5tJrruzJKYeoI= +github.com/jfrog/jfrog-cli-core/v2 v2.39.2 h1:T0h+acOkaRqwrZyzizzL7lO+Yo2KpGcAypITHxKWSEI= +github.com/jfrog/jfrog-cli-core/v2 v2.39.2/go.mod h1:/HJ9mO3AZsACtQWxkwMj7REWPdXT3yHKjJXjPHlmB34= +github.com/jfrog/jfrog-client-go v1.31.2 h1:foy8owM2lS8jZL7zuBPtcx1RpF1GeIXaXF8hIufyr4I= +github.com/jfrog/jfrog-client-go v1.31.2/go.mod h1:qEJxoe68sUtqHJ1YhXv/7pKYP/9p1D5tJrruzJKYeoI= 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.8.0 h1:G7vS2LGdpZZDH1HmHeNbxOaJ/ZnJlpwGFvOkTkJzzNk= @@ -300,8 +300,8 @@ github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YO github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f h1:J/7hjLaHLD7epG0m6TBMGmp4NQ+ibBYLfeyJWdAIFLA= -github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= @@ -376,20 +376,19 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/testcontainers/testcontainers-go v0.20.1 h1:mK15UPJ8c5P+NsQKmkqzs/jMdJt6JMs5vlw2y4j92c0= -github.com/testcontainers/testcontainers-go v0.20.1/go.mod h1:zb+NOlCQBkZ7RQp4QI+YMIHyO2CQ/qsXzNF5eLJ24SY= +github.com/testcontainers/testcontainers-go v0.21.0 h1:syePAxdeTzfkap+RrJaQZpJQ/s/fsUgn11xIvHrOE9U= +github.com/testcontainers/testcontainers-go v0.21.0/go.mod h1:c1ez3WVRHq7T/Aj+X3TIipFBwkBaNT5iNCY8+1b83Ng= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.13 h1:wsLILXG8qCJNse/qAgLNf23737Cx05GflHg/PJGe1Ok= -github.com/urfave/cli v1.22.13/go.mod h1:VufqObjsMTF2BBwKawpx9R8eAneNEWhoO0yx8Vd+FkE= +github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= +github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= github.com/vbauerster/mpb/v7 v7.5.3 h1:BkGfmb6nMrrBQDFECR/Q7RkKCw7ylMetCb4079CGs4w= github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9AhY/PnuOE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -443,8 +442,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 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-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= 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= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -470,8 +469,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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= @@ -598,15 +597,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= 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= @@ -675,6 +674,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= @@ -742,8 +742,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -760,8 +760,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/go_test.go b/go_test.go index d2559db76..1b00960c0 100644 --- a/go_test.go +++ b/go_test.go @@ -31,7 +31,7 @@ func TestGoConfigWithModuleNameChange(t *testing.T) { wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - prepareGoProject("project1", "", t, true) + prepareGoProject("project1", t, true) runGo(t, ModuleNameJFrogTest, tests.GoBuildName, buildNumber, 4, 0, "go", "build", "--mod=mod", "--build-name="+tests.GoBuildName, "--build-number="+buildNumber, "--module="+ModuleNameJFrogTest) clientTestUtils.ChangeDirAndAssert(t, wd) @@ -44,7 +44,7 @@ func TestGoGetSpecificVersion(t *testing.T) { buildNumber := "1" wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - prepareGoProject("project1", "", t, true) + prepareGoProject("project1", t, true) // Build and publish a go project. // We do so in order to make sure the rsc.io/quote:v1.5.2 will be available for the get command runGo(t, "", tests.GoBuildName, buildNumber, 4, 0, "go", "build", "--mod=mod", "--build-name="+tests.GoBuildName, "--build-number="+buildNumber) @@ -87,7 +87,7 @@ func TestGoGetNestedPackage(t *testing.T) { defer cleanUpFunc() wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - prepareGoProject("project1", "", t, true) + prepareGoProject("project1", t, true) jfrogCli := tests.NewJfrogCli(execMain, "jfrog", "") // Download 'mockgen', which is a nested package inside 'github.com/golang/mock@v1.4.1'. Then validate it was downloaded correctly. @@ -112,9 +112,9 @@ func TestGoPublishResolve(t *testing.T) { defer cleanUpFunc() wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - project1Path := prepareGoProject("project1", "", t, true) + project1Path := prepareGoProject("project1", t, true) clientTestUtils.ChangeDirAndAssert(t, wd) - project2Path := prepareGoProject("project2", "", t, true) + project2Path := prepareGoProject("project2", t, true) clientTestUtils.ChangeDirAndAssert(t, project1Path) // Build the first project and download its dependencies from Artifactory @@ -145,7 +145,7 @@ func TestGoPublishWithDetailedSummary(t *testing.T) { // Init environment wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - projectPath := prepareGoProject("project1", "", t, true) + projectPath := prepareGoProject("project1", t, true) // Publish with detailed summary and buildinfo. // Build project @@ -190,7 +190,7 @@ func TestGoPublishWithDeploymentView(t *testing.T) { wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - prepareGoProject("project1", "", t, true) + prepareGoProject("project1", t, true) jfrogCli := tests.NewJfrogCli(execMain, "jf", "") err = execGo(jfrogCli, "gp", "v1.1.1") if err != nil { @@ -203,13 +203,63 @@ func TestGoPublishWithDeploymentView(t *testing.T) { clientTestUtils.ChangeDirAndAssert(t, wd) } +func TestGoPublishWithExclusions(t *testing.T) { + _, goCleanupFunc := initGoTest(t) + defer goCleanupFunc() + wd, err := os.Getwd() + assert.NoError(t, err, "Failed to get current dir") + searchFilePath, err := tests.CreateSpec(tests.GoPublishRepoExcludes) + assert.NoError(t, err) + + var testData = []struct { + exclusions string + expectedExistFilesPaths []string + expectedNotExistFilesPaths []string + }{ + {"./dir1/*", tests.GetGoPublishWithExclusionsExpectedFiles1(), tests.GetGoPublishWithExclusionsExcludedFiles1()}, + {"./dir1/dir2/*", tests.GetGoPublishWithExclusionsExpectedFiles2(), tests.GetGoPublishWithExclusionsExcludedFiles2()}, + {"*.txt", nil, tests.GetGoPublishWithExclusionsExcludedFiles3()}, + } + for _, test := range testData { + prepareGoProject("project4", t, true) + jfrogCli := tests.NewJfrogCli(execMain, "jf", "") + err = execGo(jfrogCli, "gp", "v1.1.1", "--exclusions", test.exclusions) + assert.NoError(t, err) + + // Verify that go-publish successfully published expected files and directories to Artifactory. + inttestutils.VerifyExistInArtifactory(tests.GetGoPublishWithExclusionsExpectedRepoGo(), searchFilePath, serverDetails, t) + // Creating a temporary directory to download for it the content of the zip file from artifactory. + tmpDir, createTempDirCallback := coretests.CreateTempDirWithCallbackAndAssert(t) + err = os.RemoveAll(tmpDir) + assert.NoError(t, err) + assert.NoError(t, os.Mkdir(tmpDir, 0777)) + runRt(t, "download", tests.GoRepo, tmpDir+"/", "--explode") + // Checking whether the expected files exist in the zip file after downloading from artifactory with unzipping it. + for _, path := range test.expectedExistFilesPaths { + result, err := fileutils.IsFileExists(filepath.Join(tmpDir, path), true) + assert.NoError(t, err) + assert.True(t, result, "This file"+path+"does not exist") + } + // Checking whether the excluded files do not exist in the zip file after downloading from Artifactory with unzipping it. + for _, path := range test.expectedNotExistFilesPaths { + result, err := fileutils.IsFileExists(filepath.Join(tmpDir, path), true) + assert.NoError(t, err) + assert.False(t, result) + } + // Delete the temporary dir. + createTempDirCallback() + // Restore workspace. + clientTestUtils.ChangeDirAndAssert(t, wd) + } +} + func TestGoVcsFallback(t *testing.T) { _, cleanUpFunc := initGoTest(t) defer cleanUpFunc() wd, err := os.Getwd() assert.NoError(t, err, "Failed to get current dir") - _ = prepareGoProject("vcsfallback", "", t, false) + _ = prepareGoProject("vcsfallback", t, false) jfrogCli := tests.NewJfrogCli(execMain, "jfrog", "") // Run "go get github.com/octocat/Hello-World" with --no-fallback. @@ -225,17 +275,14 @@ func TestGoVcsFallback(t *testing.T) { clientTestUtils.ChangeDirAndAssert(t, wd) } -func prepareGoProject(projectName, configDestDir string, t *testing.T, copyDirs bool) string { +func prepareGoProject(projectName string, t *testing.T, copyDirs bool) string { projectPath := createGoProject(t, projectName, copyDirs) testdataTarget := filepath.Join(tests.Out, "testdata") testdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "testdata") err := fileutils.CopyDir(testdataSrc, testdataTarget, copyDirs, nil) assert.NoError(t, err) - if configDestDir == "" { - configDestDir = filepath.Join(projectPath, ".jfrog") - } configFileDir := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", projectName, ".jfrog", "projects") - _, err = tests.ReplaceTemplateVariables(filepath.Join(configFileDir, "go.yaml"), filepath.Join(configDestDir, "projects")) + _, err = tests.ReplaceTemplateVariables(filepath.Join(configFileDir, "go.yaml"), filepath.Join(projectPath, ".jfrog", "projects")) assert.NoError(t, err) clientTestUtils.ChangeDirAndAssert(t, projectPath) log.Info("Using Go project located at", projectPath) diff --git a/gradle_test.go b/gradle_test.go index c89f8ca12..773521091 100644 --- a/gradle_test.go +++ b/gradle_test.go @@ -74,7 +74,8 @@ func TestGradleBuildWithServerID(t *testing.T) { createConfigFile(destPath, configFilePath, t) oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath)) buildNumber := "1" - buildGradlePath = strings.Replace(buildGradlePath, `\`, "/", -1) // Windows compatibility. + // Windows compatibility + buildGradlePath = strings.ReplaceAll(buildGradlePath, `\`, "/") runJfrogCli(t, "gradle", "clean artifactoryPublish", "-b"+buildGradlePath, "--build-name="+tests.GradleBuildName, "--build-number="+buildNumber) clientTestUtils.ChangeDirAndAssert(t, oldHomeDir) // Validate @@ -106,7 +107,8 @@ func TestGradleBuildWithServerIDAndDetailedSummary(t *testing.T) { createConfigFile(destPath, configFilePath, t) oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath)) buildNumber := "1" - buildGradlePath = strings.Replace(buildGradlePath, `\`, "/", -1) // Windows compatibility. + // Windows compatibility. + buildGradlePath = strings.ReplaceAll(buildGradlePath, `\`, "/") // Test gradle with detailed summary without buildinfo props. filteredGradleArgs := []string{"clean artifactoryPublish", "-b" + buildGradlePath} diff --git a/inttestutils/docker.go b/inttestutils/docker.go index 44f496d39..5b537d2db 100644 --- a/inttestutils/docker.go +++ b/inttestutils/docker.go @@ -51,7 +51,7 @@ func (image *BuildDockerImage) GetCmd() *exec.Cmd { } cmd = append(cmd, image.buildContext) - return exec.Command(image.containerManager.String(), cmd[:]...) + return exec.Command(image.containerManager.String(), cmd...) } func (image *BuildDockerImage) GetEnv() map[string]string { @@ -82,7 +82,7 @@ func (e *ExecDockerImage) GetCmd() *exec.Cmd { var cmd []string cmd = append(cmd, "exec") cmd = append(cmd, e.Args...) - return exec.Command(e.containerManager.String(), cmd[:]...) + return exec.Command(e.containerManager.String(), cmd...) } func (e *ExecDockerImage) GetEnv() map[string]string { @@ -118,7 +118,7 @@ func (run *RunDockerImage) GetCmd() *exec.Cmd { var cmd []string cmd = append(cmd, "run") cmd = append(cmd, run.Args...) - return exec.Command(run.containerManager.String(), cmd[:]...) + return exec.Command(run.containerManager.String(), cmd...) } func (run *RunDockerImage) GetEnv() map[string]string { @@ -147,7 +147,7 @@ func (image *DeleteDockerImage) GetCmd() *exec.Cmd { cmd = append(cmd, "image") cmd = append(cmd, "rm") cmd = append(cmd, image.imageTag) - return exec.Command(image.containerManager.String(), cmd[:]...) + return exec.Command(image.containerManager.String(), cmd...) } func (image *DeleteDockerImage) GetEnv() map[string]string { @@ -176,7 +176,7 @@ func (image *DeleteContainer) GetCmd() *exec.Cmd { cmd = append(cmd, "rm") cmd = append(cmd, "--force") cmd = append(cmd, image.containerName) - return exec.Command(image.containerManager.String(), cmd[:]...) + return exec.Command(image.containerManager.String(), cmd...) } func (image *DeleteContainer) GetEnv() map[string]string { diff --git a/lifecycle/cli.go b/lifecycle/cli.go new file mode 100644 index 000000000..8caa332d2 --- /dev/null +++ b/lifecycle/cli.go @@ -0,0 +1,134 @@ +package lifecycle + +import ( + "errors" + "github.com/jfrog/jfrog-cli-core/v2/common/commands" + coreCommon "github.com/jfrog/jfrog-cli-core/v2/docs/common" + "github.com/jfrog/jfrog-cli-core/v2/lifecycle" + coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli/docs/common" + rbCreate "github.com/jfrog/jfrog-cli/docs/lifecycle/create" + rbPromote "github.com/jfrog/jfrog-cli/docs/lifecycle/promote" + "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/urfave/cli" +) + +const lcCategory = "Lifecycle" + +func GetCommands() []cli.Command { + return cliutils.GetSortedCommands(cli.CommandsByName{ + { + Name: "release-bundle-create", + Aliases: []string{"rbc"}, + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundleCreate), + Usage: rbCreate.GetDescription(), + HelpName: coreCommon.CreateUsage("release-bundle-create", rbCreate.GetDescription(), rbCreate.Usage), + UsageText: rbCreate.GetArguments(), + ArgsUsage: common.CreateEnvVars(), + BashComplete: coreCommon.CreateBashCompletionFunc(), + Category: lcCategory, + Action: create, + }, + { + Name: "release-bundle-promote", + Aliases: []string{"rbp"}, + Flags: cliutils.GetCommandFlags(cliutils.ReleaseBundlePromote), + Usage: rbPromote.GetDescription(), + HelpName: coreCommon.CreateUsage("release-bundle-promote", rbPromote.GetDescription(), rbPromote.Usage), + UsageText: rbPromote.GetArguments(), + ArgsUsage: common.CreateEnvVars(), + BashComplete: coreCommon.CreateBashCompletionFunc(), + Category: lcCategory, + Action: promote, + }, + }) +} + +func validateCreateReleaseBundleContext(c *cli.Context) error { + if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil { + return err + } + + if c.NArg() != 2 { + return cliutils.WrongNumberOfArgumentsHandler(c) + } + + if err := assertSigningKeyProvided(c); err != nil { + return err + } + + bothProvided := c.IsSet(cliutils.Builds) && c.IsSet(cliutils.ReleaseBundles) + noneProvided := !c.IsSet(cliutils.Builds) && !c.IsSet(cliutils.ReleaseBundles) + if bothProvided || noneProvided { + return errorutils.CheckErrorf("exactly one of the following options must be supplied: --%s or --%s", cliutils.Builds, cliutils.ReleaseBundles) + } + return nil +} + +func create(c *cli.Context) (err error) { + if err = validateCreateReleaseBundleContext(c); err != nil { + return err + } + + lcDetails, err := createLifecycleDetailsByFlags(c) + if err != nil { + return + } + + createCmd := lifecycle.NewReleaseBundleCreate().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)). + SetReleaseBundleVersion(c.Args().Get(1)).SetSigningKeyName(c.String(cliutils.SigningKey)).SetSync(c.Bool(cliutils.Sync)). + SetReleaseBundleProject(cliutils.GetProject(c)).SetBuildsSpecPath(c.String(cliutils.Builds)). + SetReleaseBundlesSpecPath(c.String(cliutils.ReleaseBundles)) + return commands.Exec(createCmd) +} + +func promote(c *cli.Context) error { + if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil { + return err + } + + if c.NArg() != 3 { + return cliutils.WrongNumberOfArgumentsHandler(c) + } + + if err := assertSigningKeyProvided(c); err != nil { + return err + } + + lcDetails, err := createLifecycleDetailsByFlags(c) + if err != nil { + return err + } + + createCmd := lifecycle.NewReleaseBundlePromote().SetServerDetails(lcDetails).SetReleaseBundleName(c.Args().Get(0)). + SetReleaseBundleVersion(c.Args().Get(1)).SetEnvironment(c.Args().Get(2)).SetSigningKeyName(c.String(cliutils.SigningKey)). + SetSync(c.Bool(cliutils.Sync)).SetReleaseBundleProject(cliutils.GetProject(c)).SetOverwrite(c.Bool(cliutils.Overwrite)) + return commands.Exec(createCmd) +} + +func assertSigningKeyProvided(c *cli.Context) error { + if c.String(cliutils.SigningKey) == "" { + return errorutils.CheckErrorf("the --%s option is mandatory", cliutils.SigningKey) + } + return nil +} + +func createLifecycleDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) { + lcDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, false, cliutils.Platform) + if err != nil { + return nil, err + } + if lcDetails.Url == "" { + return nil, errors.New("platform URL is mandatory for lifecycle commands") + } + PlatformToLifecycleUrls(lcDetails) + return lcDetails, nil +} + +func PlatformToLifecycleUrls(lcDetails *coreConfig.ServerDetails) { + lcDetails.ArtifactoryUrl = utils.AddTrailingSlashIfNeeded(lcDetails.Url) + "artifactory/" + lcDetails.LifecycleUrl = utils.AddTrailingSlashIfNeeded(lcDetails.Url) + "lifecycle/" + lcDetails.Url = "" +} diff --git a/lifecycle/cli_test.go b/lifecycle/cli_test.go new file mode 100644 index 000000000..9da70f718 --- /dev/null +++ b/lifecycle/cli_test.go @@ -0,0 +1,42 @@ +package lifecycle + +import ( + "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/jfrog/jfrog-cli/utils/tests" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestValidateCreateReleaseBundleContext(t *testing.T) { + testRuns := []struct { + name string + args []string + flags []string + expectError bool + }{ + {"withoutArgs", []string{}, []string{}, true}, + {"oneArg", []string{"one"}, []string{}, true}, + {"twoArgs", []string{"one", "two"}, []string{}, true}, + {"extraArgs", []string{"one", "two", "three", "four"}, []string{}, true}, + {"bothSources", []string{"one", "two", "three"}, []string{cliutils.Builds + "=/path/to/file", cliutils.ReleaseBundles + "=/path/to/file"}, true}, + {"noSources", []string{"one", "two", "three"}, []string{}, true}, + {"builds without signing key", []string{"name", "version"}, []string{cliutils.Builds + "=/path/to/file"}, true}, + {"builds correct", []string{"name", "version"}, []string{ + cliutils.Builds + "=/path/to/file", cliutils.SigningKey + "=key"}, false}, + {"releaseBundles without signing key", []string{"name", "version", "env"}, []string{cliutils.ReleaseBundles + "=/path/to/file"}, true}, + {"releaseBundles", []string{"name", "version"}, []string{ + cliutils.ReleaseBundles + "=/path/to/file", cliutils.SigningKey + "=key"}, false}, + } + + for _, test := range testRuns { + t.Run(test.name, func(t *testing.T) { + context, buffer := tests.CreateContext(t, test.flags, test.args) + err := validateCreateReleaseBundleContext(context) + if test.expectError { + assert.Error(t, err, buffer) + } else { + assert.NoError(t, err, buffer) + } + }) + } +} diff --git a/lifecycle_test.go b/lifecycle_test.go new file mode 100644 index 000000000..24980c734 --- /dev/null +++ b/lifecycle_test.go @@ -0,0 +1,275 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + configUtils "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli/inttestutils" + lifecycleCli "github.com/jfrog/jfrog-cli/lifecycle" + "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/jfrog/jfrog-cli/utils/tests" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "github.com/jfrog/jfrog-client-go/lifecycle" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + clientUtils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/stretchr/testify/assert" + "net/http" + "os" + "path/filepath" + "testing" +) + +const ( + rbMinVersion = "7.45.0" + gpgKeyPairName = "lc-tests-key-pair" + lcTestdataPath = "lifecycle" + releaseBundlesSpec = "release-bundles-spec.json" + buildsSpec12 = "builds-spec-1-2.json" + buildsSpec3 = "builds-spec-3.json" + prodEnvironment = "PROD" + number1, number2, number3 = "111", "222", "333" +) + +var ( + lcDetails *configUtils.ServerDetails + lcCli *tests.JfrogCli +) + +func TestLifecycle(t *testing.T) { + initLifecycleTest(t) + defer cleanLifecycleTests(t) + lcManager := getLcServiceManager(t) + + // Upload builds to create release bundles from. + deleteBuilds := uploadBuilds(t) + defer deleteBuilds() + + // Create release bundles from builds synchronously. + createRb(t, buildsSpec12, cliutils.Builds, tests.LcRbName1, number1, true) + defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1) + + // Create release bundles from builds asynchronously and assert status. + createRb(t, buildsSpec3, cliutils.Builds, tests.LcRbName2, number2, false) + defer deleteReleaseBundle(t, lcManager, tests.LcRbName2, number2) + assertStatusCompleted(t, lcManager, tests.LcRbName2, number2, "") + + // Create a combined release bundle from the two previous release bundle. + createRb(t, releaseBundlesSpec, cliutils.ReleaseBundles, tests.LcRbName3, number3, true) + defer deleteReleaseBundle(t, lcManager, tests.LcRbName3, number3) + + // Promote the last release bundle. + promoteRb(t, lcManager, number3) + + // Verify the artifacts of both the initial release bundles made it to the prod repo. + searchSpec, err := tests.CreateSpec(tests.SearchAllProdRepo) + assert.NoError(t, err) + inttestutils.VerifyExistInArtifactory(tests.GetExpectedLifecycleArtifacts(), searchSpec, serverDetails, t) +} + +func uploadBuilds(t *testing.T) func() { + uploadBuild(t, tests.UploadDevSpecA, tests.LcBuildName1, number1) + uploadBuild(t, tests.UploadDevSpecB, tests.LcBuildName2, number2) + uploadBuild(t, tests.UploadDevSpecC, tests.LcBuildName3, number3) + return func() { + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName1, artHttpDetails) + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName2, artHttpDetails) + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName3, artHttpDetails) + } +} + +func createRb(t *testing.T, specName, sourceOption, buildName, buildNumber string, sync bool) { + specFile, err := getSpecFile(specName) + assert.NoError(t, err) + argsAndOptions := []string{ + "rbc", + buildName, + buildNumber, + getOption(sourceOption, specFile), + getOption(cliutils.SigningKey, gpgKeyPairName), + } + // Add the --sync option only if requested, to test the default value. + if sync { + argsAndOptions = append(argsAndOptions, getOption(cliutils.Sync, "true")) + } + assert.NoError(t, lcCli.Exec(argsAndOptions...)) +} + +func getOption(option, value string) string { + return fmt.Sprintf("--%s=%s", option, value) +} + +func promoteRb(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbVersion string) { + output := lcCli.RunCliCmdWithOutput(t, "rbp", tests.LcRbName3, rbVersion, prodEnvironment, + getOption(cliutils.SigningKey, gpgKeyPairName), + getOption(cliutils.Overwrite, "true"), + "--project=default") + var promotionResp services.RbPromotionResp + if !assert.NoError(t, json.Unmarshal([]byte(output), &promotionResp)) { + return + } + assertStatusCompleted(t, lcManager, tests.LcRbName3, rbVersion, promotionResp.CreatedMillis.String()) +} + +func getSpecFile(fileName string) (string, error) { + source := filepath.Join(tests.GetTestResourcesPath(), lcTestdataPath, fileName) + return tests.ReplaceTemplateVariables(source, "") +} + +// If createdMillis is provided, assert status for promotion. If blank, assert for creation. +func assertStatusCompleted(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, createdMillis string) { + resp, err := getStatus(lcManager, rbName, rbVersion, createdMillis) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, services.Completed, resp.Status) +} + +func getLcServiceManager(t *testing.T) *lifecycle.LifecycleServicesManager { + lcManager, err := utils.CreateLifecycleServiceManager(lcDetails, false) + assert.NoError(t, err) + return lcManager +} + +func authenticateLifecycle() string { + *tests.JfrogUrl = clientUtils.AddTrailingSlashIfNeeded(*tests.JfrogUrl) + lcDetails = &configUtils.ServerDetails{ + Url: *tests.JfrogUrl} + lifecycleCli.PlatformToLifecycleUrls(lcDetails) + + cred := fmt.Sprintf("--url=%s", *tests.JfrogUrl) + if *tests.JfrogAccessToken != "" { + lcDetails.AccessToken = *tests.JfrogAccessToken + cred += fmt.Sprintf(" --access-token=%s", lcDetails.AccessToken) + } else { + lcDetails.User = *tests.JfrogUser + lcDetails.Password = *tests.JfrogPassword + cred += fmt.Sprintf(" --user=%s --password=%s", lcDetails.User, lcDetails.Password) + } + return cred +} + +func getStatus(lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, createdMillis string) (services.ReleaseBundleStatusResponse, error) { + rbDetails := services.ReleaseBundleDetails{ + ReleaseBundleName: rbName, + ReleaseBundleVersion: rbVersion, + } + + if createdMillis == "" { + return lcManager.GetReleaseBundleCreationStatus(rbDetails, "", true) + } + return lcManager.GetReleaseBundlePromotionStatus(rbDetails, "", createdMillis, true) +} + +func deleteReleaseBundle(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion string) { + rbDetails := services.ReleaseBundleDetails{ + ReleaseBundleName: rbName, + ReleaseBundleVersion: rbVersion, + } + + assert.NoError(t, lcManager.DeleteReleaseBundle(rbDetails, services.ReleaseBundleQueryParams{Async: false})) +} + +func uploadBuild(t *testing.T, specFileName, buildName, buildNumber string) { + specFile, err := tests.CreateSpec(specFileName) + assert.NoError(t, err) + runRt(t, "upload", "--spec="+specFile, "--build-name="+buildName, "--build-number="+buildNumber) + runRt(t, "build-publish", buildName, buildNumber) +} + +func initLifecycleTest(t *testing.T) { + if !*tests.TestLifecycle { + t.Skip("Skipping lifecycle test. To run release bundle test add the '-test.lc=true' option.") + } + validateArtifactoryVersion(t, rbMinVersion) + + if !isLifecycleSupported(t) { + t.Skip("Skipping lifecycle test because the functionality is not enabled on the provided JPD.") + } +} + +func isLifecycleSupported(t *testing.T) (skip bool) { + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + + resp, _, _, err := client.SendGet(serverDetails.ArtifactoryUrl+"api/release_bundles/records/non-existing-rb", true, artHttpDetails, "") + if !assert.NoError(t, err) { + return + } + return resp.StatusCode != http.StatusNotImplemented +} + +func InitLifecycleTests() { + initArtifactoryCli() + initLifecycleCli() + cleanUpOldBuilds() + cleanUpOldRepositories() + cleanUpOldUsers() + tests.AddTimestampToGlobalVars() + createRequiredRepos() + sendGpgKeyPair() +} + +func initLifecycleCli() { + if lcCli != nil { + return + } + lcCli = tests.NewJfrogCli(execMain, "jfrog", authenticateLifecycle()) +} + +func CleanLifecycleTests() { + deleteCreatedRepos() +} + +func cleanLifecycleTests(t *testing.T) { + deleteFilesFromRepo(t, tests.RtDevRepo) + deleteFilesFromRepo(t, tests.RtProdRepo) + tests.CleanFileSystem() +} + +func sendGpgKeyPair() { + // Create http client + client, err := httpclient.ClientBuilder().Build() + coreutils.ExitOnErr(err) + + // Check if one already exists + resp, body, _, err := client.SendGet(*tests.JfrogUrl+"artifactory/api/security/keypair/"+gpgKeyPairName, true, artHttpDetails, "") + coreutils.ExitOnErr(err) + if resp.StatusCode == http.StatusOK { + return + } + coreutils.ExitOnErr(errorutils.CheckResponseStatusWithBody(resp, body, http.StatusNotFound)) + + // Read gpg public and private keys + keysDir := filepath.Join(tests.GetTestResourcesPath(), lcTestdataPath, "keys") + publicKey, err := os.ReadFile(filepath.Join(keysDir, "public.txt")) + coreutils.ExitOnErr(err) + privateKey, err := os.ReadFile(filepath.Join(keysDir, "private.txt")) + coreutils.ExitOnErr(err) + + // Send keys to Artifactory + payload := KeyPairPayload{ + PairName: gpgKeyPairName, + PairType: "GPG", + Alias: gpgKeyPairName + "-alias", + Passphrase: "password", + PublicKey: string(publicKey), + PrivateKey: string(privateKey), + } + content, err := json.Marshal(payload) + coreutils.ExitOnErr(err) + resp, body, err = client.SendPost(*tests.JfrogUrl+"artifactory/api/security/keypair", content, artHttpDetails, "") + coreutils.ExitOnErr(err) + coreutils.ExitOnErr(errorutils.CheckResponseStatusWithBody(resp, body, http.StatusCreated)) +} + +type KeyPairPayload struct { + PairName string `json:"pairName,omitempty"` + PairType string `json:"pairType,omitempty"` + Alias string `json:"alias,omitempty"` + Passphrase string `json:"passphrase,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + PrivateKey string `json:"privateKey,omitempty"` +} diff --git a/main.go b/main.go index ddb09b4d8..7f8dcd7b8 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,8 @@ package main import ( "fmt" + "github.com/jfrog/jfrog-cli/lifecycle" + "golang.org/x/exp/slices" "os" "runtime" "sort" @@ -20,8 +22,10 @@ import ( "github.com/jfrog/jfrog-cli/distribution" "github.com/jfrog/jfrog-cli/docs/common" "github.com/jfrog/jfrog-cli/docs/general/cisetup" + loginDocs "github.com/jfrog/jfrog-cli/docs/general/login" cisetupcommand "github.com/jfrog/jfrog-cli/general/cisetup" "github.com/jfrog/jfrog-cli/general/envsetup" + "github.com/jfrog/jfrog-cli/general/login" "github.com/jfrog/jfrog-cli/general/project" "github.com/jfrog/jfrog-cli/missioncontrol" "github.com/jfrog/jfrog-cli/pipelines" @@ -231,7 +235,7 @@ func getCommands() []cli.Command { return cisetupcommand.RunCiSetupCmd() }, }, - //{ + // { // Name: "invite", // Usage: invite.GetDescription(), // HelpName: corecommon.CreateUsage("invite", invite.GetDescription(), invite.Usage), @@ -241,24 +245,20 @@ func getCommands() []cli.Command { // Action: func(c *cli.Context) error { // return invitecommand.RunInviteCmd(c) // }, - //}, + // }, { Name: "setup", HideHelp: true, Hidden: true, Flags: cliutils.GetCommandFlags(cliutils.Setup), - Action: func(c *cli.Context) error { - return SetupCmd(c) - }, + Action: SetupCmd, }, { Name: "intro", HideHelp: true, Hidden: true, Flags: cliutils.GetCommandFlags(cliutils.Intro), - Action: func(*cli.Context) error { - return IntroCmd() - }, + Action: IntroCmd, }, { Name: cliutils.CmdOptions, @@ -268,10 +268,20 @@ func getCommands() []cli.Command { fmt.Println(common.GetGlobalEnvVars()) }, }, + { + Name: "login", + Usage: loginDocs.GetDescription(), + HelpName: corecommon.CreateUsage("login", loginDocs.GetDescription(), loginDocs.Usage), + BashComplete: corecommon.CreateBashCompletionFunc(), + Category: otherCategory, + Action: login.LoginCmd, + Hidden: true, // TODO remove when Artifactory 7.63.1 is released to self-hosted + }, } - allCommands := append(cliNameSpaces, utils.GetPlugins()...) + allCommands := append(slices.Clone(cliNameSpaces), utils.GetPlugins()...) allCommands = append(allCommands, scan.GetCommands()...) allCommands = append(allCommands, buildtools.GetCommands()...) + allCommands = append(allCommands, lifecycle.GetCommands()...) return append(allCommands, buildtools.GetBuildToolsHelpCommands()...) } @@ -309,7 +319,7 @@ func SetupCmd(c *cli.Context) error { return envsetup.RunEnvSetupCmd(c, format) } -func IntroCmd() error { +func IntroCmd(_ *cli.Context) error { ci, err := clientutils.GetBoolEnvValue(coreutils.CI, false) if ci || err != nil { return err diff --git a/main_test.go b/main_test.go index 53c207ba1..bc6684073 100644 --- a/main_test.go +++ b/main_test.go @@ -4,34 +4,30 @@ import ( "errors" "flag" "fmt" - "os" - "path/filepath" - "strconv" - "strings" - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/common/spec" - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils" - "github.com/urfave/cli" - buildinfo "github.com/jfrog/build-info-go/entities" - clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" - + commandUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" + artifactoryUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/common/commands" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/log" - clientlog "github.com/jfrog/jfrog-client-go/utils/log" - - commandUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" - artifactoryUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" + xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "github.com/jfrog/jfrog-cli/artifactory" "github.com/jfrog/jfrog-cli/inttestutils" "github.com/jfrog/jfrog-cli/utils/tests" "github.com/jfrog/jfrog-client-go/utils" + clientlog "github.com/jfrog/jfrog-client-go/utils/log" + clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" + "github.com/urfave/cli" "gopkg.in/yaml.v2" + "os" + "path/filepath" + "strconv" + "strings" + "testing" ) func TestMain(m *testing.M) { @@ -80,6 +76,9 @@ func setupIntegrationTests() { if *tests.TestTransfer { InitTransferTests() } + if *tests.TestLifecycle { + InitLifecycleTests() + } } func tearDownIntegrationTests() { @@ -98,6 +97,9 @@ func tearDownIntegrationTests() { if *tests.TestTransfer { CleanTransferTests() } + if *tests.TestLifecycle { + CleanLifecycleTests() + } } func InitBuildToolsTests() { @@ -180,7 +182,8 @@ func initArtifactoryCli() { } *tests.JfrogUrl = utils.AddTrailingSlashIfNeeded(*tests.JfrogUrl) artifactoryCli = tests.NewJfrogCli(execMain, "jfrog rt", authenticate(false)) - if (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestPlugins || *tests.TestArtifactoryProject || *tests.TestAccess || *tests.TestTransfer { + if (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestPlugins || *tests.TestArtifactoryProject || + *tests.TestAccess || *tests.TestTransfer || *tests.TestLifecycle { configCli = createConfigJfrogCLI(authenticate(true)) platformCli = tests.NewJfrogCli(execMain, "jfrog", authenticate(false)) } @@ -330,3 +333,20 @@ func initDeploymentViewTest(t *testing.T) (assertDeploymentViewFunc func(), clea } return } + +func deleteFilesFromRepo(t *testing.T, repoName string) { + deleteSpec := spec.NewBuilder().Pattern(repoName).BuildSpec() + _, _, err := tests.DeleteFiles(deleteSpec, serverDetails) + assert.NoError(t, err) +} + +func TestIntro(t *testing.T) { + buffer, _, previousLog := coreTests.RedirectLogOutputToBuffer() + defer clientlog.SetLogger(previousLog) + + setEnvCallBack := clientTestUtils.SetEnvWithCallbackAndAssert(t, "CI", "false") + defer setEnvCallBack() + + runJfrogCli(t, "intro") + assert.Contains(t, buffer.String(), "Thank you for installing version") +} diff --git a/maven_test.go b/maven_test.go index a41cfc498..e7de3a582 100644 --- a/maven_test.go +++ b/maven_test.go @@ -2,29 +2,25 @@ package main import ( "fmt" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/jfrog/jfrog-cli/inttestutils" - "github.com/jfrog/jfrog-cli/utils/tests/proxy/server/certificate" - "github.com/jfrog/jfrog-client-go/utils/log" - clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" - buildinfo "github.com/jfrog/build-info-go/entities" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/mvn" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/common/commands" "github.com/jfrog/jfrog-cli-core/v2/common/spec" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" + "github.com/jfrog/jfrog-cli/inttestutils" "github.com/jfrog/jfrog-cli/utils/tests" cliproxy "github.com/jfrog/jfrog-cli/utils/tests/proxy/server" + "github.com/jfrog/jfrog-cli/utils/tests/proxy/server/certificate" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" + clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" + "os" + "path/filepath" + "strings" + "testing" ) const mavenTestsProxyPort = "1028" @@ -34,12 +30,8 @@ var localRepoDir string func cleanMavenTest(t *testing.T) { clientTestUtils.UnSetEnvAndAssert(t, coreutils.HomeDir) - deleteSpec := spec.NewBuilder().Pattern(tests.MvnRepo1).BuildSpec() - _, _, err := tests.DeleteFiles(deleteSpec, serverDetails) - assert.NoError(t, err) - deleteSpec = spec.NewBuilder().Pattern(tests.MvnRepo2).BuildSpec() - _, _, err = tests.DeleteFiles(deleteSpec, serverDetails) - assert.NoError(t, err) + deleteFilesFromRepo(t, tests.MvnRepo1) + deleteFilesFromRepo(t, tests.MvnRepo2) tests.CleanFileSystem() } diff --git a/missioncontrol/cli.go b/missioncontrol/cli.go index ed7c22458..4e7a6341a 100644 --- a/missioncontrol/cli.go +++ b/missioncontrol/cli.go @@ -31,9 +31,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), Aliases: []string{"la"}, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return licenseAcquire(c) - }, + Action: licenseAcquire, }, { Name: "license-deploy", @@ -44,9 +42,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), Aliases: []string{"ld"}, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return licenseDeploy(c) - }, + Action: licenseDeploy, }, { Name: "license-release", @@ -57,9 +53,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), Aliases: []string{"lr"}, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return licenseRelease(c) - }, + Action: licenseRelease, }, { Name: "jpd-add", @@ -70,9 +64,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), Aliases: []string{"ja"}, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return jpdAdd(c) - }, + Action: jpdAdd, }, { Name: "jpd-delete", @@ -83,9 +75,7 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), Aliases: []string{"jd"}, BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return jpdDelete(c) - }, + Action: jpdDelete, }, }) } diff --git a/nuget_test.go b/nuget_test.go index 446ee82a0..b77f106b5 100644 --- a/nuget_test.go +++ b/nuget_test.go @@ -15,6 +15,7 @@ import ( clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" "os" "path/filepath" "strconv" @@ -62,7 +63,7 @@ func TestDotnetResolve(t *testing.T) { func testNativeNugetDotnetResolve(t *testing.T, uniqueTests []testDescriptor, buildName string, projectType utils.ProjectType) { initNugetTest(t) - testDescriptors := append(uniqueTests, []testDescriptor{ + testDescriptors := append(slices.Clone(uniqueTests), []testDescriptor{ {"referencewithoutmodulechnage", "reference", []string{projectType.String(), "restore"}, []string{"reference"}, []int{6}}, {"referencewithmodulechnage", "reference", []string{projectType.String(), "restore", "--module=" + ModuleNameJFrogTest}, []string{ModuleNameJFrogTest}, []int{6}}, {"multireferencewithoutmodulechnage", "multireference", []string{projectType.String(), "restore"}, []string{"proj1", "proj2"}, []int{5, 3}}, diff --git a/pipelines/cli.go b/pipelines/cli.go index d01011e1c..b9c539250 100644 --- a/pipelines/cli.go +++ b/pipelines/cli.go @@ -29,9 +29,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("pl status", status.GetDescription(), status.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return fetchLatestPipelineRunStatus(c) - }, + Action: fetchLatestPipelineRunStatus, }, { Name: "trigger", @@ -42,9 +40,7 @@ func GetCommands() []cli.Command { UsageText: trigger.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return triggerNewRun(c) - }, + Action: triggerNewRun, }, { Name: "version", @@ -53,9 +49,7 @@ func GetCommands() []cli.Command { Usage: version.GetDescription(), HelpName: corecommon.CreateUsage("pl version", version.GetDescription(), version.Usage), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return getVersion(c) - }, + Action: getVersion, }, { Name: "sync", @@ -66,9 +60,7 @@ func GetCommands() []cli.Command { UsageText: sync.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return syncPipelineResources(c) - }, + Action: syncPipelineResources, }, { Name: "sync-status", @@ -78,9 +70,7 @@ func GetCommands() []cli.Command { HelpName: corecommon.CreateUsage("pl sync-status", syncstatus.GetDescription(), syncstatus.Usage), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return getSyncPipelineResourcesStatus(c) - }, + Action: getSyncPipelineResourcesStatus, }, }) } diff --git a/plugins/cli.go b/plugins/cli.go index 040027990..ae1842e4e 100644 --- a/plugins/cli.go +++ b/plugins/cli.go @@ -21,9 +21,7 @@ func GetCommands() []cli.Command { UsageText: installdocs.GetArguments(), ArgsUsage: common.CreateEnvVars(installdocs.EnvVar...), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return commands.InstallCmd(c) - }, + Action: commands.InstallCmd, }, { Name: "uninstall", @@ -33,9 +31,7 @@ func GetCommands() []cli.Command { UsageText: uninstalldocs.GetArguments(), ArgsUsage: common.CreateEnvVars(), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return commands.UninstallCmd(c) - }, + Action: commands.UninstallCmd, }, { Name: "publish", @@ -45,9 +41,7 @@ func GetCommands() []cli.Command { UsageText: publishdocs.GetArguments(), ArgsUsage: common.CreateEnvVars(publishdocs.EnvVar...), BashComplete: corecommon.CreateBashCompletionFunc(), - Action: func(c *cli.Context) error { - return commands.PublishCmd(c) - }, + Action: commands.PublishCmd, }, }) } diff --git a/plugins_test.go b/plugins_test.go index c1cd56828..83e51eb77 100644 --- a/plugins_test.go +++ b/plugins_test.go @@ -49,13 +49,13 @@ func TestPluginInstallUninstallOfficialRegistry(t *testing.T) { jfrogCli := tests.NewJfrogCli(execMain, "jfrog", "") // Try installing a plugin with specific version. - err = installAndAssertPlugin(t, jfrogCli, officialPluginForTest, officialPluginVersion) + err = installAndAssertPlugin(t, jfrogCli, officialPluginVersion) if err != nil { return } // Try installing the latest version of the plugin. Also verifies replacement was successful. - err = installAndAssertPlugin(t, jfrogCli, officialPluginForTest, "") + err = installAndAssertPlugin(t, jfrogCli, "") if err != nil { return } @@ -99,21 +99,21 @@ func TestPluginInstallWithProgressBar(t *testing.T) { jfrogCli := tests.NewJfrogCli(execMain, "jfrog", "") // Try installing a plugin with specific version. - err = installAndAssertPlugin(t, jfrogCli, officialPluginForTest, officialPluginVersion) + err = installAndAssertPlugin(t, jfrogCli, officialPluginVersion) if err != nil { return } // Try installing the latest version of the plugin. Also verifies replacement was successful. - err = installAndAssertPlugin(t, jfrogCli, officialPluginForTest, "") + err = installAndAssertPlugin(t, jfrogCli, "") if err != nil { return } } -func installAndAssertPlugin(t *testing.T, jfrogCli *tests.JfrogCli, pluginName, pluginVersion string) error { +func installAndAssertPlugin(t *testing.T, jfrogCli *tests.JfrogCli, pluginVersion string) error { // If version required, concat to plugin name - identifier := pluginName + identifier := officialPluginForTest if pluginVersion != "" { identifier += "@" + pluginVersion } @@ -124,7 +124,7 @@ func installAndAssertPlugin(t *testing.T, jfrogCli *tests.JfrogCli, pluginName, assert.NoError(t, err) return err } - err = verifyPluginInPluginsDir(t, pluginName, true, false) + err = verifyPluginInPluginsDir(t, officialPluginForTest, true, false) if err != nil { return err } diff --git a/scan/cli.go b/scan/cli.go index 115e619d0..a99b94e1d 100644 --- a/scan/cli.go +++ b/scan/cli.go @@ -48,7 +48,6 @@ func GetCommands() []cli.Command { ArgsUsage: common.CreateEnvVars(), BashComplete: corecommondocs.CreateBashCompletionFunc(), Action: CurationCmd, - Hidden: true, }, { Name: "audit", @@ -182,12 +181,11 @@ func AuditCmd(c *cli.Context) error { allTechnologies := coreutils.GetAllTechnologiesList() technologies := []string{} for _, tech := range allTechnologies { - techExists := false - switch tech { - case coreutils.Maven: + var techExists bool + if tech == coreutils.Maven { // On Maven we use '--mvn' flag techExists = c.Bool("mvn") - default: + } else { techExists = c.Bool(tech.ToString()) } if techExists { @@ -215,7 +213,7 @@ func CurationCmd(c *cli.Context) error { return err } curationAuditCommand := curation.NewCurationAuditCommand(). - SetWorkingDirs(splitAndTrim(c.String("working-dirs"), ",")). + SetWorkingDirs(splitByCommaAndTrim(c.String("working-dirs"))). SetParallelRequests(threads) serverDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, true, "rt") @@ -264,11 +262,11 @@ func createGenericAuditCmd(c *cli.Context) (*audit.GenericAuditCommand, error) { SetFixableOnly(c.Bool(cliutils.FixableOnly)) if c.String("watches") != "" { - auditCmd.SetWatches(splitAndTrim(c.String("watches"), ",")) + auditCmd.SetWatches(splitByCommaAndTrim(c.String("watches"))) } if c.String("working-dirs") != "" { - auditCmd.SetWorkingDirs(splitAndTrim(c.String("working-dirs"), ",")) + auditCmd.SetWorkingDirs(splitByCommaAndTrim(c.String("working-dirs"))) } auditCmd.SetServerDetails(serverDetails). SetExcludeTestDependencies(c.Bool(cliutils.ExcludeTestDeps)). @@ -295,11 +293,11 @@ func ScanCmd(c *cli.Context) error { var specFile *spec.SpecFiles if c.IsSet("spec") { specFile, err = cliutils.GetFileSystemSpec(c) + if err != nil { + return err + } } else { - specFile, err = createDefaultScanSpec(c, addTrailingSlashToRepoPathIfNeeded(c)) - } - if err != nil { - return err + specFile = createDefaultScanSpec(c, addTrailingSlashToRepoPathIfNeeded(c)) } err = spec.ValidateSpec(specFile.Files, false, false) if err != nil { @@ -332,7 +330,7 @@ func ScanCmd(c *cli.Context) error { SetFixableOnly(c.Bool(cliutils.FixableOnly)). SetMinSeverityFilter(minSeverity) if c.String("watches") != "" { - scanCmd.SetWatches(splitAndTrim(c.String("watches"), ",")) + scanCmd.SetWatches(splitByCommaAndTrim(c.String("watches"))) } return commands.Exec(scanCmd) } @@ -410,7 +408,7 @@ func DockerScan(c *cli.Context, image string) error { SetFixableOnly(c.Bool(cliutils.FixableOnly)). SetMinSeverityFilter(minSeverity) if c.String("watches") != "" { - containerScanCommand.SetWatches(splitAndTrim(c.String("watches"), ",")) + containerScanCommand.SetWatches(splitByCommaAndTrim(c.String("watches"))) } return progressbar.ExecWithProgress(containerScanCommand) } @@ -424,7 +422,7 @@ func addTrailingSlashToRepoPathIfNeeded(c *cli.Context) string { return repoPath } -func createDefaultScanSpec(c *cli.Context, defaultTarget string) (*spec.SpecFiles, error) { +func createDefaultScanSpec(c *cli.Context, defaultTarget string) *spec.SpecFiles { return spec.NewBuilder(). Pattern(c.Args().Get(0)). Target(defaultTarget). @@ -433,7 +431,7 @@ func createDefaultScanSpec(c *cli.Context, defaultTarget string) (*spec.SpecFile Regexp(c.Bool("regexp")). Ant(c.Bool("ant")). IncludeDirs(c.Bool("include-dirs")). - BuildSpec(), nil + BuildSpec() } func createServerDetailsWithConfigOffer(c *cli.Context) (*coreconfig.ServerDetails, error) { @@ -466,8 +464,8 @@ func isProjectProvided(c *cli.Context) bool { return c.String("project") != "" || os.Getenv(coreutils.Project) != "" } -func splitAndTrim(paramValue, separator string) (res []string) { - args := strings.Split(paramValue, separator) +func splitByCommaAndTrim(paramValue string) (res []string) { + args := strings.Split(paramValue, ",") res = make([]string, len(args)) for i, arg := range args { res[i] = strings.TrimSpace(arg) diff --git a/testdata/dev_repo_repository_config.json b/testdata/dev_repo_repository_config.json new file mode 100644 index 000000000..de2297cfd --- /dev/null +++ b/testdata/dev_repo_repository_config.json @@ -0,0 +1,6 @@ +{ + "key": "${DEV_REPO}", + "rclass": "local", + "packageType": "generic", + "environments":["DEV"] +} diff --git a/testdata/filespecs/go_publish_repo_excludes.json b/testdata/filespecs/go_publish_repo_excludes.json new file mode 100644 index 000000000..979476285 --- /dev/null +++ b/testdata/filespecs/go_publish_repo_excludes.json @@ -0,0 +1,7 @@ +{ + "files": [ + { + "pattern": "${GO_REPO}/*" + } + ] +} \ No newline at end of file diff --git a/testdata/filespecs/search_all_prod_repo.json b/testdata/filespecs/search_all_prod_repo.json new file mode 100644 index 000000000..2930acf50 --- /dev/null +++ b/testdata/filespecs/search_all_prod_repo.json @@ -0,0 +1,7 @@ +{ + "files": [ + { + "pattern": "${PROD_REPO}/*" + } + ] +} \ No newline at end of file diff --git a/testdata/filespecs/upload_dev_spec_a.json b/testdata/filespecs/upload_dev_spec_a.json new file mode 100644 index 000000000..d816a4499 --- /dev/null +++ b/testdata/filespecs/upload_dev_spec_a.json @@ -0,0 +1,10 @@ +{ + "files": [ + { + "pattern": "testdata/a/*", + "target": "${DEV_REPO}/", + "flat": "true", + "recursive": "false" + } + ] +} \ No newline at end of file diff --git a/testdata/filespecs/upload_dev_spec_b.json b/testdata/filespecs/upload_dev_spec_b.json new file mode 100644 index 000000000..e5419e101 --- /dev/null +++ b/testdata/filespecs/upload_dev_spec_b.json @@ -0,0 +1,10 @@ +{ + "files": [ + { + "pattern": "testdata/a/b/*", + "target": "${DEV_REPO}/", + "flat": "true", + "recursive": "false" + } + ] +} \ No newline at end of file diff --git a/testdata/filespecs/upload_dev_spec_c.json b/testdata/filespecs/upload_dev_spec_c.json new file mode 100644 index 000000000..db8e8177f --- /dev/null +++ b/testdata/filespecs/upload_dev_spec_c.json @@ -0,0 +1,10 @@ +{ + "files": [ + { + "pattern": "testdata/a/b/c/*", + "target": "${DEV_REPO}/", + "flat": "true", + "recursive": "false" + } + ] +} \ No newline at end of file diff --git a/testdata/go/project3/.jfrog/projects/go.yaml b/testdata/go/project3/.jfrog/projects/go.yaml new file mode 100644 index 000000000..95ed0eca1 --- /dev/null +++ b/testdata/go/project3/.jfrog/projects/go.yaml @@ -0,0 +1,9 @@ +version: 1 +type: go + +resolver: + repo: ${GO_VIRTUAL_REPO} + serverID: default +deployer: + repo: ${GO_REPO} + serverID: default diff --git a/testdata/go/project3/createGoProject_go.mod_suffix b/testdata/go/project3/createGoProject_go.mod_suffix new file mode 100644 index 000000000..744893775 --- /dev/null +++ b/testdata/go/project3/createGoProject_go.mod_suffix @@ -0,0 +1,8 @@ +module github.com/jfrog/dependency + +require ( + github.com/pkg/errors v0.8.0 + rsc.io/quote v1.5.2 +) + +go 1.13 diff --git a/testdata/go/project3/dependency.go b/testdata/go/project3/dependency.go new file mode 100644 index 000000000..fb1446f05 --- /dev/null +++ b/testdata/go/project3/dependency.go @@ -0,0 +1,11 @@ +package dependency + +import ( + "fmt" + "github.com/pkg/errors" +) + +func PrintHello() error { + fmt.Println("Hello") + return errors.New("abc") +} diff --git a/testdata/go/project3/go.sum b/testdata/go/project3/go.sum new file mode 100644 index 000000000..6dd596a45 --- /dev/null +++ b/testdata/go/project3/go.sum @@ -0,0 +1,7 @@ +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/testdata/go/project4/.jfrog/projects/go.yaml b/testdata/go/project4/.jfrog/projects/go.yaml new file mode 100644 index 000000000..95ed0eca1 --- /dev/null +++ b/testdata/go/project4/.jfrog/projects/go.yaml @@ -0,0 +1,9 @@ +version: 1 +type: go + +resolver: + repo: ${GO_VIRTUAL_REPO} + serverID: default +deployer: + repo: ${GO_REPO} + serverID: default diff --git a/testdata/go/project4/createGoProject_go.mod_suffix b/testdata/go/project4/createGoProject_go.mod_suffix new file mode 100644 index 000000000..744893775 --- /dev/null +++ b/testdata/go/project4/createGoProject_go.mod_suffix @@ -0,0 +1,8 @@ +module github.com/jfrog/dependency + +require ( + github.com/pkg/errors v0.8.0 + rsc.io/quote v1.5.2 +) + +go 1.13 diff --git a/testdata/go/project4/dependency.go b/testdata/go/project4/dependency.go new file mode 100644 index 000000000..1ae8343f3 --- /dev/null +++ b/testdata/go/project4/dependency.go @@ -0,0 +1,11 @@ +package dependency + +import ( + "fmt" + "github.com/pkg/errors" +) + +func PrintHello() error { + fmt.Println("Hello World") + return errors.New("abc") +} diff --git a/testdata/go/project4/dir1/a.txt b/testdata/go/project4/dir1/a.txt new file mode 100644 index 000000000..8d14cbf98 --- /dev/null +++ b/testdata/go/project4/dir1/a.txt @@ -0,0 +1 @@ +a.txt \ No newline at end of file diff --git a/testdata/go/project4/dir1/dir2/b.txt b/testdata/go/project4/dir1/dir2/b.txt new file mode 100644 index 000000000..19acdd81a --- /dev/null +++ b/testdata/go/project4/dir1/dir2/b.txt @@ -0,0 +1 @@ +b.txt \ No newline at end of file diff --git a/testdata/go/project4/dir1/dir2/dir3/c.txt b/testdata/go/project4/dir1/dir2/dir3/c.txt new file mode 100644 index 000000000..f632129c1 --- /dev/null +++ b/testdata/go/project4/dir1/dir2/dir3/c.txt @@ -0,0 +1 @@ +c.txt \ No newline at end of file diff --git a/testdata/go/project4/dir4/d.txt b/testdata/go/project4/dir4/d.txt new file mode 100644 index 000000000..a751d6246 --- /dev/null +++ b/testdata/go/project4/dir4/d.txt @@ -0,0 +1 @@ +d.txt \ No newline at end of file diff --git a/testdata/go/project4/go.sum b/testdata/go/project4/go.sum new file mode 100644 index 000000000..6dd596a45 --- /dev/null +++ b/testdata/go/project4/go.sum @@ -0,0 +1,7 @@ +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/testdata/lifecycle/builds-spec-1-2.json b/testdata/lifecycle/builds-spec-1-2.json new file mode 100644 index 000000000..1d31239ca --- /dev/null +++ b/testdata/lifecycle/builds-spec-1-2.json @@ -0,0 +1,13 @@ +{ + "builds": [ + { + "name": "${LC_BUILD_NAME1}", + "number": "111" + }, + { + "name": "${LC_BUILD_NAME2}", + "number": "", + "project": "default" + } + ] +} diff --git a/testdata/lifecycle/builds-spec-3.json b/testdata/lifecycle/builds-spec-3.json new file mode 100644 index 000000000..b188d7eb6 --- /dev/null +++ b/testdata/lifecycle/builds-spec-3.json @@ -0,0 +1,8 @@ +{ + "builds": [ + { + "name": "${LC_BUILD_NAME3}", + "number": "" + } + ] +} diff --git a/testdata/lifecycle/keys/private.txt b/testdata/lifecycle/keys/private.txt new file mode 100644 index 000000000..302ccf64a --- /dev/null +++ b/testdata/lifecycle/keys/private.txt @@ -0,0 +1,83 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lQWGBGQPDFYBDADUnc25T16fzFZDO6SZ6iM/+rRu+lAsxNl0EmbqIf98gGU+ewA8 +C8HoI3pGQhe1y+miH98xGjZel+7j2XWgweEI9I8XpXSVeeYxMAdtcwl6Xl9MaG1g +HqVEG+7rg641R0bks3k/JDTDz+xx5ybbHBFZEUdOe9hxBXtlUaNF6Zfy2o0FoQiQ +3+gAhOYR/L2oB41V83UTwdykf0gwHzbtuj9MygE88vQV4ZCdDI4o7oIiC7+FEicF +BenND/AMjb0inab0DpTmy8UYkZWlPG7ZwCanO5A/+OSsb1w9Izf0dYbf8C1fiQm4 +GXF6PHRrkknujySmJBuXsQ5ZGIHJJTzuQWWTYZLUBCk0g8m3iAUldM5ULA6SSGr6 +vv8mjHo8drcb9iTnYkSLikd4t5NTrPPHdpFTkggPxwGiK0x7eWaPVP6MN2ZTvS8x +4wHOmQKW5yGSqwNCNxOrImfu16FTm4y8flknl1NsBhhs9ipRqSUOFc8Z99Z6J+sP +EdlL4lAYc9/mjJ0AEQEAAf4HAwI8KO3m7L/fCvaV2oWVS0ZhcwXcyvcYJZDfPfpN +6YhNS7ADY7ox6adh3911MSn5UoJUOE/vDTavqcOgoKWfxZD1emrpJorCYi87Jgva +EGKHtzPqMKsnd3v+AN9OG7u3I5qZ+xb1H4tUoAN6gImdxCQ/F82QihZ2DznAQEKV +f4y+4j5wF/YI+hk/k3ri4f3Rf2pNl8M4ScMAm+2HtexGVee10FczkysFRu3P0BAA +mok7fFFVOM7r4ZNZOqJsJRheXyQ6mIQ0OD/4KKrgeQUotCaABRrzolCFcbVeoGQf +qrBxg62PgQs+71gvedDNFUtMXTHXh6c8p/RSItP3bkID/pl6rBCfNFjt30m59dkv +e7B7QTwgb9i6qATnkJ0o3C0UDDn+kqs/HntgydAaFaJ09x88ZkVyVPNT8ygyv2wC +gN8ol+CYKCoP3vdF4xREQVJ5Xar/WSHMgQ5O9k/4KUnvI0qevLhrjSDq8pcjXS+K +kAm6+Uph4PBA5ntBp8BZKPxldfEXB0eM1jlmencBIBSchrp5ExVPhOm2YzKh1Y5t +8W1AMFux8MGf2RLj5i3JqkBtK2FS287mcv4NdvWrmoPJB9pZz3YhRNKpGy3xRpBV +xZID1IDb1nURAcsJcMze8DzPxBqN0qSR9TNYjgM4iGC3QbgVq4XX93yZ8Z4RDtYm +F3PApFOs6fOhOp/FlFxCk3ltmW9elotvEJSRshVyAx/JH5rHY3rLH1Ux7tc+nrbN +gkWruCU+HRQPUlaEvKyFXTeUUhVZdKaaQXgw9obVSjmOA29S1E86n2hnG1cnjUTc +M+7PizkLFNQ1gBWUmOo9P5XqrQubuRquggXP/aHUhSranDUP3yJ27hYzgsjpnrll +dnmklSgalAbVUTGRvUR67QMhAnpcuHl/NtwDfcYdzGEnQFxA5rK6lTjG+V6iTwtj +NtVtsah9fiTzXFB3P41AR2jeTx8mOEKkmrZ6KaMMZqonM3PihHGxJH8dCXCywCfi +BAWzqX+VSXF/nyErEGm/VE2xcFJF17XfA0dwY9gavcdneQ1KNj5kdEBWcU/gNx89 +lJQcawpSlcVw0JqviMOy5bZtWU/5mGsvGT8NLjdfL2tgSYBiRLY+GixpcDdeypki +6jucQZdaplkwDw+UsxOjNCqc1NUpXc74wt+pp1/KK3gXjCvmDOf5+4QebBfn0k8F +nLf2ZMWm3cElKYJiS/3bxeqTLv+A5t8P9JcmkqyvxaGp0FhjhUXQ4gALKs+AaqhW +ZIuqTGDkSx7Tvw49LeOwnBAF5iIoEK27LI235ZUch7ytAlls2AZK7Z9gfaoxEeAu +WgR52r6xyGXK+NYvMJtSN44PgGuUJUr/5bQddGVzdGluZyA8dGVzdGluZ0BleGFt +cGxlLmNvbT6JAdEEEwEIADsWIQSw1GEUStezDnGCJEzc19N9K1INZAUCZA8MVgIb +AwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDc19N9K1INZJMFC/9bCJxg +cCSwnPC1I1z0hCqudsQwGjVRAATyt2j0n+tAgtXrHjdpDmtVdmUQo2EHYtYcd3BP +tISHCZo/Qdut+LDRgsXUelWLMIH7Gehx+YfkQ4gb6MxTe88ERdtsVJ7mWIN9NPD6 +6FPZTJNK1d53EohCeCPllPytIFdCbmYAM4rB/dap8Oew0AXIEWOdUR3LX2AR5mUw +Hlmeu+BbLber1BGR03hNCoNJEXSGASC9mi7tukFJ9tG/MbYVRfgk7nNhIchqWcJd +y2qnoJXOQHTyn5hP2TjzDxkDjPvXRyfVKVph4fSA75i3ese4VOmCkck/SXtdsV2w +YTT3zTDwmbj0/mQ/oI5ESuL1rNlxXQ3+YsrNnRwpDmoDoFUcTQ0JrtzccYpgytEy +JNRuqF6coB3qkFaxPJ16/pnHkH9ec7uCQksJUmLeKPPTcNR89AbKJccf3+SAehUR +s5KhRoWVpRQoQNh1Mavkz4rwO0GE16JoQYu57FxymY6gi0NR1jDrC3H0E1qdBYYE +ZA8MVgEMALQSozRifb5LPazupVY98vgaLFFZfsC3gfikjxpDy1U+KMtttCKrEZ23 +h6M42/GYkH2uDOr9LUVaoKx74GWyqovaCSR7w3Z6urRjBkjej4Yn4c4aKYiMjCNB +bjFW9Ch2WdEzsO+gKIUHe8uP2g9fW6MLa10gCSIywcgZ/7g/k97f5d/5C7mEffAD +hz0HrpNdsExY/Ok4lHVOoTOfPy4Lu5FymhxzKz8b/WACIKw3/oJhH1F4zS5v3KDD +gl7z8SqTYgEfg0Rq7bP1WbwWQPGX+yPLoJmaNjAPvBYneaeTCcx4z7VnSsQxhKpU +yTfQTF5kNPS14+0SEa3/pazSG34NXiRCrZN9o/ZmoxnbLhYIZY+4R2Vy9YEV1TyJ +OSxporj6asNkNRFgEwjF8o9k8Yp8Vmy3cu+Y3tf5EOb121US1rMEo0RVZEXPBhzW +w4CfNlskYeO2YoFe/WXMBIdh33ELjo+WVK5wjv9DfLuj/UsKH7seIAxE58FqHtFc +91ggX4OytQARAQAB/gcDAmb6yrDInC2w9meQKtQtEH87Dd4xvnPVpHm8EpyDJuOZ +8L2GESYVD8Mu+QE1917JPo4tQdYZHkZrlFF1rR+SvUiJGNzHz3ooQtTxF75NE4Xz +akaRxti0H8iWP2o6SmcaZLysCNbcbkMNS+vmaiR/4E7UMVB5nwF+jqvjdF63xfRR +cWwlALIB9rhMfAkFHNWErtYjroOerb3WnVt0MIBw+P1OL8kVa7T6gaGQZkiEMydX +vqv5D9mMfN9gQo15/XOw9ipYmRu8UCP4pr36bjhZD7htjQtFRih3aNVeqmu6huht +buViTUpq1DqRHzC4tlR4etyBx1MustpCVghwL+8M1BuiC33q2jOGMf7jFjcIx69S +9NIeU/S4sMREgqiI61OWj6fqGC82BgRfbb0lGmGJ4NA7QLAozABNy5y931LFgcOp +5GsnVBln11xwG6StSCDId3tdALXzflZwV0i7HmTbWfnBwvfjQVcs0kmSCYFPVuit +sF9ji4VfmKVw2paZvmvg80iUM0Dy6BtM8JNX3UIyQzYwErCV4PTdBXTRszB1OGda +cUI44f3D7T+tx8Eq51derKyL4WZEzuz44nqJkbSnGBC+qIyK71rAKmGBszpm1J6j +/WdlNuDMwsXt+UFa78oBlVTCS7GoQWfVXABNfsHTvTGtTAKi0tPBNo6zZiLQnvqg +DXc1ubwhsdpjogYn3VVRSWw7AitlKu71wrQMYSEA++15QMgRBRLlzBtbYSTeWRs5 +YW/q4kAc2YhjkTZo1Cq+Qo7Vobq/ubEeft3r++sd25tesfXHZY4UTetahObjDzB3 +EHsn8mpGxNwpJNBNxyk1hDxaRZMMgEPpfM+TeUM4uCRpGWtTW90fRiPtH4HEL8Rr +dZfhK6nTAnKnUHXqkSgKagFg4ZRbhKcuxYuJdf019n5QQwfvdJucLnyj8uMbIl5Z +aUHjyLi/1fHOA9VWN7cZXPvb3gNb2sSACDUI5W26WLu8cS3zQc4MyOb4FEEPt84i +TsbMX86YLXdZg14G2LVN8aER5ILGf23YdZ2Jii2Yf3LFOCo1wpw3LMLdMjGmgU0E +KtUdCDx0aGNP+kWsG5MvkRpbG1DNkP28QqAAhMvTrFH+winD2o7eNvhl3+hDAjjw +eq6/tjocKM3jXrF78DxJYuGzmka60GfhRm108cU5jReSz3WqOvCk7URD8qGzZQx5 +wsSwABdKLX9ezlu+7zjwwGZT3ucgpRqCCsejDkpYfP3q2fdoAxktSALR7bijq6rG +pSrk/H/GdvJpHLa8DI11ahsvUPZ8sDYUZpyZXpJZC5q1ggh7PHCYrXtnRAUFqNF9 +zyjLRRyhh0xp2OeGY7fMAWXCysBaiQG2BBgBCAAgFiEEsNRhFErXsw5xgiRM3NfT +fStSDWQFAmQPDFYCGwwACgkQ3NfTfStSDWSIFgv/R0csiwt8buVyMSqictAkiBkK +YLwILQhyIdYs9ntjFhxhmqgJRlMGLj9fJIfFtqY4lSHvOpOVzreHXf7ijt/jGMOc +obdosFwrHjV9jR4R0pg074tR06JWPUyj9d57SBSPm8IEUWbX9PR6vlepkjAksneB +ILx3X39IbqAWDSDGvoT7tmNYHTZE8TrplsgD2WbuiR5BKkPwWLfPvS+wrfTzd6Ft +23VYK9N6eBtw2EwZwFIbawVGrt2A0I1p0gU9DvUF5kK+7yn25tlRpFAmA+sMJ1Sh +WBlFzLN1IB94AwYAzMDQw8aB6bTIu5U9E7RkXAwYvtF6KqDy5EPTeKzENeEa0FgL +xUCEWdU8nRw7dBNWET6xFzsXLN6/Yk8B1xQ/YiiHTdn/i6S7kmOGt3Ws1C30phhg +3+irG4LMU4anjbP1N/K1zbBFpUR02PVC/eMMOJjqABSiX7Srz/OCgRygRMU9Yh2B +pJv3ZiQZBQbxu6WlUsb3C2cWm0maxaPoW55LRqmm +=lBLn +-----END PGP PRIVATE KEY BLOCK----- diff --git a/testdata/lifecycle/keys/public.txt b/testdata/lifecycle/keys/public.txt new file mode 100644 index 000000000..00e214e35 --- /dev/null +++ b/testdata/lifecycle/keys/public.txt @@ -0,0 +1,41 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBGQPDFYBDADUnc25T16fzFZDO6SZ6iM/+rRu+lAsxNl0EmbqIf98gGU+ewA8 +C8HoI3pGQhe1y+miH98xGjZel+7j2XWgweEI9I8XpXSVeeYxMAdtcwl6Xl9MaG1g +HqVEG+7rg641R0bks3k/JDTDz+xx5ybbHBFZEUdOe9hxBXtlUaNF6Zfy2o0FoQiQ +3+gAhOYR/L2oB41V83UTwdykf0gwHzbtuj9MygE88vQV4ZCdDI4o7oIiC7+FEicF +BenND/AMjb0inab0DpTmy8UYkZWlPG7ZwCanO5A/+OSsb1w9Izf0dYbf8C1fiQm4 +GXF6PHRrkknujySmJBuXsQ5ZGIHJJTzuQWWTYZLUBCk0g8m3iAUldM5ULA6SSGr6 +vv8mjHo8drcb9iTnYkSLikd4t5NTrPPHdpFTkggPxwGiK0x7eWaPVP6MN2ZTvS8x +4wHOmQKW5yGSqwNCNxOrImfu16FTm4y8flknl1NsBhhs9ipRqSUOFc8Z99Z6J+sP +EdlL4lAYc9/mjJ0AEQEAAbQddGVzdGluZyA8dGVzdGluZ0BleGFtcGxlLmNvbT6J +AdEEEwEIADsWIQSw1GEUStezDnGCJEzc19N9K1INZAUCZA8MVgIbAwULCQgHAgIi +AgYVCgkICwIEFgIDAQIeBwIXgAAKCRDc19N9K1INZJMFC/9bCJxgcCSwnPC1I1z0 +hCqudsQwGjVRAATyt2j0n+tAgtXrHjdpDmtVdmUQo2EHYtYcd3BPtISHCZo/Qdut ++LDRgsXUelWLMIH7Gehx+YfkQ4gb6MxTe88ERdtsVJ7mWIN9NPD66FPZTJNK1d53 +EohCeCPllPytIFdCbmYAM4rB/dap8Oew0AXIEWOdUR3LX2AR5mUwHlmeu+BbLber +1BGR03hNCoNJEXSGASC9mi7tukFJ9tG/MbYVRfgk7nNhIchqWcJdy2qnoJXOQHTy +n5hP2TjzDxkDjPvXRyfVKVph4fSA75i3ese4VOmCkck/SXtdsV2wYTT3zTDwmbj0 +/mQ/oI5ESuL1rNlxXQ3+YsrNnRwpDmoDoFUcTQ0JrtzccYpgytEyJNRuqF6coB3q +kFaxPJ16/pnHkH9ec7uCQksJUmLeKPPTcNR89AbKJccf3+SAehURs5KhRoWVpRQo +QNh1Mavkz4rwO0GE16JoQYu57FxymY6gi0NR1jDrC3H0E1q5AY0EZA8MVgEMALQS +ozRifb5LPazupVY98vgaLFFZfsC3gfikjxpDy1U+KMtttCKrEZ23h6M42/GYkH2u +DOr9LUVaoKx74GWyqovaCSR7w3Z6urRjBkjej4Yn4c4aKYiMjCNBbjFW9Ch2WdEz +sO+gKIUHe8uP2g9fW6MLa10gCSIywcgZ/7g/k97f5d/5C7mEffADhz0HrpNdsExY +/Ok4lHVOoTOfPy4Lu5FymhxzKz8b/WACIKw3/oJhH1F4zS5v3KDDgl7z8SqTYgEf +g0Rq7bP1WbwWQPGX+yPLoJmaNjAPvBYneaeTCcx4z7VnSsQxhKpUyTfQTF5kNPS1 +4+0SEa3/pazSG34NXiRCrZN9o/ZmoxnbLhYIZY+4R2Vy9YEV1TyJOSxporj6asNk +NRFgEwjF8o9k8Yp8Vmy3cu+Y3tf5EOb121US1rMEo0RVZEXPBhzWw4CfNlskYeO2 +YoFe/WXMBIdh33ELjo+WVK5wjv9DfLuj/UsKH7seIAxE58FqHtFc91ggX4OytQAR +AQABiQG2BBgBCAAgFiEEsNRhFErXsw5xgiRM3NfTfStSDWQFAmQPDFYCGwwACgkQ +3NfTfStSDWSIFgv/R0csiwt8buVyMSqictAkiBkKYLwILQhyIdYs9ntjFhxhmqgJ +RlMGLj9fJIfFtqY4lSHvOpOVzreHXf7ijt/jGMOcobdosFwrHjV9jR4R0pg074tR +06JWPUyj9d57SBSPm8IEUWbX9PR6vlepkjAksneBILx3X39IbqAWDSDGvoT7tmNY +HTZE8TrplsgD2WbuiR5BKkPwWLfPvS+wrfTzd6Ft23VYK9N6eBtw2EwZwFIbawVG +rt2A0I1p0gU9DvUF5kK+7yn25tlRpFAmA+sMJ1ShWBlFzLN1IB94AwYAzMDQw8aB +6bTIu5U9E7RkXAwYvtF6KqDy5EPTeKzENeEa0FgLxUCEWdU8nRw7dBNWET6xFzsX +LN6/Yk8B1xQ/YiiHTdn/i6S7kmOGt3Ws1C30phhg3+irG4LMU4anjbP1N/K1zbBF +pUR02PVC/eMMOJjqABSiX7Srz/OCgRygRMU9Yh2BpJv3ZiQZBQbxu6WlUsb3C2cW +m0maxaPoW55LRqmm +=S8pT +-----END PGP PUBLIC KEY BLOCK----- diff --git a/testdata/lifecycle/release-bundles-spec.json b/testdata/lifecycle/release-bundles-spec.json new file mode 100644 index 000000000..36fac6eea --- /dev/null +++ b/testdata/lifecycle/release-bundles-spec.json @@ -0,0 +1,12 @@ +{ + "releaseBundles": [ + { + "name": "${RB_NAME1}", + "version": "111" + }, + { + "name": "${RB_NAME2}", + "version": "222" + } + ] +} diff --git a/testdata/prod_repo_repository_config.json b/testdata/prod_repo_repository_config.json new file mode 100644 index 000000000..6187c443e --- /dev/null +++ b/testdata/prod_repo_repository_config.json @@ -0,0 +1,6 @@ +{ + "key": "${PROD_REPO}", + "rclass": "local", + "packageType": "generic", + "environments":["PROD"] +} diff --git a/transfer_test.go b/transfer_test.go index f3334ae53..bfae8a364 100644 --- a/transfer_test.go +++ b/transfer_test.go @@ -489,12 +489,12 @@ func updateDockerRepoParams(t *testing.T, targetServicesManager artifactory.Arti params.AllowAnyHostAuth = inverseBooleanPointer(params.AllowAnyHostAuth) params.EnableCookieManagement = inverseBooleanPointer(params.EnableCookieManagement) params.BypassHeadRequests = inverseBooleanPointer(params.BypassHeadRequests) - params.SocketTimeoutMillis = params.SocketTimeoutMillis + 100 - params.RetrievalCachePeriodSecs = params.RetrievalCachePeriodSecs + 100 - params.MetadataRetrievalTimeoutSecs = params.MetadataRetrievalTimeoutSecs + 100 - params.MissedRetrievalCachePeriodSecs = params.MissedRetrievalCachePeriodSecs + 100 - params.UnusedArtifactsCleanupPeriodHours = params.UnusedArtifactsCleanupPeriodHours + 100 - params.AssumedOfflinePeriodSecs = params.AssumedOfflinePeriodSecs + 100 + params.SocketTimeoutMillis += 100 + params.RetrievalCachePeriodSecs += 100 + params.MetadataRetrievalTimeoutSecs += 100 + params.MissedRetrievalCachePeriodSecs += 100 + params.UnusedArtifactsCleanupPeriodHours += 100 + params.AssumedOfflinePeriodSecs += 100 params.Username = "test123" params.ContentSynchronisation.Enabled = inverseBooleanPointer(params.ContentSynchronisation.Enabled) @@ -570,6 +570,6 @@ func updateProjectParams(t *testing.T, projectParams *accessServices.Project, ta projectParams.Description = "123123123123" projectParams.AdminPrivileges.IndexResources = &trueValue projectParams.SoftLimit = &trueValue - projectParams.StorageQuotaBytes = projectParams.StorageQuotaBytes + 1 + projectParams.StorageQuotaBytes += 1 assert.NoError(t, targetAccessManager.UpdateProject(accessServices.ProjectParams{ProjectDetails: *projectParams})) } diff --git a/utils/cliutils/cli_consts.go b/utils/cliutils/cli_consts.go index c8903a5aa..f73b0e643 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.40.0" + CliVersion = "2.44.0" ClientAgent = "jfrog-cli-go" // CLI base commands constants: diff --git a/utils/cliutils/commandsflags.go b/utils/cliutils/commandsflags.go index 68d9a2a7e..5c77f30eb 100644 --- a/utils/cliutils/commandsflags.go +++ b/utils/cliutils/commandsflags.go @@ -88,11 +88,11 @@ const ( passphrase = "passphrase" // Distribution's Command Keys - ReleaseBundleCreate = "release-bundle-create" - ReleaseBundleUpdate = "release-bundle-update" - ReleaseBundleSign = "release-bundle-sign" - ReleaseBundleDistribute = "release-bundle-distribute" - ReleaseBundleDelete = "release-bundle-delete" + ReleaseBundleV1Create = "release-bundle-v1-create" + ReleaseBundleV1Update = "release-bundle-v1-update" + ReleaseBundleV1Sign = "release-bundle-v1-sign" + ReleaseBundleV1Distribute = "release-bundle-v1-distribute" + ReleaseBundleV1Delete = "release-bundle-v1-delete" // MC's Commands Keys McConfig = "mc-config" @@ -130,6 +130,10 @@ const ( // TransferInstall commands keys TransferInstall = "transfer-plugin-install" + // Lifecycle commands keys + ReleaseBundleCreate = "release-bundle-create" + ReleaseBundlePromote = "release-bundle-promote" + // *** Artifactory Commands' flags *** // Base flags url = "url" @@ -266,6 +270,9 @@ const ( propsProps = propertiesPrefix + props propsExcludeProps = propertiesPrefix + excludeProps + // Unique go publish flags + goPublishExclusions = GoPublish + exclusions + // Unique build-publish flags buildPublishPrefix = "bp-" bpDryRun = buildPublishPrefix + dryRun @@ -299,11 +306,11 @@ const ( copyFlag = "copy" failFast = "fail-fast" - async = "async" + Async = "async" // Unique build-discard flags buildDiscardPrefix = "bdi-" - bdiAsync = buildDiscardPrefix + async + bdiAsync = buildDiscardPrefix + Async maxDays = "max-days" maxBuilds = "max-builds" excludeBuilds = "exclude-builds" @@ -405,25 +412,25 @@ const ( // Base flags distUrl = "dist-url" - // Unique release-bundle-* flags - releaseBundlePrefix = "rb-" - rbDryRun = releaseBundlePrefix + dryRun - rbRepo = releaseBundlePrefix + repo - rbPassphrase = releaseBundlePrefix + passphrase - distTarget = releaseBundlePrefix + target - rbDetailedSummary = releaseBundlePrefix + detailedSummary - sign = "sign" - desc = "desc" - releaseNotesPath = "release-notes-path" - releaseNotesSyntax = "release-notes-syntax" - distRules = "dist-rules" - site = "site" - city = "city" - countryCodes = "country-codes" - sync = "sync" - maxWaitMinutes = "max-wait-minutes" - deleteFromDist = "delete-from-dist" - createRepo = "create-repo" + // Unique release-bundle-* v1 flags + releaseBundleV1Prefix = "rbv1-" + rbDryRun = releaseBundleV1Prefix + dryRun + rbRepo = releaseBundleV1Prefix + repo + rbPassphrase = releaseBundleV1Prefix + passphrase + distTarget = releaseBundleV1Prefix + target + rbDetailedSummary = releaseBundleV1Prefix + detailedSummary + sign = "sign" + desc = "desc" + releaseNotesPath = "release-notes-path" + releaseNotesSyntax = "release-notes-syntax" + distRules = "dist-rules" + site = "site" + city = "city" + countryCodes = "country-codes" + sync = "sync" + maxWaitMinutes = "max-wait-minutes" + deleteFromDist = "delete-from-dist" + createRepo = "create-repo" // *** Xray Commands' flags *** // Base flags @@ -532,6 +539,19 @@ const ( installPluginVersion = installPluginPrefix + Version InstallPluginSrcDir = "dir" InstallPluginHomeDir = "home-dir" + + // Unique lifecycle flags + lifecyclePrefix = "lc-" + lcUrl = lifecyclePrefix + url + lcSync = lifecyclePrefix + Sync + lcProject = lifecyclePrefix + project + Builds = "builds" + lcBuilds = lifecyclePrefix + Builds + ReleaseBundles = "release-bundles" + lcReleaseBundles = lifecyclePrefix + ReleaseBundles + SigningKey = "signing-key" + lcSigningKey = lifecyclePrefix + SigningKey + lcOverwrite = lifecyclePrefix + Overwrite ) var flagsMap = map[string]cli.Flag{ @@ -987,7 +1007,7 @@ var flagsMap = map[string]cli.Flag{ Usage: "[Default: false] If set to true, automatically removes build artifacts stored in Artifactory.` `", }, bdiAsync: cli.BoolFlag{ - Name: async, + Name: Async, Usage: "[Default: false] If set to true, build discard will run asynchronously and will not wait for response.` `", }, refs: cli.StringFlag{ @@ -1348,7 +1368,7 @@ var flagsMap = map[string]cli.Flag{ }, xrOutput: cli.StringFlag{ Name: xrOutput, - Usage: "[Default: table] Defines the output format of the command. Acceptable values are: table, json, simple-json and sarif. Note: the json format doesnโ€™t include information about scans that are included as part of the Advanced Security package.` `", + Usage: "[Default: table] Defines the output format of the command. Acceptable values are: table, json, simple-json and sarif. Note: the json format doesn't include information about scans that are included as part of the Advanced Security package.` `", }, BypassArchiveLimits: cli.BoolFlag{ Name: BypassArchiveLimits, @@ -1390,6 +1410,10 @@ var flagsMap = map[string]cli.Flag{ Name: Go, Usage: "[Default: false] Set to true to request audit for a Go project.` `", }, + goPublishExclusions: cli.StringFlag{ + Name: exclusions, + Usage: "[Optional] Semicolon-separated list of exclusions. Exclusions can include the * and the ? wildcards.` `", + }, rescan: cli.BoolFlag{ Name: rescan, Usage: "[Default: false] Set to true when scanning an already successfully scanned build, for example after adding an ignore rule.` `", @@ -1556,6 +1580,34 @@ var flagsMap = map[string]cli.Flag{ Name: PreChecks, Usage: "[Default: false] Set to true to run pre transfer checks.` `", }, + lcUrl: cli.StringFlag{ + Name: url, + Usage: "[Optional] JFrog platform URL.` `", + }, + lcSync: cli.BoolFlag{ + Name: Sync, + Usage: "[Default: false] Set to true to run synchronously.` `", + }, + lcProject: cli.StringFlag{ + Name: project, + Usage: "[Optional] Project key associated with the Release Bundle version.` `", + }, + lcBuilds: cli.StringFlag{ + Name: Builds, + Usage: "[Optional] Path to a JSON file containing information of the source builds from which to create a release bundle.` `", + }, + lcReleaseBundles: cli.StringFlag{ + Name: ReleaseBundles, + Usage: "[Optional] Path to a JSON file containing information of the source release bundles from which to create a release bundle.` `", + }, + lcSigningKey: cli.StringFlag{ + Name: SigningKey, + Usage: "[Mandatory] The GPG/RSA key-pair name given in Artifactory.` `", + }, + lcOverwrite: cli.BoolFlag{ + Name: Overwrite, + Usage: "[Default: false] Set to true to replace artifacts with the same name but a different checksum if such already exist at the promotion targets. By default, the promotion is stopped in a case of such conflict.` `", + }, } var commandFlags = map[string][]string{ @@ -1723,7 +1775,7 @@ var commandFlags = map[string][]string{ global, serverIdResolve, serverIdDeploy, repoResolve, repoDeploy, }, GoPublish: { - url, user, password, accessToken, buildName, buildNumber, module, project, detailedSummary, + url, user, password, accessToken, buildName, buildNumber, module, project, detailedSummary, goPublishExclusions, }, Go: { buildName, buildNumber, module, project, noFallback, @@ -1766,23 +1818,23 @@ var commandFlags = map[string][]string{ Poetry: { buildName, buildNumber, module, project, }, - ReleaseBundleCreate: { + ReleaseBundleV1Create: { distUrl, user, password, accessToken, serverId, specFlag, specVars, targetProps, rbDryRun, sign, desc, exclusions, releaseNotesPath, releaseNotesSyntax, rbPassphrase, rbRepo, InsecureTls, distTarget, rbDetailedSummary, }, - ReleaseBundleUpdate: { + ReleaseBundleV1Update: { distUrl, user, password, accessToken, serverId, specFlag, specVars, targetProps, rbDryRun, sign, desc, exclusions, releaseNotesPath, releaseNotesSyntax, rbPassphrase, rbRepo, InsecureTls, distTarget, rbDetailedSummary, }, - ReleaseBundleSign: { + ReleaseBundleV1Sign: { distUrl, user, password, accessToken, serverId, rbPassphrase, rbRepo, InsecureTls, rbDetailedSummary, }, - ReleaseBundleDistribute: { + ReleaseBundleV1Distribute: { distUrl, user, password, accessToken, serverId, rbDryRun, distRules, site, city, countryCodes, sync, maxWaitMinutes, InsecureTls, createRepo, }, - ReleaseBundleDelete: { + ReleaseBundleV1Delete: { distUrl, user, password, accessToken, serverId, rbDryRun, distRules, site, city, countryCodes, sync, maxWaitMinutes, InsecureTls, deleteFromDist, deleteQuiet, }, @@ -1834,6 +1886,12 @@ var commandFlags = map[string][]string{ TransferInstall: { installPluginVersion, InstallPluginSrcDir, InstallPluginHomeDir, }, + ReleaseBundleCreate: { + lcUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcBuilds, lcReleaseBundles, + }, + ReleaseBundlePromote: { + lcUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcOverwrite, + }, // Xray's commands OfflineUpdate: { licenseId, from, to, Version, target, Stream, Periodic, diff --git a/utils/cliutils/utils.go b/utils/cliutils/utils.go index 41fb661d8..daae7887b 100644 --- a/utils/cliutils/utils.go +++ b/utils/cliutils/utils.go @@ -33,9 +33,10 @@ import ( type CommandDomain string const ( - Rt CommandDomain = "rt" - Ds CommandDomain = "ds" - Xr CommandDomain = "xr" + Rt CommandDomain = "rt" + Ds CommandDomain = "ds" + Xr CommandDomain = "xr" + Platform CommandDomain = "platform" ) // Error modes (how should the application behave when the CheckError function is invoked): @@ -530,6 +531,8 @@ func createServerDetailsFromFlags(c *cli.Context, domain CommandDomain) (details details.XrayUrl = details.Url case Ds: details.DistributionUrl = details.Url + case Platform: + return } details.Url = "" @@ -722,7 +725,8 @@ func SetCliExecutableName(executablePath string) { coreutils.SetCliExecutableName(filepath.Base(executablePath)) } -// Returns build configuration struct using the params provided from the console. +// Returns build configuration struct using the args (build name/number) and options (project) provided by the user. +// Any empty configuration could be later overridden by environment variables if set. func CreateBuildConfiguration(c *cli.Context) *artifactoryUtils.BuildConfiguration { buildConfiguration := new(artifactoryUtils.BuildConfiguration) buildNameArg, buildNumberArg := c.Args().Get(0), c.Args().Get(1) @@ -734,6 +738,15 @@ func CreateBuildConfiguration(c *cli.Context) *artifactoryUtils.BuildConfigurati return buildConfiguration } +// Returns build configuration struct using the options provided by the user. +// Any empty configuration could be later overridden by environment variables if set. +func CreateBuildConfigurationWithModule(c *cli.Context) (buildConfigConfiguration *artifactoryUtils.BuildConfiguration, err error) { + buildConfigConfiguration = new(artifactoryUtils.BuildConfiguration) + err = buildConfigConfiguration.SetBuildName(c.String("build-name")).SetBuildNumber(c.String("build-number")). + SetProject(c.String("project")).SetModule(c.String("module")).ValidateBuildAndModuleParams() + return +} + func CreateArtifactoryDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) { artDetails, err := CreateServerDetailsWithConfigOffer(c, false, Rt) if err != nil { @@ -821,9 +834,6 @@ func shouldCheckLatestCliVersion() (shouldCheck bool, err error) { func getLatestCliVersionFromGithubAPI() (githubVersionInfo githubResponse, err error) { client := &http.Client{Timeout: time.Second * 2} - if errorutils.CheckError(err) != nil { - return - } req, err := http.NewRequest(http.MethodGet, "https://api.github.com/repos/jfrog/jfrog-cli/releases/latest", nil) if errorutils.CheckError(err) != nil { return @@ -856,3 +866,9 @@ func doHttpRequest(client *http.Client, req *http.Request) (resp *http.Response, body, err = io.ReadAll(resp.Body) return resp, body, errorutils.CheckError(err) } + +// Get project key from flag or environment variable +func GetProject(c *cli.Context) string { + projectKey := c.String("project") + return getOrDefaultEnv(projectKey, coreutils.Project) +} diff --git a/utils/progressbar/filesprogressbar.go b/utils/progressbar/filesprogressbar.go index 57997bedc..5046c7058 100644 --- a/utils/progressbar/filesprogressbar.go +++ b/utils/progressbar/filesprogressbar.go @@ -69,7 +69,7 @@ func (p *filesProgressBarManager) NewProgressReader(total int64, label, path str p.barsRWMutex.Lock() defer p.barsRWMutex.Unlock() p.barsWg.Add(1) - newBar := p.container.New(int64(total), + newBar := p.container.New(total, mpb.BarStyle().Lbound("|").Filler("๐ŸŸฉ").Tip("๐ŸŸฉ").Padding("โฌ›").Refiller("").Rbound("|"), mpb.BarRemoveOnComplete(), mpb.AppendDecorators( @@ -89,8 +89,7 @@ func (p *filesProgressBarManager) NewProgressReader(total int64, label, path str // Changes progress indicator state and acts accordingly. func (p *filesProgressBarManager) SetProgressState(id int, state string) { - switch state { - case "Merging": + if state == "Merging" { p.addNewMergingSpinner(id) } } diff --git a/utils/progressbar/readerprogressbar.go b/utils/progressbar/readerprogressbar.go index e44cab22b..0ccef8190 100644 --- a/utils/progressbar/readerprogressbar.go +++ b/utils/progressbar/readerprogressbar.go @@ -27,6 +27,8 @@ func (p *ReaderProgressBar) Abort() { } // GetId Returns the ProgressBar ID +// +//nolint:gocritic func (p *ReaderProgressBar) GetId() (Id int) { return p.Id } diff --git a/utils/progressbar/simpleprogressbar.go b/utils/progressbar/simpleprogressbar.go index 7387265bd..a6695acf3 100644 --- a/utils/progressbar/simpleprogressbar.go +++ b/utils/progressbar/simpleprogressbar.go @@ -9,7 +9,7 @@ type SimpleProgressBar struct { Id int } -// Usesd to update the progress bar progress. +// Used to update the progress bar progress. func (p *SimpleProgressBar) ActionWithProgress(reader io.Reader) (results io.Reader) { p.bar.Increment() return nil @@ -21,6 +21,8 @@ func (p *SimpleProgressBar) Abort() { } // GetId Returns the ProgressBar ID +// +//nolint:gocritic func (p *SimpleProgressBar) GetId() (Id int) { return p.Id } diff --git a/utils/summary/summary.go b/utils/summary/summary.go index c7a7624a1..bb9207d2b 100644 --- a/utils/summary/summary.go +++ b/utils/summary/summary.go @@ -79,9 +79,7 @@ func (bis *BuildInfoSummary) AddSha256(sha256Str string) { func GetSummaryReport(success, failed int, failNoOp bool, err error) *Summary { summary := &Summary{Totals: &Totals{}} - if err != nil || failed > 0 { - summary.Status = Failure - } else if success == 0 && failNoOp { + if err != nil || failed > 0 || (success == 0 && failNoOp) { summary.Status = Failure } else { summary.Status = Success diff --git a/utils/tests/consts.go b/utils/tests/consts.go index 7e13132e6..8373be6d7 100644 --- a/utils/tests/consts.go +++ b/utils/tests/consts.go @@ -1,13 +1,11 @@ package tests import ( - "path/filepath" - - "github.com/jfrog/jfrog-client-go/artifactory/services" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" - servicesutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" - clientutils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/artifactory/services" + servicesUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" + clientUtils "github.com/jfrog/jfrog-client-go/utils" + "path/filepath" ) const ( @@ -93,8 +91,10 @@ const ( SearchAllMaven = "search_all_maven.json" SearchAllNpm = "search_all_npm.json" SearchAllRepo1 = "search_all_repo1.json" + SearchAllProdRepo = "search_all_prod_repo.json" SearchDistRepoByInSuffix = "search_dist_repo_by_in_suffix.json" SearchRepo1ByInSuffix = "search_repo1_by_in_suffix.json" + GoPublishRepoExcludes = "go_publish_repo_excludes.json" SearchRepo1IncludeDirs = "search_repo1_include_dirs.json" SearchRepo1NonExistFile = "search_repo1_ant_test_file.json" SearchRepo1NonExistFileAntExclusions = "search_repo1_ant_and_exclusions_test_file.json" @@ -148,6 +148,11 @@ const ( DockerRemoteRepositoryConfig = "docker_remote_repository_config.json" DockerVirtualRepositoryConfig = "docker_virtual_repository_config.json" XrayEndpoint = "xray/" + DevRepoRepositoryConfig = "dev_repo_repository_config.json" + ProdRepoRepositoryConfig = "prod_repo_repository_config.json" + UploadDevSpecA = "upload_dev_spec_a.json" + UploadDevSpecB = "upload_dev_spec_b.json" + UploadDevSpecC = "upload_dev_spec_c.json" ) var ( @@ -181,6 +186,9 @@ var ( RtRepo1 = "cli-rt1" RtRepo2 = "cli-rt2" RtVirtualRepo = "cli-rt-virtual" + // Repositories that are assigned to an environment. + RtDevRepo = "cli-rt-dev" + RtProdRepo = "cli-rt-prod" // These are not actual repositories. These patterns are meant to be used in both Repo1 and Repo2. RtRepo1And2 = "cli-rt*" RtRepo1And2Placeholder = "cli-rt(*)" @@ -202,6 +210,13 @@ var ( RtBuildName2 = "cli-rt-build2" RtBuildNameWithSpecialChars = "cli-rt-a$+~&^a#-build3" RtPermissionTargetName = "cli-rt-pt" + LcBuildName1 = "cli-lc-build1" + LcBuildName2 = "cli-lc-build2" + LcBuildName3 = "cli-lc-build3" + LcRbName1 = "cli-lc-rb1" + LcRbName2 = "cli-lc-rb2" + LcRbName3 = "cli-lc-rb3" + GoPublishWithExclusionPath = "github.com/jfrog/dependency/@v/github.com/jfrog/dependency@v1.1.1/" // Users UserName1 = "alice" @@ -1739,12 +1754,6 @@ func GetSearchResultAfterDeleteByPropsStep3() []utils.SearchResult { } } -func GetDockerSourceManifest() []string { - return []string{ - DockerLocalRepo + "/" + DockerImageName + "/1/manifest.json", - } -} - func GetDockerDeployedManifest() []string { return []string{ DockerLocalPromoteRepo + "/" + DockerImageName + "promotion" + "/2/manifest.json", @@ -1910,7 +1919,7 @@ func GetUploadedFileWithDownloadedPlaceHolder() []string { func GetFileWithDownloadedPlaceHolder() []string { return []string{ - filepath.Join(Out), + Out, filepath.Join(Out, "mypath2"), filepath.Join(Out, "mypath2", "b1.in"), filepath.Join(Out, "mypath2", "b2.in"), @@ -1932,7 +1941,7 @@ func GetUploadedFileWithDownloadedDoublePlaceHolder() []string { func GetFileWithDownloadedDoublePlaceHolder() []string { return []string{ - filepath.Join(Out), + Out, filepath.Join(Out, "mypath2"), filepath.Join(Out, "mypath2", "c"), filepath.Join(Out, "mypath2", "c", "c1.in"), @@ -1954,7 +1963,7 @@ func GetUploadedFileWithDownloadedPlaceHolderlashSlashSuffix() []string { func GetFileWithDownloadedPlaceHolderSlashSuffix() []string { return []string{ - filepath.Join(Out), + Out, filepath.Join(Out, "mypath2"), filepath.Join(Out, "mypath2", "b1.in"), filepath.Join(Out, "mypath2", "b2.in"), @@ -1972,17 +1981,17 @@ func GetFileWithDownloadedPlaceHolderSlashSuffix() []string { } } -func GetExpectedUploadSummaryDetails(RtUrl string) []clientutils.FileTransferDetails { +func GetExpectedUploadSummaryDetails(rtUrl string) []clientUtils.FileTransferDetails { path1, path2, path3 := filepath.Join("testdata", "a", "a1.in"), filepath.Join("testdata", "a", "a2.in"), filepath.Join("testdata", "a", "a3.in") - return []clientutils.FileTransferDetails{ - {SourcePath: path1, RtUrl: RtUrl, TargetPath: RtRepo1 + "/testdata/a/a1.in", Sha256: "4eb341b5d2762a853d79cc25e622aa8b978eb6e12c3259e2d99dc9dc60d82c5d"}, - {SourcePath: path2, RtUrl: RtUrl, TargetPath: RtRepo1 + "/testdata/a/a2.in", Sha256: "3e3deb6628658a48cf0d280a2210211f9d977ec2e10a4619b95d5fb85cb10450"}, - {SourcePath: path3, RtUrl: RtUrl, TargetPath: RtRepo1 + "/testdata/a/a3.in", Sha256: "14e3dc4749bf42df13a67a271065b0f334d0ad36bb34a74cc57c6e137f9af09e"}, + return []clientUtils.FileTransferDetails{ + {SourcePath: path1, RtUrl: rtUrl, TargetPath: RtRepo1 + "/testdata/a/a1.in", Sha256: "4eb341b5d2762a853d79cc25e622aa8b978eb6e12c3259e2d99dc9dc60d82c5d"}, + {SourcePath: path2, RtUrl: rtUrl, TargetPath: RtRepo1 + "/testdata/a/a2.in", Sha256: "3e3deb6628658a48cf0d280a2210211f9d977ec2e10a4619b95d5fb85cb10450"}, + {SourcePath: path3, RtUrl: rtUrl, TargetPath: RtRepo1 + "/testdata/a/a3.in", Sha256: "14e3dc4749bf42df13a67a271065b0f334d0ad36bb34a74cc57c6e137f9af09e"}, } } -func GetReplicationConfig() []servicesutils.ReplicationParams { - return []servicesutils.ReplicationParams{ +func GetReplicationConfig() []servicesUtils.ReplicationParams { + return []servicesUtils.ReplicationParams{ { Url: *JfrogUrl + ArtifactoryEndpoint + "targetRepo", Username: "admin", @@ -2075,3 +2084,68 @@ func GetTransferExpectedRepoSnapshot() []string { RtRepo1 + "/testdata/a/b/b3.in", } } + +func GetExpectedLifecycleArtifacts() []string { + return []string{ + RtProdRepo + "/a1.in", + RtProdRepo + "/a2.in", + RtProdRepo + "/a3.in", + RtProdRepo + "/b1.in", + RtProdRepo + "/b2.in", + RtProdRepo + "/b3.in", + RtProdRepo + "/c1.in", + RtProdRepo + "/c2.in", + RtProdRepo + "/c3.in", + } +} + +func GetGoPublishWithExclusionsExpectedRepoGo() []string { + var expected = []string{ + GoRepo + "/github.com/jfrog/dependency/@v/v1.1.1.info", + GoRepo + "/github.com/jfrog/dependency/@v/v1.1.1.mod", + GoRepo + "/github.com/jfrog/dependency/@v/v1.1.1.zip", + } + return expected +} + +func GetGoPublishWithExclusionsExpectedFiles1() []string { + var expected = []string{ + GoPublishWithExclusionPath + "dir4/d.txt", + } + return expected +} + +func GetGoPublishWithExclusionsExcludedFiles1() []string { + var excluded = []string{ + GoPublishWithExclusionPath + "dir1/a.txt", + GoPublishWithExclusionPath + "dir1/dir2/b.txt", + GoPublishWithExclusionPath + "dir1/dir2/dir3/c.txt", + } + return excluded +} + +func GetGoPublishWithExclusionsExpectedFiles2() []string { + var expected = []string{ + GoPublishWithExclusionPath + "dir4/d.txt", + GoPublishWithExclusionPath + "dir1/a.txt", + } + return expected +} + +func GetGoPublishWithExclusionsExcludedFiles2() []string { + var excluded = []string{ + GoPublishWithExclusionPath + "dir1/dir2/b.txt", + GoPublishWithExclusionPath + "dir1/dir2/dir3/c.txt", + } + return excluded +} + +func GetGoPublishWithExclusionsExcludedFiles3() []string { + var excluded = []string{ + GoPublishWithExclusionPath + "dir1/a.txt", + GoPublishWithExclusionPath + "dir1/dir2/b.txt", + GoPublishWithExclusionPath + "dir1/dir2/dir3/c.txt", + GoPublishWithExclusionPath + "dir4/d.txt", + } + return excluded +} diff --git a/utils/tests/container.go b/utils/tests/container.go index 7894cea76..05024b0f1 100644 --- a/utils/tests/container.go +++ b/utils/tests/container.go @@ -3,12 +3,10 @@ package tests import ( "context" "fmt" - "io" - "testing" - "github.com/jfrog/jfrog-client-go/utils/log" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" + "io" ) // When two containers are joined to the same network, one container is able to address another by using its name (as the hostname). @@ -55,14 +53,14 @@ func NewContainerRequest() *ContainerRequest { // rather than using a pre-built image. // This setter cannot be used with 'SetImage' to run a container.. // -// context - The path to the context of of the docker build +// context - The path to the context of the docker build // file - The path from the context to the Dockerfile for the image, defaults to "Dockerfile" // BuildArgs - Args to docker daemon -func (c *ContainerRequest) SetDockerfile(context, file string, BuildArgs map[string]*string) *ContainerRequest { +func (c *ContainerRequest) SetDockerfile(context, file string, buildArgs map[string]*string) *ContainerRequest { c.request.FromDockerfile = testcontainers.FromDockerfile{ Context: context, Dockerfile: file, - BuildArgs: BuildArgs, + BuildArgs: buildArgs, PrintBuildLog: true, } return c @@ -123,7 +121,7 @@ func (c *ContainerRequest) WaitFor(waitingFor wait.Strategy) *ContainerRequest { } // Creates a container based on container request parameters. -func (c *ContainerRequest) Build(ctx context.Context, t *testing.T, autoStart bool) (*TestContainer, error) { +func (c *ContainerRequest) Build(ctx context.Context, autoStart bool) (*TestContainer, error) { container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: c.request, Started: autoStart, diff --git a/utils/tests/proxy/server/server.go b/utils/tests/proxy/server/server.go index 308ae0930..2462e5d75 100644 --- a/utils/tests/proxy/server/server.go +++ b/utils/tests/proxy/server/server.go @@ -86,7 +86,7 @@ func copyHeaders(dst, src http.Header) { func httpProxyHandler(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/" { - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) } else { removeProxyHeaders(r) t := &http.Transport{} @@ -118,7 +118,7 @@ type testProxy struct { func (t *testProxy) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) { if request.RequestURI == "/" { - responseWriter.WriteHeader(200) + responseWriter.WriteHeader(http.StatusOK) } else { host := request.URL.Host request.Host = "https://" + request.Host diff --git a/utils/tests/utils.go b/utils/tests/utils.go index bd16fa265..227f96b43 100644 --- a/utils/tests/utils.go +++ b/utils/tests/utils.go @@ -7,6 +7,7 @@ import ( "errors" "flag" "fmt" + "github.com/urfave/cli" "io" "math/rand" "os" @@ -68,6 +69,7 @@ var ( TestXray *bool TestAccess *bool TestTransfer *bool + TestLifecycle *bool HideUnitTestLog *bool ciRunId *string InstallDataTransferPlugin *bool @@ -103,6 +105,7 @@ func init() { TestXray = flag.Bool("test.xray", false, "Test Xray") TestAccess = flag.Bool("test.access", false, "Test Access") TestTransfer = flag.Bool("test.transfer", false, "Test files transfer") + TestLifecycle = flag.Bool("test.lc", false, "Test lifecycle") ContainerRegistry = flag.String("test.containerRegistry", "localhost:8082", "Container registry") HideUnitTestLog = flag.Bool("test.hideUnitTestLog", false, "Hide unit tests logs and print it in a file") InstallDataTransferPlugin = flag.Bool("test.installDataTransferPlugin", false, "Install data-transfer plugin on the source Artifactory server") @@ -349,6 +352,8 @@ var reposConfigMap = map[*string]string{ &DockerLocalPromoteRepo: DockerLocalPromoteRepositoryConfig, &DockerRemoteRepo: DockerRemoteRepositoryConfig, &DockerVirtualRepo: DockerVirtualRepositoryConfig, + &RtDevRepo: DevRepoRepositoryConfig, + &RtProdRepo: ProdRepoRepositoryConfig, } var CreatedNonVirtualRepositories map[*string]string @@ -399,6 +404,7 @@ func GetNonVirtualRepositories() map[*string]string { TestXray: {}, TestAccess: {&RtRepo1}, TestTransfer: {&RtRepo1, &RtRepo2, &MvnRepo1, &MvnRemoteRepo, &DockerRemoteRepo}, + TestLifecycle: {&RtDevRepo, &RtProdRepo}, } return getNeededRepositories(nonVirtualReposMap) } @@ -459,6 +465,7 @@ func GetBuildNames() []string { TestXray: {}, TestAccess: {}, TestTransfer: {&MvnBuildName}, + TestLifecycle: {&LcBuildName1, &LcBuildName2, &LcBuildName3}, } return getNeededBuildNames(buildNamesMap) } @@ -512,6 +519,13 @@ func getSubstitutionMap() map[string]string { "{PASSWORD_1}": Password1, "{USER_NAME_2}": UserName2, "{PASSWORD_2}": Password2, + "${LC_BUILD_NAME1}": LcBuildName1, + "${LC_BUILD_NAME2}": LcBuildName2, + "${LC_BUILD_NAME3}": LcBuildName3, + "${RB_NAME1}": LcRbName1, + "${RB_NAME2}": LcRbName2, + "${DEV_REPO}": RtDevRepo, + "${PROD_REPO}": RtProdRepo, } } @@ -561,6 +575,8 @@ func AddTimestampToGlobalVars() { RtRepo1And2Placeholder += uniqueSuffix RtRepo2 += uniqueSuffix RtVirtualRepo += uniqueSuffix + RtDevRepo += uniqueSuffix + RtProdRepo += uniqueSuffix // Builds/bundles/images BundleName += uniqueSuffix @@ -580,6 +596,12 @@ func AddTimestampToGlobalVars() { RtBuildName2 += uniqueSuffix RtBuildNameWithSpecialChars += uniqueSuffix RtPermissionTargetName += uniqueSuffix + LcBuildName1 += uniqueSuffix + LcBuildName2 += uniqueSuffix + LcBuildName3 += uniqueSuffix + LcRbName1 += uniqueSuffix + LcRbName2 += uniqueSuffix + LcRbName3 += uniqueSuffix // Users UserName1 += uniqueSuffix @@ -605,7 +627,7 @@ func ReplaceTemplateVariables(path, destPath string) (string, error) { } for name, value := range getSubstitutionMap() { - content = bytes.Replace(content, []byte(name), []byte(value), -1) + content = bytes.ReplaceAll(content, []byte(name), []byte(value)) } if destPath == "" { destPath, err = os.Getwd() @@ -620,7 +642,7 @@ func ReplaceTemplateVariables(path, destPath string) (string, error) { } specPath := filepath.Join(destPath, filepath.Base(path)) log.Info("Creating spec file at:", specPath) - err = os.WriteFile(specPath, []byte(content), 0700) + err = os.WriteFile(specPath, content, 0700) if err != nil { return "", errorutils.CheckError(err) } @@ -771,10 +793,31 @@ func VerifySha256DetailedSummaryFromResult(t *testing.T, result *commandutils.Re } func SkipKnownFailingTest(t *testing.T) { - skipDate := time.Date(2023, time.July, 0, 0, 0, 0, 0, time.UTC) + skipDate := time.Date(2023, time.August, 0, 0, 0, 0, 0, time.UTC) if time.Now().Before(skipDate) { t.Skip("Skipping a known failing test, will resume testing after ", skipDate.String()) } else { t.Error("Not skipping test. Please fix the test or delay the skipMonth") } } + +func CreateContext(t *testing.T, testFlags, testArgs []string) (*cli.Context, *bytes.Buffer) { + flagSet := createFlagSet(t, testFlags, testArgs) + app := cli.NewApp() + app.Writer = &bytes.Buffer{} + return cli.NewContext(app, flagSet, nil), &bytes.Buffer{} +} + +// Create flag set with input flags and arguments. +func createFlagSet(t *testing.T, flags []string, args []string) *flag.FlagSet { + flagSet := flag.NewFlagSet("TestFlagSet", flag.ContinueOnError) + flags = append(flags, "url=http://127.0.0.1:8081/artifactory") + var cmdFlags []string + for _, curFlag := range flags { + flagSet.String(strings.Split(curFlag, "=")[0], "", "") + cmdFlags = append(cmdFlags, "--"+curFlag) + } + cmdFlags = append(cmdFlags, args...) + assert.NoError(t, flagSet.Parse(cmdFlags)) + return flagSet +} diff --git a/xray_test.go b/xray_test.go index 5e162cc2e..795d73ced 100644 --- a/xray_test.go +++ b/xray_test.go @@ -97,7 +97,7 @@ func TestXrayBinaryScanJson(t *testing.T) { func TestXrayBinaryScanSimpleJson(t *testing.T) { output := testXrayBinaryScan(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 1, 1) + verifySimpleJsonScanResults(t, output, 1, 1) } func TestXrayBinaryScanJsonWithProgress(t *testing.T) { @@ -111,7 +111,7 @@ func TestXrayBinaryScanSimpleJsonWithProgress(t *testing.T) { callback := tests.MockProgressInitialization() defer callback() output := testXrayBinaryScan(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 1, 1) + verifySimpleJsonScanResults(t, output, 1, 1) } func testXrayBinaryScan(t *testing.T, format string) string { @@ -145,7 +145,7 @@ func TestXrayAuditNpmJson(t *testing.T) { func TestXrayAuditNpmSimpleJson(t *testing.T) { output := testXrayAuditNpm(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 1, 1) + verifySimpleJsonScanResults(t, output, 1, 1) } func testXrayAuditNpm(t *testing.T, format string) string { @@ -211,7 +211,7 @@ func TestXrayAuditYarnJson(t *testing.T) { func TestXrayAuditYarnSimpleJson(t *testing.T) { testXrayAuditYarn(t, "yarn", func() { output := runXrayAuditYarnWithOutput(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 1, 1) + verifySimpleJsonScanResults(t, output, 1, 1) }) } @@ -250,7 +250,7 @@ func TestXrayAuditNugetJson(t *testing.T) { func TestXrayAuditNugetSimpleJson(t *testing.T) { output := testXrayAuditNuget(t, "single", string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 2, 0) + verifySimpleJsonScanResults(t, output, 2, 0) } // Tests NuGet audit by providing a multi-project NuGet project and asserts any error. @@ -282,7 +282,7 @@ func TestXrayAuditGradleJson(t *testing.T) { func TestXrayAuditGradleSimpleJson(t *testing.T) { output := testXrayAuditGradle(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 0, 0) + verifySimpleJsonScanResults(t, output, 0, 0) } func testXrayAuditGradle(t *testing.T, format string) string { @@ -306,7 +306,7 @@ func TestXrayAuditMavenJson(t *testing.T) { func TestXrayAuditMavenSimpleJson(t *testing.T) { output := testXrayAuditMaven(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 1, 1) + verifySimpleJsonScanResults(t, output, 1, 1) } func testXrayAuditMaven(t *testing.T, format string) string { @@ -331,7 +331,7 @@ func TestXrayAuditNoTech(t *testing.T) { defer clientTestUtils.ChangeDirAndAssert(t, prevWd) // Run audit on empty folder, expect an error err := xrayCli.Exec("audit") - assert.EqualError(t, err, "could not determine the package manager / build tool used by this project.") + assert.NoError(t, err) } func TestXrayAuditDetectTech(t *testing.T) { @@ -361,7 +361,7 @@ func TestXrayAuditMultiProjects(t *testing.T) { assert.NoError(t, fileutils.CopyDir(multiProject, tempDirPath, true, nil)) workingDirsFlag := fmt.Sprintf("--working-dirs=%s, %s ,%s", filepath.Join(tempDirPath, "maven"), filepath.Join(tempDirPath, "nuget", "single"), filepath.Join(tempDirPath, "python", "pip")) output := xrayCli.RunCliCmdWithOutput(t, "audit", "--format="+string(utils.SimpleJson), workingDirsFlag) - verifySimpleJsonScanResults(t, output, 0, 0, 30, 0) + verifySimpleJsonScanResults(t, output, 30, 0) } func TestXrayAuditPipJson(t *testing.T) { @@ -371,7 +371,7 @@ func TestXrayAuditPipJson(t *testing.T) { func TestXrayAuditPipSimpleJson(t *testing.T) { output := testXrayAuditPip(t, string(utils.SimpleJson), "") - verifySimpleJsonScanResults(t, output, 0, 0, 3, 1) + verifySimpleJsonScanResults(t, output, 3, 1) } func TestXrayAuditPipJsonWithRequirementsFile(t *testing.T) { @@ -381,7 +381,7 @@ func TestXrayAuditPipJsonWithRequirementsFile(t *testing.T) { func TestXrayAuditPipSimpleJsonWithRequirementsFile(t *testing.T) { output := testXrayAuditPip(t, string(utils.SimpleJson), "requirements.txt") - verifySimpleJsonScanResults(t, output, 0, 0, 2, 0) + verifySimpleJsonScanResults(t, output, 2, 0) } func testXrayAuditPip(t *testing.T, format, requirementsFile string) string { @@ -410,7 +410,7 @@ func TestXrayAuditPipenvJson(t *testing.T) { func TestXrayAuditPipenvSimpleJson(t *testing.T) { output := testXrayAuditPipenv(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 3, 1) + verifySimpleJsonScanResults(t, output, 3, 1) } func testXrayAuditPipenv(t *testing.T, format string) string { @@ -472,7 +472,7 @@ func TestXrayAuditPoetryJson(t *testing.T) { func TestXrayAuditPoetrySimpleJson(t *testing.T) { output := testXrayAuditPoetry(t, string(utils.SimpleJson)) - verifySimpleJsonScanResults(t, output, 0, 0, 3, 1) + verifySimpleJsonScanResults(t, output, 3, 1) } func testXrayAuditPoetry(t *testing.T, format string) string { @@ -541,12 +541,10 @@ func verifyJsonScanResults(t *testing.T, content string, minViolations, minVulne } } -func verifySimpleJsonScanResults(t *testing.T, content string, minSecViolations, minLicViolations, minVulnerabilities, minLicenses int) { +func verifySimpleJsonScanResults(t *testing.T, content string, minVulnerabilities, minLicenses int) { var results formats.SimpleJsonResults err := json.Unmarshal([]byte(content), &results) if assert.NoError(t, err) { - assert.GreaterOrEqual(t, len(results.SecurityViolations), minSecViolations) - assert.GreaterOrEqual(t, len(results.LicensesViolations), minLicViolations) assert.GreaterOrEqual(t, len(results.Vulnerabilities), minVulnerabilities) assert.GreaterOrEqual(t, len(results.Licenses), minLicenses) } @@ -753,11 +751,13 @@ func TestCurationAudit(t *testing.T) { output := localXrayCli.RunCliCmdWithOutput(t, "curation-audit", "--format="+string(utils.Json), workingDirsFlag) expectedResp := getCurationExpectedResponse(config) var got []coreCuration.PackageStatus - err = json.Unmarshal([]byte(output[strings.Index(output, "["):]), &got) + bracketIndex := strings.Index(output, "[") + require.Less(t, 0, bracketIndex, "Unexpected Curation output with missing '['") + err = json.Unmarshal([]byte(output[bracketIndex:]), &got) assert.NoError(t, err) assert.Equal(t, expectedResp, got) for k, v := range expectedRequest { - assert.Truef(t, v, "didn't recieve expected GET request for packe url %s", k) + assert.Truef(t, v, "didn't receive expected GET request for package url %s", k) } } @@ -775,8 +775,16 @@ func getCurationExpectedResponse(config *config.ServerDetails) []coreCuration.Pa PkgType: "npm", Policy: []coreCuration.Policy{ { - Policy: "pol1", - Condition: "cond1", + Policy: "pol1", + Condition: "cond1", + Explanation: "explanation", + Recommendation: "recommendation", + }, + { + Policy: "pol2", + Condition: "cond2", + Explanation: "explanation2", + Recommendation: "recommendation2", }, }, }, @@ -802,7 +810,7 @@ func curationServer(t *testing.T, expectedRequest map[string]bool, requestToFail w.WriteHeader(http.StatusForbidden) _, err := w.Write([]byte("{\n \"errors\": [\n {\n \"status\": 403,\n " + "\"message\": \"Package download was blocked by JFrog Packages " + - "Curation service due to the following policies violated {pol1, cond1}\"\n }\n ]\n}")) + "Curation service due to the following policies violated {pol1, cond1, explanation, recommendation}, {pol2, cond2, explanation2, recommendation2}\"\n }\n ]\n}")) require.NoError(t, err) } }