|
| 1 | +package packagemanagerlogin |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + bidotnet "github.com/jfrog/build-info-go/build/utils/dotnet" |
| 6 | + biutils "github.com/jfrog/build-info-go/utils" |
| 7 | + "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/dotnet" |
| 8 | + gocommands "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/golang" |
| 9 | + pythoncommands "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/python" |
| 10 | + "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/repository" |
| 11 | + commandsutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" |
| 12 | + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" |
| 13 | + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/npm" |
| 14 | + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/yarn" |
| 15 | + "github.com/jfrog/jfrog-cli-core/v2/common/project" |
| 16 | + "github.com/jfrog/jfrog-cli-core/v2/utils/config" |
| 17 | + "github.com/jfrog/jfrog-client-go/artifactory/services" |
| 18 | + "github.com/jfrog/jfrog-client-go/utils/errorutils" |
| 19 | + "github.com/jfrog/jfrog-client-go/utils/log" |
| 20 | +) |
| 21 | + |
| 22 | +// PackageManagerLoginCommand configures registries and authentication for various package manager (npm, Yarn, Pip, Pipenv, Poetry, Go) |
| 23 | +type PackageManagerLoginCommand struct { |
| 24 | + // packageManager represents the type of package manager (e.g., NPM, Yarn). |
| 25 | + packageManager project.ProjectType |
| 26 | + // repoName is the name of the repository used for configuration. |
| 27 | + repoName string |
| 28 | + // serverDetails contains Artifactory server configuration. |
| 29 | + serverDetails *config.ServerDetails |
| 30 | + // commandName specifies the command for this instance. |
| 31 | + commandName string |
| 32 | +} |
| 33 | + |
| 34 | +// NewPackageManagerLoginCommand initializes a new PackageManagerLoginCommand for the specified package manager |
| 35 | +// and automatically sets a command name for the login operation. |
| 36 | +func NewPackageManagerLoginCommand(packageManager project.ProjectType) *PackageManagerLoginCommand { |
| 37 | + return &PackageManagerLoginCommand{ |
| 38 | + packageManager: packageManager, |
| 39 | + commandName: packageManager.String() + "_login", |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +// packageManagerToPackageType maps project types to corresponding Artifactory package types (e.g., npm, pypi). |
| 44 | +func packageManagerToPackageType(packageManager project.ProjectType) (string, error) { |
| 45 | + switch packageManager { |
| 46 | + case project.Npm, project.Yarn: |
| 47 | + return repository.Npm, nil |
| 48 | + case project.Pip, project.Pipenv, project.Poetry: |
| 49 | + return repository.Pypi, nil |
| 50 | + case project.Go: |
| 51 | + return repository.Go, nil |
| 52 | + case project.Nuget, project.Dotnet: |
| 53 | + return repository.Nuget, nil |
| 54 | + default: |
| 55 | + return "", errorutils.CheckErrorf("unsupported package manager: %s", packageManager) |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +// CommandName returns the name of the login command. |
| 60 | +func (pmlc *PackageManagerLoginCommand) CommandName() string { |
| 61 | + return pmlc.commandName |
| 62 | +} |
| 63 | + |
| 64 | +// SetServerDetails assigns the server configuration details to the command. |
| 65 | +func (pmlc *PackageManagerLoginCommand) SetServerDetails(serverDetails *config.ServerDetails) *PackageManagerLoginCommand { |
| 66 | + pmlc.serverDetails = serverDetails |
| 67 | + return pmlc |
| 68 | +} |
| 69 | + |
| 70 | +// ServerDetails returns the stored server configuration details. |
| 71 | +func (pmlc *PackageManagerLoginCommand) ServerDetails() (*config.ServerDetails, error) { |
| 72 | + return pmlc.serverDetails, nil |
| 73 | +} |
| 74 | + |
| 75 | +// Run executes the configuration method corresponding to the package manager specified for the command. |
| 76 | +func (pmlc *PackageManagerLoginCommand) Run() (err error) { |
| 77 | + if pmlc.repoName == "" { |
| 78 | + // Prompt the user to select a virtual repository that matches the package manager. |
| 79 | + if err = pmlc.promptUserToSelectRepository(); err != nil { |
| 80 | + return err |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + // Configure the appropriate package manager based on the package manager. |
| 85 | + switch pmlc.packageManager { |
| 86 | + case project.Npm: |
| 87 | + err = pmlc.configureNpm() |
| 88 | + case project.Yarn: |
| 89 | + err = pmlc.configureYarn() |
| 90 | + case project.Pip, project.Pipenv: |
| 91 | + err = pmlc.configurePip() |
| 92 | + case project.Poetry: |
| 93 | + err = pmlc.configurePoetry() |
| 94 | + case project.Go: |
| 95 | + err = pmlc.configureGo() |
| 96 | + case project.Nuget, project.Dotnet: |
| 97 | + err = pmlc.configureDotnetNuget() |
| 98 | + default: |
| 99 | + err = errorutils.CheckErrorf("unsupported package manager: %s", pmlc.packageManager) |
| 100 | + } |
| 101 | + if err != nil { |
| 102 | + return fmt.Errorf("failed to configure %s: %w", pmlc.packageManager.String(), err) |
| 103 | + } |
| 104 | + |
| 105 | + log.Info(fmt.Sprintf("Successfully configured %s to use JFrog Artifactory repository '%s'.", pmlc.packageManager.String(), pmlc.repoName)) |
| 106 | + return nil |
| 107 | +} |
| 108 | + |
| 109 | +// promptUserToSelectRepository prompts the user to select a compatible virtual repository. |
| 110 | +func (pmlc *PackageManagerLoginCommand) promptUserToSelectRepository() error { |
| 111 | + // Map the package manager to its corresponding package type. |
| 112 | + packageType, err := packageManagerToPackageType(pmlc.packageManager) |
| 113 | + if err != nil { |
| 114 | + return err |
| 115 | + } |
| 116 | + repoFilterParams := services.RepositoriesFilterParams{ |
| 117 | + RepoType: utils.Virtual.String(), |
| 118 | + PackageType: packageType, |
| 119 | + } |
| 120 | + |
| 121 | + // Prompt for repository selection based on filter parameters. |
| 122 | + pmlc.repoName, err = utils.SelectRepositoryInteractively(pmlc.serverDetails, repoFilterParams) |
| 123 | + return err |
| 124 | +} |
| 125 | + |
| 126 | +// configurePip sets the global index-url for pip and pipenv to use the Artifactory PyPI repository. |
| 127 | +// Runs the following command: |
| 128 | +// |
| 129 | +// pip config set global.index-url https://<user>:<token>@<your-artifactory-url>/artifactory/api/pypi/<repo-name>/simple |
| 130 | +func (pmlc *PackageManagerLoginCommand) configurePip() error { |
| 131 | + repoWithCredsUrl, err := pythoncommands.GetPypiRepoUrl(pmlc.serverDetails, pmlc.repoName, false) |
| 132 | + if err != nil { |
| 133 | + return err |
| 134 | + } |
| 135 | + return pythoncommands.RunConfigCommand(project.Pip, []string{"set", "global.index-url", repoWithCredsUrl}) |
| 136 | +} |
| 137 | + |
| 138 | +// configurePoetry configures Poetry to use the specified repository and authentication credentials. |
| 139 | +// Runs the following commands: |
| 140 | +// |
| 141 | +// poetry config repositories.<repo-name> https://<your-artifactory-url>/artifactory/api/pypi/<repo-name>/simple |
| 142 | +// poetry config http-basic.<repo-name> <user> <password/token> |
| 143 | +func (pmlc *PackageManagerLoginCommand) configurePoetry() error { |
| 144 | + repoUrl, username, password, err := pythoncommands.GetPypiRepoUrlWithCredentials(pmlc.serverDetails, pmlc.repoName, false) |
| 145 | + if err != nil { |
| 146 | + return err |
| 147 | + } |
| 148 | + return pythoncommands.RunPoetryConfig(repoUrl.String(), username, password, pmlc.repoName) |
| 149 | +} |
| 150 | + |
| 151 | +// configureNpm configures npm to use the Artifactory repository URL and sets authentication. |
| 152 | +// Runs the following commands: |
| 153 | +// |
| 154 | +// npm config set registry https://<your-artifactory-url>/artifactory/api/npm/<repo-name> |
| 155 | +// |
| 156 | +// For token-based auth: |
| 157 | +// |
| 158 | +// npm config set //your-artifactory-url/artifactory/api/npm/<repo-name>/:_authToken "<token>" |
| 159 | +// |
| 160 | +// For basic auth: |
| 161 | +// |
| 162 | +// npm config set //your-artifactory-url/artifactory/api/npm/<repo-name>/:_auth "<base64-encoded-username:password>" |
| 163 | +func (pmlc *PackageManagerLoginCommand) configureNpm() error { |
| 164 | + repoUrl := commandsutils.GetNpmRepositoryUrl(pmlc.repoName, pmlc.serverDetails.ArtifactoryUrl) |
| 165 | + |
| 166 | + if err := npm.ConfigSet(commandsutils.NpmConfigRegistryKey, repoUrl, "npm"); err != nil { |
| 167 | + return err |
| 168 | + } |
| 169 | + |
| 170 | + authKey, authValue := commandsutils.GetNpmAuthKeyValue(pmlc.serverDetails, repoUrl) |
| 171 | + if authKey != "" && authValue != "" { |
| 172 | + return npm.ConfigSet(authKey, authValue, "npm") |
| 173 | + } |
| 174 | + return nil |
| 175 | +} |
| 176 | + |
| 177 | +// configureYarn configures Yarn to use the specified Artifactory repository and sets authentication. |
| 178 | +// Runs the following commands: |
| 179 | +// |
| 180 | +// yarn config set registry https://<your-artifactory-url>/artifactory/api/npm/<repo-name> |
| 181 | +// |
| 182 | +// For token-based auth: |
| 183 | +// |
| 184 | +// yarn config set //your-artifactory-url/artifactory/api/npm/<repo-name>/:_authToken "<token>" |
| 185 | +// |
| 186 | +// For basic auth: |
| 187 | +// |
| 188 | +// yarn config set //your-artifactory-url/artifactory/api/npm/<repo-name>/:_auth "<base64-encoded-username:password>" |
| 189 | +func (pmlc *PackageManagerLoginCommand) configureYarn() error { |
| 190 | + repoUrl := commandsutils.GetNpmRepositoryUrl(pmlc.repoName, pmlc.serverDetails.ArtifactoryUrl) |
| 191 | + |
| 192 | + if err := yarn.ConfigSet(commandsutils.NpmConfigRegistryKey, repoUrl, "yarn", false); err != nil { |
| 193 | + return err |
| 194 | + } |
| 195 | + |
| 196 | + authKey, authValue := commandsutils.GetNpmAuthKeyValue(pmlc.serverDetails, repoUrl) |
| 197 | + if authKey != "" && authValue != "" { |
| 198 | + return yarn.ConfigSet(authKey, authValue, "yarn", false) |
| 199 | + } |
| 200 | + return nil |
| 201 | +} |
| 202 | + |
| 203 | +// configureGo configures Go to use the Artifactory repository for GOPROXY. |
| 204 | +// Runs the following command: |
| 205 | +// |
| 206 | +// go env -w GOPROXY=https://<user>:<token>@<your-artifactory-url>/artifactory/go/<repo-name>,direct |
| 207 | +func (pmlc *PackageManagerLoginCommand) configureGo() error { |
| 208 | + repoWithCredsUrl, err := gocommands.GetArtifactoryRemoteRepoUrl(pmlc.serverDetails, pmlc.repoName, gocommands.GoProxyUrlParams{Direct: true}) |
| 209 | + if err != nil { |
| 210 | + return err |
| 211 | + } |
| 212 | + return biutils.RunGo([]string{"env", "-w", "GOPROXY=" + repoWithCredsUrl}, "") |
| 213 | +} |
| 214 | + |
| 215 | +// configureDotnetNuget configures NuGet or .NET Core to use the specified Artifactory repository with credentials. |
| 216 | +// Adds the repository source to the NuGet configuration file, using appropriate credentials for authentication. |
| 217 | +// The following command is run for dotnet: |
| 218 | +// |
| 219 | +// dotnet nuget add source --name <JFrog-Artifactory> "https://acme.jfrog.io/artifactory/api/nuget/{repository-name}" --username <your-username> --password <your-password> |
| 220 | +// |
| 221 | +// For NuGet: |
| 222 | +// |
| 223 | +// nuget sources add -Name <JFrog-Artifactory> -Source "https://acme.jfrog.io/artifactory/api/nuget/{repository-name}" -Username <your-username> -Password <your-password> |
| 224 | +func (pmlc *PackageManagerLoginCommand) configureDotnetNuget() error { |
| 225 | + // Retrieve repository URL and credentials for NuGet or .NET Core. |
| 226 | + sourceUrl, user, password, err := dotnet.GetSourceDetails(pmlc.serverDetails, pmlc.repoName, false) |
| 227 | + if err != nil { |
| 228 | + return err |
| 229 | + } |
| 230 | + |
| 231 | + // Determine the appropriate toolchain type (NuGet or .NET Core). |
| 232 | + toolchainType := bidotnet.DotnetCore |
| 233 | + if pmlc.packageManager == project.Nuget { |
| 234 | + toolchainType = bidotnet.Nuget |
| 235 | + } |
| 236 | + if err = dotnet.RemoveSourceFromNugetConfigIfExists(toolchainType); err != nil { |
| 237 | + return err |
| 238 | + } |
| 239 | + // Add the repository as a source in the NuGet configuration with credentials for authentication. |
| 240 | + return dotnet.AddSourceToNugetConfig(toolchainType, sourceUrl, user, password) |
| 241 | +} |
0 commit comments