From bb0814074f4acea108f8f1bb69a625b4c352db11 Mon Sep 17 00:00:00 2001 From: Eyal Ben Moshe Date: Mon, 3 Jun 2024 09:24:55 +0300 Subject: [PATCH 1/3] Remove the (#2562) --- artifactory_test.go | 77 --- docs/general/cisetup/help.go | 7 - docs/general/project/init/help.go | 8 - general/cisetup/cisetup.go | 1046 ----------------------------- general/cisetup/cisetup_test.go | 46 -- general/cisetup/utils.go | 102 --- general/project/cli.go | 52 -- go.mod | 10 +- go.sum | 12 +- main.go | 22 - 10 files changed, 12 insertions(+), 1370 deletions(-) delete mode 100644 docs/general/cisetup/help.go delete mode 100644 docs/general/project/init/help.go delete mode 100644 general/cisetup/cisetup.go delete mode 100644 general/cisetup/cisetup_test.go delete mode 100644 general/cisetup/utils.go delete mode 100644 general/project/cli.go diff --git a/artifactory_test.go b/artifactory_test.go index df72662ee..de295ae8e 100644 --- a/artifactory_test.go +++ b/artifactory_test.go @@ -33,7 +33,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" "github.com/jfrog/jfrog-cli-core/v2/common/commands" - "github.com/jfrog/jfrog-cli-core/v2/common/project" "github.com/jfrog/jfrog-cli-core/v2/common/spec" commontests "github.com/jfrog/jfrog-cli-core/v2/common/tests" "github.com/jfrog/jfrog-cli-core/v2/utils/config" @@ -5652,82 +5651,6 @@ func readerGetErrorAndAssert(t *testing.T, reader *content.ContentReader) { assert.NoError(t, reader.GetError(), "Couldn't get reader error") } -func TestProjectInitMaven(t *testing.T) { - testProjectInit(t, "multiproject", coreutils.Maven) -} - -func TestProjectInitGradle(t *testing.T) { - testProjectInit(t, "gradleproject", coreutils.Gradle) -} - -func TestProjectInitNpm(t *testing.T) { - testProjectInit(t, "npmproject", coreutils.Npm) -} - -func TestProjectInitGo(t *testing.T) { - testProjectInit(t, "dependency", coreutils.Go) -} - -func TestProjectInitPip(t *testing.T) { - testProjectInit(t, "requirementsproject", coreutils.Pip) -} - -func TestProjectInitNuget(t *testing.T) { - testProjectInit(t, "multipackagesconfig", coreutils.Nuget) -} - -func testProjectInit(t *testing.T, projectExampleName string, technology coreutils.Technology) { - initArtifactoryTest(t, "") - defer cleanArtifactoryTest() - // Create temp JFrog home dir - tmpHomeDir, deleteHomeDir := coretests.CreateTempDirWithCallbackAndAssert(t) - defer deleteHomeDir() - clientTestUtils.SetEnvAndAssert(t, coreutils.HomeDir, tmpHomeDir) - _, err := createServerConfigAndReturnPassphrase(t) - assert.NoError(t, err) - - // Copy a simple project in a temp work dir - tmpWorkDir, deleteWorkDir := coretests.CreateTempDirWithCallbackAndAssert(t) - defer deleteWorkDir() - testdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), technology.String(), projectExampleName) - err = biutils.CopyDir(testdataSrc, tmpWorkDir, true, nil) - assert.NoError(t, err) - if technology == coreutils.Go { - goModeOriginalPath := filepath.Join(tmpWorkDir, "createGoProject_go.mod_suffix") - goModeTargetPath := filepath.Join(tmpWorkDir, "go.mod") - assert.NoError(t, os.Rename(goModeOriginalPath, goModeTargetPath)) - } - - // Run cd command to temp dir. - currentWd, err := os.Getwd() - assert.NoError(t, err) - changeDirBack := clientTestUtils.ChangeDirWithCallback(t, currentWd, tmpWorkDir) - defer changeDirBack() - // Run JFrog project init - err = platformCli.WithoutCredentials().Exec("project", "init", "--path", tmpWorkDir, "--server-id="+tests.ServerId) - assert.NoError(t, err) - // Validate correctness of .jfrog/projects/$technology.yml - validateProjectYamlFile(t, tmpWorkDir, technology.String()) - // Validate correctness of .jfrog/projects/build.yml - validateBuildYamlFile(t, tmpWorkDir) -} - -func validateProjectYamlFile(t *testing.T, projectDir, technology string) { - techConfig, err := project.ReadConfigFile(filepath.Join(projectDir, ".jfrog", "projects", technology+".yaml"), project.YAML) - if assert.NoError(t, err) { - assert.Equal(t, technology, techConfig.GetString("type")) - assert.Equal(t, tests.ServerId, techConfig.GetString("resolver.serverId")) - assert.Equal(t, tests.ServerId, techConfig.GetString("deployer.serverId")) - } -} - -func validateBuildYamlFile(t *testing.T, projectDir string) { - techConfig, err := project.ReadConfigFile(filepath.Join(projectDir, ".jfrog", "projects", "build.yaml"), project.YAML) - assert.NoError(t, err) - assert.Equal(t, "build", techConfig.GetString("type")) - assert.Equal(t, filepath.Base(projectDir+"/"), techConfig.GetString("name")) -} - func TestTerraformPublish(t *testing.T) { testTerraformPublish(t, false) } diff --git a/docs/general/cisetup/help.go b/docs/general/cisetup/help.go deleted file mode 100644 index c3bdbfdb3..000000000 --- a/docs/general/cisetup/help.go +++ /dev/null @@ -1,7 +0,0 @@ -package cisetup - -var Usage = []string{"ci-setup "} - -func GetDescription() string { - return "Set up a CI pipeline with the JFrog Platform." -} diff --git a/docs/general/project/init/help.go b/docs/general/project/init/help.go deleted file mode 100644 index b8f8506fc..000000000 --- a/docs/general/project/init/help.go +++ /dev/null @@ -1,8 +0,0 @@ -package projectinit - -var Usage = []string{"project init", - "project init "} - -func GetDescription() string { - return "Initialize a new project environment." -} diff --git a/general/cisetup/cisetup.go b/general/cisetup/cisetup.go deleted file mode 100644 index 07af9a7c1..000000000 --- a/general/cisetup/cisetup.go +++ /dev/null @@ -1,1046 +0,0 @@ -package cisetup - -import ( - "bytes" - "encoding/json" - "fmt" - "golang.org/x/exp/slices" - "os" - "path" - "path/filepath" - "strings" - "syscall" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/transport" - "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/buildinfo" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/permissiontarget" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/usersmanagement" - "github.com/jfrog/jfrog-cli-core/v2/common/build" - coreCommonCommands "github.com/jfrog/jfrog-cli-core/v2/common/commands" - "github.com/jfrog/jfrog-cli-core/v2/general/cisetup" - repoutils "github.com/jfrog/jfrog-cli-core/v2/general/project" - utilsConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" - buildinfocmd "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" - "github.com/jfrog/jfrog-client-go/artifactory/services" - clientConfig "github.com/jfrog/jfrog-client-go/config" - "github.com/jfrog/jfrog-client-go/pipelines" - pipelinesservices "github.com/jfrog/jfrog-client-go/pipelines/services" - "github.com/jfrog/jfrog-client-go/utils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - xrayservices "github.com/jfrog/jfrog-client-go/xray/services" - xrayutils "github.com/jfrog/jfrog-client-go/xray/services/utils" - "golang.org/x/term" -) - -const ( - VcsConfigFile = "jfrog-cli-vcs.conf" - DefaultFirstBuildNumber = "0" - DefaultWorkspace = "./ci-setup-workspace" - pipelineUiPath = "ui/pipelines/myPipelines/default/" - permissionTargetName = "jfrog-ide-developer-pt" - permissionTargetTemplate = `{"build":{"include-patterns":"**","actions-groups":{"%s":"read"}},"name":"%s"}` - pttFileName = "ci-setup-ptt" - ideGroupName = "jfrog-ide-developer-group" - ideUserName = "ide-developer" - ideUserPassPlaceholder = "" - ideUserEmailPlaceholder = "" - createUserTemplate = `jfrog rt user-create "%s" "%s" "%s" --users-groups="%s" --server-id="%s"` - maxRepoCreationAttempts = 200 -) - -type CiSetupCommand struct { - defaultData *cisetup.CiSetupData - data *cisetup.CiSetupData -} - -func RunCiSetupCmd() error { - cc := &CiSetupCommand{} - err := logBeginningInstructions() - if err != nil { - return err - } - err = cc.prepareConfigurationData() - if err != nil { - return err - } - err = cc.Run() - if err != nil { - return err - } - return saveVcsConf(cc.data) -} - -func logBeginningInstructions() error { - instructions := []string{ - "", - coreutils.PrintTitle("About this command"), - "This command sets up a basic CI pipeline which uses the JFrog Platform.", - "It currently supports Maven, Gradle and npm, but additional package managers will be added in the future.", - "The following CI providers are currently supported: JFrog Pipelines, Jenkins and GitHub Actions.", - "The command takes care of configuring JFrog Artifactory and JFrog Xray for you.", - "", - coreutils.PrintTitle("Important"), - " 1. If you don't have a JFrog Platform instance with admin credentials, head over to https://jfrog.com/start-free/ and get one for free.", - " 2. When asked to provide credentials for your JFrog Platform and Git provider, please make sure the credentials have admin privileges.", - " 3. You can exit the command by hitting 'control + C' at any time. The values you provided before exiting are saved (with the exception of passwords and tokens) and will be set as defaults the next time you run the command.", - "", "", - } - return writeToScreen(strings.Join(instructions, "\n")) -} - -func inactivePipelinesNote(pipelinesUrl string) error { - instructions := []string{ - "", - coreutils.PrintTitle("JFrog Pipelines"), - "It looks like your JFrog platform does not include JFrog Pipelines or it is currently inactive.", - pipelinesUrl, - "", - } - return writeToScreen(strings.Join(instructions, "\n")) -} - -func (cc *CiSetupCommand) prepareConfigurationData() error { - // If data is nil, initialize a new one - if cc.data == nil { - cc.data = new(cisetup.CiSetupData) - } - - // Get previous vcs data if exists - defaultData, err := readVcsConf() - cc.defaultData = defaultData - return err -} - -func readVcsConf() (*cisetup.CiSetupData, error) { - conf := &cisetup.CiSetupData{} - homeDirPath, err := coreutils.GetJfrogHomeDir() - if err != nil { - return nil, err - } - confPath := filepath.Join(homeDirPath, VcsConfigFile) - exists, err := fileutils.IsFileExists(confPath, false) - if err != nil { - return nil, err - } - if !exists { - return conf, nil - } - configFile, err := fileutils.ReadFile(confPath) - if err != nil { - return nil, err - } - err = json.Unmarshal(configFile, conf) - return conf, errorutils.CheckError(err) -} - -func saveVcsConf(conf *cisetup.CiSetupData) error { - homeDirPath, err := coreutils.GetJfrogHomeDir() - if err != nil { - return err - } - bytesContent, err := json.Marshal(conf) - if err != nil { - return errorutils.CheckError(err) - } - var content bytes.Buffer - err = json.Indent(&content, bytesContent, "", " ") - if err != nil { - return errorutils.CheckError(err) - } - err = os.WriteFile(filepath.Join(homeDirPath, VcsConfigFile), content.Bytes(), 0600) - return errorutils.CheckError(err) -} - -func (cc *CiSetupCommand) Run() error { - // Run JFrog config command - err := runConfigCmd() - if err != nil { - return err - } - // Basic VCS questionnaire (URLs, Credentials, etc'...) - err = cc.gitPhase() - err = saveIfNoError(err, cc.data) - if err != nil { - return err - } - // Ask the user which CI he tries to setup - cc.ciProviderPhase() - err = saveVcsConf(cc.data) - if err != nil { - return err - } - // Interactively create Artifactory repository based on the detected technologies and ongoing user input - err = cc.artifactoryConfigPhase() - err = saveIfNoError(err, cc.data) - if err != nil { - return err - } - // Publish empty build info. - err = cc.publishFirstBuild() - err = saveIfNoError(err, cc.data) - if err != nil { - return err - } - // Configure Xray to scan the new build. - err = cc.xrayConfigPhase() - err = saveIfNoError(err, cc.data) - if err != nil { - return err - } - var ciSpecificInstructions []string - switch cc.data.CiType { - case cisetup.Pipelines: - // Configure pipelines, create and stage pipelines.yml. - ciFileName, err := cc.runPipelinesPhase() - if err != nil { - return err - } - ciSpecificInstructions, err = cc.getPipelinesCompletionInstruction(ciFileName) - if err != nil { - return err - } - case cisetup.Jenkins: - // Create and stage Jenkinsfile. - _, err := cc.runJenkinsPhase() - if err != nil { - return err - } - ciSpecificInstructions = cc.getJenkinsCompletionInstruction() - case cisetup.GithubActions: - // Create and stage main.yml. - ciFileName, err := cc.runGithubActionsPhase() - if err != nil { - return err - } - ciSpecificInstructions = cc.getGithubActionsCompletionInstruction(ciFileName) - } - // Create group and permission target if needed. - err = runIdePhase() - if err != nil { - return err - } - return cc.logCompletionInstruction(ciSpecificInstructions) -} - -func saveIfNoError(errCheck error, conf *cisetup.CiSetupData) error { - if errCheck != nil { - return errCheck - } - return saveVcsConf(conf) -} - -func runIdePhase() error { - serverDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return err - } - err = createGroup(serverDetails) - if err != nil { - return err - } - return createPermissionTarget(serverDetails) -} - -func createGroup(serverDetails *utilsConfig.ServerDetails) error { - log.Info("Creating group...") - groupCreateCmd := usersmanagement.NewGroupCreateCommand() - groupCreateCmd.SetName(ideGroupName).SetServerDetails(serverDetails).SetReplaceIfExists(false) - err := groupCreateCmd.Run() - if err != nil { - if _, ok := err.(*services.GroupAlreadyExistsError); !ok { - return err - } - log.Debug("Group already exists, skipping...") - } - return nil -} - -func createPermissionTarget(serverDetails *utilsConfig.ServerDetails) error { - ptTemplate := fmt.Sprintf(permissionTargetTemplate, ideGroupName, permissionTargetName) - tempDir, err := fileutils.CreateTempDir() - if err != nil { - return err - } - pttPath := filepath.Join(tempDir, pttFileName) - err = os.WriteFile(pttPath, []byte(ptTemplate), 0600) - if err != nil { - return err - } - permissionTargetCreateCmd := permissiontarget.NewPermissionTargetCreateCommand() - permissionTargetCreateCmd.SetTemplatePath(pttPath).SetServerDetails(serverDetails).SetVars("") - err = permissionTargetCreateCmd.Run() - if err != nil { - if _, ok := err.(*services.PermissionTargetAlreadyExistsError); !ok { - return err - } - log.Debug("Permission target already exists, skipping...") - } - return nil -} - -func writeToScreen(content string) error { - _, err := fmt.Fprint(os.Stderr, content) - return errorutils.CheckError(err) -} - -func getPipelinesToken() (string, error) { - var err error - var byteToken []byte - for len(byteToken) == 0 { - err = writeToScreen("Please provide a JFrog Pipelines admin token (To generate the token, " + - "log into the JFrog Platform UI --> Administration --> Identity and Access --> Access Tokens --> Generate Admin Token): ") - if err != nil { - return "", err - } - //nolint:unconvert - byteToken, err = term.ReadPassword(int(syscall.Stdin)) - if err != nil { - return "", errorutils.CheckError(err) - } - // New-line required after the access token input: - log.Output() - } - return string(byteToken), nil -} - -func runConfigCmd() (err error) { - for { - configCmd := coreCommonCommands.NewConfigCommand(coreCommonCommands.AddOrEdit, cisetup.ConfigServerId).SetInteractive(true).SetEncPassword(true) - err = configCmd.Run() - if err != nil { - log.Error(err) - continue - } - // Validate JFrog credentials by execute get repo command - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return err - } - _, err = GetAllRepos(serviceDetails, "", "") - if err == nil { - return nil - } - log.Error(err) - } -} - -func (cc *CiSetupCommand) runJenkinsPhase() (string, error) { - generator := cisetup.JenkinsfileDslGenerator{ - SetupData: cc.data, - } - jenkinsfileBytes, jenkinsfileName, err := generator.GenerateDsl() - if err != nil { - return "", err - } - - err = cc.saveCiConfigToFile(jenkinsfileBytes, cisetup.JenkinsfileName) - if err != nil { - return "", err - } - err = cc.stageCiConfigFile(cisetup.JenkinsfileName) - if err != nil { - return "", err - } - return jenkinsfileName, nil -} - -func (cc *CiSetupCommand) runGithubActionsPhase() (string, error) { - generator := cisetup.GithubActionsGenerator{ - SetupData: cc.data, - } - GithubActionsYamlBytes, GithubActionsName, err := generator.Generate() - if err != nil { - return "", err - } - err = os.MkdirAll(filepath.Join(cc.data.LocalDirPath, cisetup.GithubActionsDir), 0744) - if err != nil { - return "", errorutils.CheckError(err) - } - err = cc.saveCiConfigToFile(GithubActionsYamlBytes, cisetup.GithubActionsFilePath) - if err != nil { - return "", err - } - err = cc.stageCiConfigFile(cisetup.GithubActionsFilePath) - - return GithubActionsName, err -} - -func (cc *CiSetupCommand) runPipelinesPhase() (string, error) { - var vcsIntName string - var rtIntName string - var err error - configurator := cisetup.JFrogPipelinesConfigurator{ - SetupData: cc.data, PipelinesToken: "", - } - // Ask for token and config pipelines. Run again if authentication problem. - for { - // Ask for pipelines token. - configurator.PipelinesToken, err = getPipelinesToken() - if err != nil { - return "", err - } - // Run Pipelines setup - vcsIntName, rtIntName, err = configurator.Config() - // If no error occurred, continue with flow. Elseif unauthorized error, ask for token again. - if err == nil { - break - } - if _, ok := err.(*pipelinesservices.IntegrationUnauthorizedError); !ok { - return "", err - } - log.Debug(err.Error()) - log.Info("There seems to be an authorization problem with the pipelines token you entered. Please try again.") - } - generator := cisetup.JFrogPipelinesYamlGenerator{ - VcsIntName: vcsIntName, - RtIntName: rtIntName, - SetupData: cc.data, - } - pipelinesYamlBytes, pipelineName, err := generator.Generate() - if err != nil { - return "", err - } - - err = cc.saveCiConfigToFile(pipelinesYamlBytes, cisetup.PipelinesYamlName) - if err != nil { - return "", err - } - err = cc.stageCiConfigFile(cisetup.PipelinesYamlName) - if err != nil { - return "", err - } - return pipelineName, nil -} - -func (cc *CiSetupCommand) saveCiConfigToFile(ciConfig []byte, fileName string) error { - filePath := filepath.Join(cc.data.LocalDirPath, fileName) - log.Info(fmt.Sprintf("Generating %s at: %q ...", fileName, filePath)) - return os.WriteFile(filePath, ciConfig, 0644) -} - -func (cc *CiSetupCommand) getPipelinesCompletionInstruction(pipelinesFileName string) ([]string, error) { - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return []string{}, err - } - - return []string{"", coreutils.PrintTitle("Completing the setup"), - "We configured the JFrog Platform and generated a pipelines.yml for you.", - "To complete the setup, add the new pipelines.yml to your git repository by running the following commands:", - "", - "\t cd " + cc.data.LocalDirPath, - "\t git commit -m \"Add " + pipelinesFileName + "\"", - "\t git push", - "", - "Although your pipeline is configured, it hasn't run yet.", - "It will run and become visible in the following URL, after the next git commit:", - getPipelineUiPath(serviceDetails.Url, pipelinesFileName), ""}, nil -} - -func (cc *CiSetupCommand) getJenkinsCompletionInstruction() []string { - JenkinsCompletionInstruction := []string{"", coreutils.PrintTitle("Completing the setup"), - "We configured the JFrog Platform and generated a Jenkinsfile file for you under " + cc.data.LocalDirPath, - "To complete the setup, follow these steps:", - "* Open the Jenkinsfile for edit."} - // HOME env instructions relevant only for Maven - if cc.data.BuiltTechnology.Type == coreutils.Maven || cc.data.BuiltTechnology.Type == coreutils.Gradle { - JenkinsCompletionInstruction = append(JenkinsCompletionInstruction, - "* Inside the 'environment' section, set the value of the HOME ENV variable,", - " to the Maven installation directory on the Jenkins agent (the directory which includes the 'bin' directory).") - } - - JenkinsCompletionInstruction = append(JenkinsCompletionInstruction, - "* If cloning the code from git requires credentials, modify the 'git' step as described", - " in the comment inside the 'Clone' step.", - "* Create credentials with 'rt-cred-id' as its ID in: Jenkins > Configure System > credentials > 'username with password' > ID: 'rt-cred-id' )", - " Read more about this here - https://www.jenkins.io/doc/book/using/using-credentials/", - "* Add the new Jenkinsfile to your git repository by running the following commands:", - "", - "\t cd "+cc.data.LocalDirPath, - "\t git commit -m \"Add Jenkinsfile\"", - "\t git push", - "", - "* Create a Pipelines job in Jenkins, and configure it to pull the new Jenkinsfile from git.", - "* Run the new Jenkins job. ", "") - - return JenkinsCompletionInstruction -} - -func (cc *CiSetupCommand) getGithubActionsCompletionInstruction(githubActionFileName string) []string { - return []string{"", coreutils.PrintTitle("Completing the setup"), - "We configured the JFrog Platform and generated a GitHub Actions workflow file", - "named " + cisetup.GithubActionsFileName + " for you under " + cisetup.GithubActionsDir + ".", - "", - "To complete the setup, follow these steps:", - "* Run the following JFrog CLI command:", - "", - "\t jfrog c export " + cisetup.ConfigServerId, - "", - "* Copy the displayed token into your clipboard and save it as a secret", - " named JF_ARTIFACTORY_SECRET_1 on GitHub.", - "* Add the new workflow file to your git repository by running the following commands:", - "", - "\t cd " + cc.data.LocalDirPath, - "\t git commit -m \"Add " + githubActionFileName + "\"", - "\t git push", - "", - "* View the build running on GitHub.", - ""} -} - -func (cc *CiSetupCommand) logCompletionInstruction(ciSpecificInstructions []string) error { - 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:", - " 1. Make sure the latest version of the JFrog Plugin is installed on IntelliJ IDEA:", - " https://www.jfrog.com/confluence/display/JFROG/JFrog+IntelliJ+IDEA+Plugin", - " 2. Create a JFrog user for the IDE by running the following command:", - "", - "\t "+fmt.Sprintf(createUserTemplate, ideUserName, ideUserPassPlaceholder, ideUserEmailPlaceholder, ideGroupName, cisetup.ConfigServerId), - "", - " 3. In IDEA, under 'JFrog Global Configuration', set the JFrog Platform URL and the user you created.", - " 4. In IDEA, under 'JFrog CI Integration', set * as the 'Build name pattern'.", - " 5. In IDEA, open the 'JFrog' panel at the bottom of the screen, choose the 'CI' tab to see the CI information.", - "", - ) - return writeToScreen(strings.Join(instructions, "\n")) -} - -func getPipelineUiPath(pipelinesUrl, pipelineName string) string { - return utils.AddTrailingSlashIfNeeded(pipelinesUrl) + pipelineUiPath + pipelineName -} - -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) - buildConfiguration := build.NewBuildConfiguration(cc.data.BuildName, DefaultFirstBuildNumber, "", "") - buildAddGitConfigurationCmd = buildAddGitConfigurationCmd.SetBuildConfiguration(buildConfiguration) - log.Info("Generating an initial build-info...") - err = coreCommonCommands.Exec(buildAddGitConfigurationCmd) - if err != nil { - return err - } - // Run BP Command. - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return err - } - buildInfoConfiguration := buildinfocmd.Configuration{DryRun: false} - buildPublishCmd := buildinfo.NewBuildPublishCommand().SetServerDetails(serviceDetails).SetBuildConfiguration(buildConfiguration).SetConfig(&buildInfoConfiguration) - return coreCommonCommands.Exec(buildPublishCmd) -} - -func (cc *CiSetupCommand) xrayConfigPhase() (err error) { - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return err - } - xrayManager, err := CreateXrayServiceManager(serviceDetails) - if err != nil { - return err - } - // Index the build. - buildsToIndex := []string{cc.data.BuildName} - err = xrayManager.AddBuildsToIndexing(buildsToIndex) - if err != nil { - return err - } - // Create new default policy. - policyParams := xrayutils.NewPolicyParams() - policyParams.Name = "ci-pipeline-security-policy" - policyParams.Type = xrayutils.Security - policyParams.Description = "Basic Security policy." - policyParams.Rules = []xrayutils.PolicyRule{ - { - Name: "min-severity-rule", - Criteria: *xrayutils.CreateSeverityPolicyCriteria(xrayutils.Critical), - Priority: 1, - }, - } - err = xrayManager.CreatePolicy(policyParams) - if err != nil { - // In case the error is from type PolicyAlreadyExistsError, we should continue with the regular flow. - if paeErr, ok := err.(*xrayservices.PolicyAlreadyExistsError); !ok { - return err - } else { - log.Debug(paeErr.InnerError) - } - } - // Create new default watcher. - watchParams := xrayutils.NewWatchParams() - watchParams.Name = "ci-pipeline-watch-all" - watchParams.Description = "CI Pipeline Build Watch" - watchParams.Active = true - watchParams.Builds.Type = xrayutils.WatchBuildAll - watchParams.Policies = []xrayutils.AssignedPolicy{ - { - Name: policyParams.Name, - Type: "security", - }, - } - - err = xrayManager.CreateWatch(watchParams) - if err != nil { - // In case the error is from type WatchAlreadyExistsError, we should continue with the regular flow. - if waeErr, ok := err.(*xrayservices.WatchAlreadyExistsError); !ok { - return err - } else { - log.Debug(waeErr.InnerError) - err = nil - } - } - return -} - -func (cc *CiSetupCommand) artifactoryConfigPhase() (err error) { - err = cc.printDetectedTechs() - if err != nil { - return err - } - // First create repositories for the selected technology. - for tech := range cc.data.DetectedTechnologies { - if coreutils.AskYesNo(fmt.Sprintf("Would you like to use %s to build the code?", tech), true) { - cc.data.BuiltTechnology = &cisetup.TechnologyInfo{Type: tech} - err = cc.interactivelyCreateRepos(tech) - if err != nil { - return - } - cc.getBuildCmd() - return nil - } - } - return errorutils.CheckErrorf("at least one of the supported technologies is expected to be chosen for building") -} - -func (cc *CiSetupCommand) printDetectedTechs() error { - var techs []string - for tech := range cc.data.DetectedTechnologies { - techs = append(techs, string(tech)) - } - if len(techs) == 0 { - return errorutils.CheckErrorf("no supported technology was found in the project") - } - return writeToScreen("The next step is to provide the commands to build your code. It looks like the code is built with " + coreutils.ListToText(techs) + ".\n") -} - -func (cc *CiSetupCommand) getBuildCmd() { - defaultBuildCmd := buildCmdByTech[cc.data.BuiltTechnology.Type] - // Use the cached build command only if the chosen built technology wasn't changed. - if cc.defaultData.BuiltTechnology != nil && cc.defaultData.BuiltTechnology.Type == cc.data.BuiltTechnology.Type { - if cc.defaultData.BuiltTechnology.BuildCmd != "" { - defaultBuildCmd = cc.defaultData.BuiltTechnology.BuildCmd - } - } - // Ask for working build command. - prompt := "Please provide a single-line " + string(cc.data.BuiltTechnology.Type) + " build command." - ioutils.ScanFromConsole(prompt, &cc.data.BuiltTechnology.BuildCmd, defaultBuildCmd) -} - -func getRepoSelectionFromUser(repos *[]services.RepositoryDetails, promptString string) (repo string, err error) { - shouldPromptSelection := len(*repos) > 0 - if shouldPromptSelection { - // Ask if the user would like us to create a new repo or to choose from the existing repositories list - repo, err = promptARepoSelection(repos, promptString) - if err != nil { - return "", err - } - } else { - repo = NewRepository - } - return repo, nil -} - -func handleNewLocalRepository(serviceDetails *utilsConfig.ServerDetails, technologyType coreutils.Technology) (repo string) { - // Create local repository - for { - var newLocalRepo string - ioutils.ScanFromConsole("Repository Name", &newLocalRepo, repoutils.RepoDefaultName[technologyType][repoutils.Local]) - err := CreateLocalRepo(serviceDetails, technologyType, newLocalRepo) - if err != nil { - log.Error(err) - } else { - return newLocalRepo - } - } -} - -func (cc *CiSetupCommand) interactivelyCreateRepos(technologyType coreutils.Technology) (err error) { - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - return err - } - // Get all relevant local to choose from - localRepos, err := GetAllRepos(serviceDetails, repoutils.Local, string(technologyType)) - if err != nil { - return err - } - deployerRepoType := "" - if technologyType == coreutils.Maven { - deployerRepoType = "releases " - } - localRepo, err := getRepoSelectionFromUser(localRepos, fmt.Sprintf("Create or select an Artifactory %sRepository to deploy the build artifacts to", deployerRepoType)) - if err != nil { - return err - } - if localRepo == NewRepository { - localRepo = handleNewLocalRepository(serviceDetails, technologyType) - } - cc.data.BuiltTechnology.LocalReleasesRepo = localRepo - if technologyType == coreutils.Maven { - localRepo, err = getRepoSelectionFromUser(localRepos, "Create or select an Artifactory snapshots Repository to deploy the build artifacts to") - if err != nil { - return err - } - if localRepo == NewRepository { - localRepo = handleNewLocalRepository(serviceDetails, technologyType) - } - } - cc.data.BuiltTechnology.LocalSnapshotsRepo = localRepo - // Get all relevant remotes to choose from - remoteRepos, err := GetAllRepos(serviceDetails, repoutils.Remote, string(technologyType)) - if err != nil { - return err - } - remoteRepo, err := getRepoSelectionFromUser(remoteRepos, "Create or select an Artifactory remote repository to resolve (download) 3rd party dependencies for your build") - if err != nil { - return err - } - // The user choose to create a new remote repo - if remoteRepo == NewRepository { - for { - var repoName, repoUrl string - ioutils.ScanFromConsole("Repository Name", &repoName, repoutils.RepoDefaultName[technologyType][repoutils.Remote]) - ioutils.ScanFromConsole("Repository URL", &repoUrl, repoutils.RepoDefaultName[technologyType][repoutils.RemoteUrl]) - err = CreateRemoteRepo(serviceDetails, technologyType, repoName, repoUrl) - if err != nil { - log.Error(err) - } else { - remoteRepo = repoName - for { - // Create a new virtual repository as well - ioutils.ScanFromConsole(fmt.Sprintf("Choose a name for a new virtual repository which will include %q remote repo", remoteRepo), - &repoName, repoutils.RepoDefaultName[technologyType][repoutils.Virtual]) - err = CreateVirtualRepo(serviceDetails, technologyType, repoName, remoteRepo) - if err != nil { - log.Error(err) - } else { - // We created both remote and virtual repositories successfully - cc.data.BuiltTechnology.VirtualRepo = repoName - return - } - } - } - } - } - // Else, the user choose an existing remote repo - virtualRepos, err := GetAllRepos(serviceDetails, repoutils.Virtual, string(technologyType)) - chosenVirtualRepo := "" - if err != nil { - return err - } - for _, repo := range *virtualRepos { - virtualRepo, err := GetVirtualRepo(serviceDetails, repo.Key) - if err != nil { - return err - } - if contains(virtualRepo.Repositories, remoteRepo) { - chosenVirtualRepo = repo.Key - } - } - if chosenVirtualRepo == "" { - virtualRepoName := repoutils.RepoDefaultName[technologyType][repoutils.Virtual] - for i := 1; i < maxRepoCreationAttempts; i++ { - _, err := GetVirtualRepo(serviceDetails, virtualRepoName) - if err == nil { - err = CreateVirtualRepo(serviceDetails, technologyType, virtualRepoName, remoteRepo) - if err != nil { - return err - } - break - } else { - virtualRepoName = fmt.Sprintf("%s-%d", virtualRepoName, i) - } - } - if err != nil { - return err - } - chosenVirtualRepo = virtualRepoName - } - cc.data.BuiltTechnology.VirtualRepo = chosenVirtualRepo - return -} - -func promptARepoSelection(repoDetails *[]services.RepositoryDetails, promptMsg string) (selectedRepoName string, err error) { - - selectableItems := []ioutils.PromptItem{{Option: NewRepository, TargetValue: &selectedRepoName}} - for _, repo := range *repoDetails { - selectableItems = append(selectableItems, ioutils.PromptItem{Option: repo.Key, TargetValue: &selectedRepoName, DefaultValue: repo.Url}) - } - log.Output(promptMsg) - err = ioutils.SelectString(selectableItems, "", true, func(item ioutils.PromptItem) { - *item.TargetValue = item.Option - }) - return -} - -func promptGitProviderSelection() (selected string, err error) { - gitProviders := []cisetup.GitProvider{ - cisetup.Github, - cisetup.GithubEnterprise, - cisetup.Bitbucket, - cisetup.BitbucketServer, - cisetup.Gitlab, - } - - var selectableItems []ioutils.PromptItem - for _, provider := range gitProviders { - selectableItems = append(selectableItems, ioutils.PromptItem{Option: string(provider), TargetValue: &selected}) - } - log.Output("Choose your project Git provider:") - err = ioutils.SelectString(selectableItems, "", false, func(item ioutils.PromptItem) { - *item.TargetValue = item.Option - }) - return -} - -func promptCiProviderSelection() (selected string, err error) { - ciTypes := []cisetup.CiType{ - cisetup.Pipelines, - cisetup.Jenkins, - cisetup.GithubActions, - } - - var selectableItems []ioutils.PromptItem - for _, ci := range ciTypes { - selectableItems = append(selectableItems, ioutils.PromptItem{Option: string(ci), TargetValue: &selected}) - } - log.Output("Select a CI provider:") - err = ioutils.SelectString(selectableItems, "", false, func(item ioutils.PromptItem) { - *item.TargetValue = item.Option - }) - return -} - -func (cc *CiSetupCommand) prepareVcsData() (err error) { - cc.data.LocalDirPath = DefaultWorkspace - for i := 1; i < maxRepoCreationAttempts; i++ { - err = fileutils.CreateDirIfNotExist(cc.data.LocalDirPath) - if err != nil { - return err - } - dirEmpty, err := fileutils.IsDirEmpty(cc.data.LocalDirPath) - if err != nil { - return err - } - if dirEmpty { - break - } else { - cc.data.LocalDirPath = fmt.Sprintf("%s-%d", DefaultWorkspace, i) - } - } - if err != nil { - return - } - err = cc.cloneProject() - if err != nil { - return - } - err = cc.detectTechnologies() - return -} - -func (cc *CiSetupCommand) cloneProject() (err error) { - // Create the desired path if necessary - err = os.MkdirAll(cc.data.LocalDirPath, os.ModePerm) - if err != nil { - return errorutils.CheckError(err) - } - cloneOption := &git.CloneOptions{ - URL: cc.data.VcsCredentials.Url, - Auth: createCredentials(&cc.data.VcsCredentials), - // Enable git submodules clone if their any. - RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, - } - if cc.data.GitBranch != "" { - cloneOption.ReferenceName = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", cc.data.GitBranch)) - } - err = cc.extractRepositoryName() - if err != nil { - return - } - // Clone the given repository to the given directory from the given branch - log.Info(fmt.Sprintf("Cloning project %q from: %q into: %q", cc.data.RepositoryName, cc.data.VcsCredentials.Url, cc.data.LocalDirPath)) - cloneRepo, err := git.PlainClone(cc.data.LocalDirPath, false, cloneOption) - if err != nil { - return errorutils.CheckError(err) - } - if cc.data.GitBranch == "" { - err = cc.extractDefaultBranchName(cloneRepo) - } - return errorutils.CheckError(err) -} - -func (cc *CiSetupCommand) stageCiConfigFile(ciFileName string) error { - log.Info(fmt.Sprintf("Staging %s for git commit...", ciFileName)) - repo, err := git.PlainOpen(cc.data.LocalDirPath) - if err != nil { - return errorutils.CheckError(err) - } - worktree, err := repo.Worktree() - if err != nil { - return errorutils.CheckError(err) - } - _, err = worktree.Add(ciFileName) - return errorutils.CheckError(err) -} - -func (cc *CiSetupCommand) extractRepositoryName() error { - vcsUrl := cc.data.VcsCredentials.Url - if vcsUrl == "" { - return errorutils.CheckErrorf("vcs URL should not be empty") - } - // Trim trailing "/" if one exists - vcsUrl = strings.TrimSuffix(vcsUrl, "/") - cc.data.VcsCredentials.Url = vcsUrl - - // Split vcs url. - splitUrl := strings.Split(vcsUrl, "/") - if len(splitUrl) < 3 { - return errorutils.CheckErrorf("unexpected URL. URL is expected to contain the git provider URL, domain and repository names") - } - cc.data.RepositoryName = strings.TrimSuffix(splitUrl[len(splitUrl)-1], ".git") - cc.data.ProjectDomain = splitUrl[len(splitUrl)-2] - cc.data.VcsBaseUrl = strings.Join(splitUrl[:len(splitUrl)-2], "/") - return nil -} - -func (cc *CiSetupCommand) extractDefaultBranchName(repo *git.Repository) error { - headRef, err := repo.Head() - if err != nil { - return err - } - defaultBranch := path.Base(string(headRef.Name())) // refs/heads/branchName > branchName - cc.data.GitBranch = defaultBranch - return nil -} - -func (cc *CiSetupCommand) detectTechnologies() (err error) { - cc.data.DetectedTechnologies, err = coreutils.DetectTechnologies(cc.data.LocalDirPath, true, true) - return -} - -func createCredentials(serviceDetails *cisetup.VcsServerDetails) (auth transport.AuthMethod) { - var password, username string - if serviceDetails.AccessToken != "" { - password = serviceDetails.AccessToken - // Authentication fails if the username string is empty. This can be anything except an empty string... - username = "user" - } else { - password = serviceDetails.Password - username = serviceDetails.User - } - return &http.BasicAuth{Username: username, Password: password} -} - -func (cc *CiSetupCommand) gitPhase() (err error) { - for { - gitProvider, err := promptGitProviderSelection() - if err != nil { - log.Error(err) - continue - } - cc.data.GitProvider = cisetup.GitProvider(gitProvider) - ioutils.ScanFromConsole("Git project URL", &cc.data.VcsCredentials.Url, cc.defaultData.VcsCredentials.Url) - ioutils.ScanFromConsole("Git username", &cc.data.VcsCredentials.User, cc.defaultData.VcsCredentials.User) - err = writeToScreen("Git access token (requires admin permissions): ") - if err != nil { - return err - } - //nolint:unconvert - byteToken, err := term.ReadPassword(int(syscall.Stdin)) - if err != nil { - log.Error(err) - continue - } - // New-line required after the access token input: - log.Output() - cc.data.VcsCredentials.AccessToken = string(byteToken) - cc.defaultData.GitBranch = "" - gitBranchCaption := "Git branch" - if cc.defaultData.GitBranch == "" { - gitBranchCaption += " (Leave blank for default)" - } - ioutils.ScanFromConsole(gitBranchCaption, &cc.data.GitBranch, cc.defaultData.GitBranch) - err = cc.prepareVcsData() - if err != nil { - log.Error(err) - } else { - return nil - } - } -} - -func (cc *CiSetupCommand) ciProviderPhase() { - for { - ciType, err := promptCiProviderSelection() - if err != nil { - log.Error(err) - continue - } - if ciType == cisetup.Pipelines { - // validate that pipelines is available. - serviceDetails, err := utilsConfig.GetSpecificConfig(cisetup.ConfigServerId, false, false) - if err != nil { - log.Error(err) - continue - } - pipelinesDetails := *serviceDetails - pipelinesDetails.AccessToken = "" - pipelinesDetails.User = "" - pipelinesDetails.Password = "" - - pAuth, err := pipelinesDetails.CreatePipelinesAuthConfig() - if err != nil { - log.Error(err) - continue - } - serviceConfig, err := clientConfig.NewConfigBuilder(). - SetServiceDetails(pAuth). - SetDryRun(false). - Build() - if err != nil { - log.Error(err) - continue - } - pipelinesMgr, err := pipelines.New(serviceConfig) - if err != nil { - log.Error(err) - continue - } - _, err = pipelinesMgr.GetSystemInfo() - if err == nil { - cc.data.CiType = cisetup.CiType(ciType) - return - } - log.Error(err) - if _, ok := err.(*pipelinesservices.PipelinesNotAvailableError); ok { - err = inactivePipelinesNote(pipelinesDetails.PipelinesUrl) - if err != nil { - log.Error(err) - } - } - } else { // The user doesn't choose Pipelines. - cc.data.CiType = cisetup.CiType(ciType) - return - } - } -} diff --git a/general/cisetup/cisetup_test.go b/general/cisetup/cisetup_test.go deleted file mode 100644 index 28e430dda..000000000 --- a/general/cisetup/cisetup_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package cisetup - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestExtractRepositoryName(t *testing.T) { - tests := []struct { - name string - repoUrl string - expectedProjectName string - expectedProjectDomain string - expectedBaseUrl string - errorExpected bool - }{ - {"simpleURL", "https://github.com/jfrog/jfrog-cli", "jfrog-cli", "jfrog", "https://github.com", false}, - {"URLWithTrailingDash", "https://github.com/jfrog/jfrog-cli/", "jfrog-cli", "jfrog", "https://github.com", false}, - {"URLWithGitExtension", "https://github.com/jfrog/jfrog-cli.git", "jfrog-cli", "jfrog", "https://github.com", false}, - {"noProtocol", "localhost:1234/jfrog/jfrog-cli.git", "jfrog-cli", "jfrog", "localhost:1234", false}, - {"emptyURL", "", "", "", "", true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cc := &CiSetupCommand{} - err := cc.prepareConfigurationData() - if err != nil { - assert.NoError(t, err) - return - } - cc.data.VcsCredentials.Url = test.repoUrl - - err = cc.extractRepositoryName() - if test.errorExpected { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, test.expectedProjectName, cc.data.RepositoryName) - assert.Equal(t, test.expectedProjectDomain, cc.data.ProjectDomain) - assert.Equal(t, test.expectedBaseUrl, cc.data.VcsBaseUrl) - } - }) - } -} diff --git a/general/cisetup/utils.go b/general/cisetup/utils.go deleted file mode 100644 index 94e025169..000000000 --- a/general/cisetup/utils.go +++ /dev/null @@ -1,102 +0,0 @@ -package cisetup - -import ( - artUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" - utilsconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/artifactory/services" - "github.com/jfrog/jfrog-client-go/config" - "github.com/jfrog/jfrog-client-go/xray" -) - -const ( - NewRepository = "[Create new repository]" - - // Build commands defaults - mavenDefaultBuildCmd = "mvn clean install" - gradleDefaultBuildCmd = "gradle clean artifactoryPublish" - npmDefaultBuildCmd = "npm install" -) - -var buildCmdByTech = map[coreutils.Technology]string{ - coreutils.Maven: mavenDefaultBuildCmd, - coreutils.Gradle: gradleDefaultBuildCmd, - coreutils.Npm: npmDefaultBuildCmd, -} - -func CreateXrayServiceManager(serviceDetails *utilsconfig.ServerDetails) (*xray.XrayServicesManager, error) { - xrayDetails, err := serviceDetails.CreateXrayAuthConfig() - if err != nil { - return nil, err - } - serviceConfig, err := config.NewConfigBuilder(). - SetServiceDetails(xrayDetails). - Build() - if err != nil { - return nil, err - } - return xray.New(serviceConfig) -} - -func GetAllRepos(serviceDetails *utilsconfig.ServerDetails, repoType, packageType string) (*[]services.RepositoryDetails, error) { - servicesManager, err := artUtils.CreateServiceManager(serviceDetails, -1, 0, false) - if err != nil { - return nil, err - } - filterParams := services.RepositoriesFilterParams{RepoType: repoType, PackageType: packageType} - return servicesManager.GetAllRepositoriesFiltered(filterParams) -} - -func GetVirtualRepo(serviceDetails *utilsconfig.ServerDetails, repoKey string) (*services.VirtualRepositoryBaseParams, error) { - servicesManager, err := artUtils.CreateServiceManager(serviceDetails, -1, 0, false) - if err != nil { - return nil, err - } - virtualRepoDetails := services.VirtualRepositoryBaseParams{} - err = servicesManager.GetRepository(repoKey, &virtualRepoDetails) - return &virtualRepoDetails, err -} - -func CreateLocalRepo(serviceDetails *utilsconfig.ServerDetails, technologyType coreutils.Technology, repoName string) error { - servicesManager, err := artUtils.CreateServiceManager(serviceDetails, -1, 0, false) - if err != nil { - return err - } - params := services.NewLocalRepositoryBaseParams() - params.PackageType = string(technologyType) - params.Key = repoName - return servicesManager.CreateLocalRepositoryWithParams(params) -} - -func CreateRemoteRepo(serviceDetails *utilsconfig.ServerDetails, technologyType coreutils.Technology, repoName, remoteUrl string) error { - servicesManager, err := artUtils.CreateServiceManager(serviceDetails, -1, 0, false) - if err != nil { - return err - } - params := services.NewRemoteRepositoryBaseParams() - params.PackageType = string(technologyType) - params.Key = repoName - params.Url = remoteUrl - return servicesManager.CreateRemoteRepositoryWithParams(params) -} - -func CreateVirtualRepo(serviceDetails *utilsconfig.ServerDetails, technologyType coreutils.Technology, repoName string, repositories ...string) error { - servicesManager, err := artUtils.CreateServiceManager(serviceDetails, -1, 0, false) - if err != nil { - return err - } - params := services.NewVirtualRepositoryBaseParams() - params.PackageType = string(technologyType) - params.Key = repoName - params.Repositories = repositories - return servicesManager.CreateVirtualRepositoryWithParams(params) -} - -func contains(arr []string, str string) bool { - for _, element := range arr { - if element == str { - return true - } - } - return false -} diff --git a/general/project/cli.go b/general/project/cli.go deleted file mode 100644 index 27a2bc54a..000000000 --- a/general/project/cli.go +++ /dev/null @@ -1,52 +0,0 @@ -package project - -import ( - "os" - "path/filepath" - - "github.com/jfrog/jfrog-cli-core/v2/common/commands" - corecommon "github.com/jfrog/jfrog-cli-core/v2/docs/common" - projectlogic "github.com/jfrog/jfrog-cli-core/v2/general/project" - projectinit "github.com/jfrog/jfrog-cli/docs/general/project/init" - clientutils "github.com/jfrog/jfrog-client-go/utils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/urfave/cli" - - "github.com/jfrog/jfrog-cli/utils/cliutils" -) - -func GetCommands() []cli.Command { - return cliutils.GetSortedCommands(cli.CommandsByName{ - { - Name: "init", - Hidden: true, - Usage: projectinit.GetDescription(), - Flags: cliutils.GetCommandFlags(cliutils.InitProject), - HelpName: corecommon.CreateUsage("project init", projectinit.GetDescription(), projectinit.Usage), - BashComplete: corecommon.CreateBashCompletionFunc(), - Action: initProject, - }, - }) -} - -func initProject(c *cli.Context) error { - if c.NArg() > 1 { - return cliutils.WrongNumberOfArgumentsHandler(c) - } - // The default project path is the current directory - path, err := os.Getwd() - if errorutils.CheckError(err) != nil { - return err - } - if c.NArg() == 1 { - path = c.Args().Get(0) - path, err = filepath.Abs(path) - if errorutils.CheckError(err) != nil { - return err - } - } - path = clientutils.AddTrailingSlashIfNeeded(path) - initCmd := projectlogic.NewProjectInitCommand() - initCmd.SetProjectPath(path).SetServerId(c.String("server-id")) - return commands.Exec(initCmd) -} diff --git a/go.mod b/go.mod index d144b6039..8631a2113 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,10 @@ go 1.22.3 require ( github.com/agnivade/levenshtein v1.1.1 github.com/buger/jsonparser v1.1.1 - github.com/go-git/go-git/v5 v5.12.0 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jfrog/archiver/v3 v3.6.0 github.com/jfrog/build-info-go v1.9.27 - github.com/jfrog/gofrog v1.7.1 + github.com/jfrog/gofrog v1.7.2 github.com/jfrog/jfrog-cli-core/v2 v2.53.0 github.com/jfrog/jfrog-cli-platform-services v1.3.0 github.com/jfrog/jfrog-cli-security v1.2.0 @@ -20,7 +19,6 @@ require ( github.com/urfave/cli v1.22.15 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/term v0.20.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -56,6 +54,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-git/v5 v5.12.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -127,6 +126,7 @@ require ( golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect @@ -137,7 +137,9 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240505164307-d12abb9f140e +replace github.com/jfrog/jfrog-cli-core/v2 => github.com/eyalbe4/jfrog-cli-core/v2 v2.53.1-0.20240603040428-a33e0e7a9a03 + +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 // replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.1.1-0.20240522121307-3e9fe2dc5e81 diff --git a/go.sum b/go.sum index 702f9df19..c6879c204 100644 --- a/go.sum +++ b/go.sum @@ -84,6 +84,8 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcej github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/eyalbe4/jfrog-cli-core/v2 v2.53.1-0.20240603040428-a33e0e7a9a03 h1:pay/ucXMV7Gjt0ECeqQ9WCWpzYHEwi1nW5i5GvmZ/bA= +github.com/eyalbe4/jfrog-cli-core/v2 v2.53.1-0.20240603040428-a33e0e7a9a03/go.mod h1:uQueYasazFM4PuIsroKu6zXzkEjlrnuRiO5eVHUOj1A= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/forPelevin/gomoji v1.2.0 h1:9k4WVSSkE1ARO/BWywxgEUBvR/jMnao6EZzrql5nxJ8= @@ -141,18 +143,16 @@ github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= github.com/jfrog/build-info-go v1.9.27 h1:7RWJcajqtNNbGHuYkgOLUIG7mmRKF0yxC7mvYAbdVlU= github.com/jfrog/build-info-go v1.9.27/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= -github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= -github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= +github.com/jfrog/gofrog v1.7.2 h1:VkAaA/9tmbw27IqgUOmaZWnO6ATUqL3vRzDnsROKATw= +github.com/jfrog/gofrog v1.7.2/go.mod h1:WJFk88SR9Sr9mKl1bQBig7DmSdXiBGKV3WhL9O6jL9w= github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY= github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= -github.com/jfrog/jfrog-cli-core/v2 v2.53.0 h1:qdZ1Svb1hGyRx2QviJtarhcA8eet8QtYU054nKzlhDg= -github.com/jfrog/jfrog-cli-core/v2 v2.53.0/go.mod h1:l101ZcbHy/FLieCx1xDtjONgkqsoLDNaqVT7b4KJ5OQ= github.com/jfrog/jfrog-cli-platform-services v1.3.0 h1:IblSDZFBjL7WLRi37Ni2DmHrXJJ6ysSMxx7t41AvyDA= github.com/jfrog/jfrog-cli-platform-services v1.3.0/go.mod h1:Ky4SDXuMeaiNP/5zMT1YSzIuXG+cNYYOl8BaEA7Awbc= github.com/jfrog/jfrog-cli-security v1.2.0 h1:4lNl/bbU8qhkpnpMQqZtPlniwtM9rJXDYNEm7VsLRKs= github.com/jfrog/jfrog-cli-security v1.2.0/go.mod h1:IbP3MiDz5gXXc2+oXSqV688uEhLrtxHapoJ14oYTV20= -github.com/jfrog/jfrog-client-go v1.40.2 h1:zdCWPPT11r0bMGnAXGhZPb3RrIINhiTFCceQABhguZ4= -github.com/jfrog/jfrog-client-go v1.40.2/go.mod h1:m3hIn12eFWk5nJH1swPRtFrjXbiiCscOpX+v/vCdmNI= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 h1:ERLE/L7YPr6aCUTeAnE8SXU5VOZHd5/XK16rM1TEpts= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04/go.mod h1:37RR4pYgXZM4w7tywyfRu8t2wagt0qf5wBtpDILWBsk= github.com/jszwec/csvutil v1.10.0 h1:upMDUxhQKqZ5ZDCs/wy+8Kib8rZR8I8lOR34yJkdqhI= github.com/jszwec/csvutil v1.10.0/go.mod h1:/E4ONrmGkwmWsk9ae9jpXnv9QT8pLHEPcCirMFhxG9I= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= diff --git a/main.go b/main.go index a487e8a37..fde318120 100644 --- a/main.go +++ b/main.go @@ -28,13 +28,10 @@ import ( "github.com/jfrog/jfrog-cli/distribution" "github.com/jfrog/jfrog-cli/docs/common" aiDocs "github.com/jfrog/jfrog-cli/docs/general/ai" - "github.com/jfrog/jfrog-cli/docs/general/cisetup" loginDocs "github.com/jfrog/jfrog-cli/docs/general/login" tokenDocs "github.com/jfrog/jfrog-cli/docs/general/token" - 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/general/token" "github.com/jfrog/jfrog-cli/lifecycle" "github.com/jfrog/jfrog-cli/missioncontrol" @@ -254,25 +251,6 @@ func getCommands() ([]cli.Command, error) { Subcommands: config.GetCommands(), Category: commandNamespacesCategory, }, - { - Name: cliutils.CmdProject, - Hidden: true, - Usage: "Project commands.", - Subcommands: project.GetCommands(), - Category: otherCategory, - }, - { - Name: "ci-setup", - Hidden: true, - Usage: cisetup.GetDescription(), - HelpName: corecommon.CreateUsage("ci-setup", cisetup.GetDescription(), cisetup.Usage), - ArgsUsage: common.CreateEnvVars(), - BashComplete: corecommon.CreateBashCompletionFunc(), - Category: otherCategory, - Action: func(c *cli.Context) error { - return cisetupcommand.RunCiSetupCmd() - }, - }, { Name: "setup", Hidden: true, From 3131792865b84ca25f34eba8665cc32fac58131b Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Mon, 3 Jun 2024 12:14:40 +0300 Subject: [PATCH 2/3] UX improvement for how command (#2561) --- general/ai/cli.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/general/ai/cli.go b/general/ai/cli.go index e8afa8cba..7e97d9bab 100644 --- a/general/ai/cli.go +++ b/general/ai/cli.go @@ -47,12 +47,12 @@ func HowCmd(c *cli.Context) error { return cliutils.WrongNumberOfArgumentsHandler(c) } log.Output(coreutils.PrintTitle("This AI-based interface converts your natural language inputs into fully functional JFrog CLI commands.\n" + - "NOTE: This is a beta version and it supports mostly Artifactory and Xray commands.\n")) + "NOTE: This is an experimental version and it supports mostly Artifactory and Xray commands.\n")) for { var question string scanner := bufio.NewScanner(os.Stdin) - fmt.Print("šŸø Your request: ") + fmt.Print("šŸø Your request:\n ") for { // Ask the user for a question scanner.Scan() @@ -62,13 +62,15 @@ func HowCmd(c *cli.Context) error { break } } + fmt.Print("\nšŸ¤– Generated command:\n ") questionBody := QuestionBody{Question: question} llmAnswer, err := askQuestion(questionBody) if err != nil { return err } + log.Output(coreutils.PrintLink(llmAnswer) + "\n") - log.Output("šŸ¤– Generated command: " + coreutils.PrintLink(llmAnswer) + "\n") + // Ask the user for feedback feedback := FeedbackBody{QuestionBody: questionBody, LlmAnswer: llmAnswer} feedback.getUserFeedback() if err = sendFeedback(feedback); err != nil { From 033ebb1b0f1d92ea56555bf4789ad04f928505e3 Mon Sep 17 00:00:00 2001 From: Yahav Itschak Date: Tue, 4 Jun 2024 17:51:14 +0300 Subject: [PATCH 3/3] Fix Maven config freeze (#2564) --- go.mod | 6 ++++++ go.sum | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 8631a2113..db72a1080 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,12 @@ module github.com/jfrog/jfrog-cli go 1.22.3 +// Should not be updated to 0.2.6 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372) +replace github.com/c-bata/go-prompt => github.com/c-bata/go-prompt v0.2.5 + +// Should not be updated to 0.2.0-beta.2 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372) +replace github.com/pkg/term => github.com/pkg/term v1.1.0 + require ( github.com/agnivade/levenshtein v1.1.1 github.com/buger/jsonparser v1.1.1 diff --git a/go.sum b/go.sum index c6879c204..958ff202d 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1l github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= -github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= +github.com/c-bata/go-prompt v0.2.5 h1:3zg6PecEywxNn0xiqcXHD96fkbxghD+gdB2tbsYfl+Y= +github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -232,8 +232,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmd github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= -github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= +github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= +github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=