@@ -10,21 +10,50 @@ import (
1010 "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/repository"
1111 commandsutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils"
1212 "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
13+ "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/container"
1314 "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/npm"
1415 "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/yarn"
1516 "github.com/jfrog/jfrog-cli-core/v2/common/project"
1617 "github.com/jfrog/jfrog-cli-core/v2/utils/config"
18+ "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
1719 "github.com/jfrog/jfrog-client-go/artifactory/services"
1820 "github.com/jfrog/jfrog-client-go/utils/errorutils"
1921 "github.com/jfrog/jfrog-client-go/utils/log"
22+ "golang.org/x/exp/maps"
23+ "net/url"
24+ "slices"
2025)
2126
27+ // packageManagerToRepositoryPackageType maps project types to corresponding Artifactory repository package types.
28+ var packageManagerToRepositoryPackageType = map [project.ProjectType ]string {
29+ // Npm package managers
30+ project .Npm : repository .Npm ,
31+ project .Yarn : repository .Npm ,
32+
33+ // Python (pypi) package managers
34+ project .Pip : repository .Pypi ,
35+ project .Pipenv : repository .Pypi ,
36+ project .Poetry : repository .Pypi ,
37+
38+ // Nuget package managers
39+ project .Nuget : repository .Nuget ,
40+ project .Dotnet : repository .Nuget ,
41+
42+ // Docker package managers
43+ project .Docker : repository .Docker ,
44+ project .Podman : repository .Docker ,
45+
46+ project .Go : repository .Go ,
47+ }
48+
2249// PackageManagerLoginCommand configures registries and authentication for various package manager (npm, Yarn, Pip, Pipenv, Poetry, Go)
2350type PackageManagerLoginCommand struct {
2451 // packageManager represents the type of package manager (e.g., NPM, Yarn).
2552 packageManager project.ProjectType
2653 // repoName is the name of the repository used for configuration.
2754 repoName string
55+ // projectKey is the JFrog Project key in JFrog Platform.
56+ projectKey string
2857 // serverDetails contains Artifactory server configuration.
2958 serverDetails * config.ServerDetails
3059 // commandName specifies the command for this instance.
@@ -40,20 +69,19 @@ func NewPackageManagerLoginCommand(packageManager project.ProjectType) *PackageM
4069 }
4170}
4271
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- }
72+ // GetSupportedPackageManagersList returns a sorted list of supported package managers.
73+ func GetSupportedPackageManagersList () []project.ProjectType {
74+ allSupportedPackageManagers := maps .Keys (packageManagerToRepositoryPackageType )
75+ // Sort keys based on their natural enum order
76+ slices .SortFunc (allSupportedPackageManagers , func (a , b project.ProjectType ) int {
77+ return int (a ) - int (b )
78+ })
79+ return allSupportedPackageManagers
80+ }
81+
82+ func IsSupportedPackageManager (packageManager project.ProjectType ) bool {
83+ _ , exists := packageManagerToRepositoryPackageType [packageManager ]
84+ return exists
5785}
5886
5987// CommandName returns the name of the login command.
@@ -72,8 +100,24 @@ func (pmlc *PackageManagerLoginCommand) ServerDetails() (*config.ServerDetails,
72100 return pmlc .serverDetails , nil
73101}
74102
103+ // SetRepoName assigns the repository name to the command.
104+ func (pmlc * PackageManagerLoginCommand ) SetRepoName (repoName string ) * PackageManagerLoginCommand {
105+ pmlc .repoName = repoName
106+ return pmlc
107+ }
108+
109+ // SetProjectKey assigns the project key to the command.
110+ func (pmlc * PackageManagerLoginCommand ) SetProjectKey (projectKey string ) * PackageManagerLoginCommand {
111+ pmlc .projectKey = projectKey
112+ return pmlc
113+ }
114+
75115// Run executes the configuration method corresponding to the package manager specified for the command.
76116func (pmlc * PackageManagerLoginCommand ) Run () (err error ) {
117+ if ! IsSupportedPackageManager (pmlc .packageManager ) {
118+ return errorutils .CheckErrorf ("unsupported package manager: %s" , pmlc .packageManager )
119+ }
120+
77121 if pmlc .repoName == "" {
78122 // Prompt the user to select a virtual repository that matches the package manager.
79123 if err = pmlc .promptUserToSelectRepository (); err != nil {
@@ -95,27 +139,25 @@ func (pmlc *PackageManagerLoginCommand) Run() (err error) {
95139 err = pmlc .configureGo ()
96140 case project .Nuget , project .Dotnet :
97141 err = pmlc .configureDotnetNuget ()
142+ case project .Docker , project .Podman :
143+ err = pmlc .configureContainer ()
98144 default :
99145 err = errorutils .CheckErrorf ("unsupported package manager: %s" , pmlc .packageManager )
100146 }
101147 if err != nil {
102148 return fmt .Errorf ("failed to configure %s: %w" , pmlc .packageManager .String (), err )
103149 }
104150
105- log .Info (fmt .Sprintf ("Successfully configured %s to use JFrog Artifactory repository '%s'." , pmlc .packageManager .String (), pmlc .repoName ))
151+ log .Output (fmt .Sprintf ("Successfully configured %s to use JFrog Artifactory repository '%s'." , coreutils . PrintBoldTitle ( pmlc .packageManager .String ()), coreutils . PrintBoldTitle ( pmlc .repoName ) ))
106152 return nil
107153}
108154
109155// 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- }
156+ func (pmlc * PackageManagerLoginCommand ) promptUserToSelectRepository () (err error ) {
116157 repoFilterParams := services.RepositoriesFilterParams {
117158 RepoType : utils .Virtual .String (),
118- PackageType : packageType ,
159+ PackageType : packageManagerToRepositoryPackageType [pmlc .packageManager ],
160+ ProjectKey : pmlc .projectKey ,
119161 }
120162
121163 // Prompt for repository selection based on filter parameters.
@@ -239,3 +281,36 @@ func (pmlc *PackageManagerLoginCommand) configureDotnetNuget() error {
239281 // Add the repository as a source in the NuGet configuration with credentials for authentication.
240282 return dotnet .AddSourceToNugetConfig (toolchainType , sourceUrl , user , password )
241283}
284+
285+ // configureContainer configures container managers like Docker or Podman to authenticate with JFrog Artifactory.
286+ // It performs a login using the container manager's CLI command.
287+ //
288+ // For Docker:
289+ //
290+ // echo <password> | docker login <artifactory-url-without-scheme> -u <username> --password-stdin
291+ //
292+ // For Podman:
293+ //
294+ // echo <password> | podman login <artifactory-url-without-scheme> -u <username> --password-stdin
295+ func (pmlc * PackageManagerLoginCommand ) configureContainer () error {
296+ var containerManagerType container.ContainerManagerType
297+ switch pmlc .packageManager {
298+ case project .Docker :
299+ containerManagerType = container .DockerClient
300+ case project .Podman :
301+ containerManagerType = container .Podman
302+ default :
303+ return errorutils .CheckErrorf ("unsupported container manager: %s" , pmlc .packageManager )
304+ }
305+ // Parse the URL to remove the scheme (https:// or http://)
306+ parsedPlatformURL , err := url .Parse (pmlc .serverDetails .GetUrl ())
307+ if err != nil {
308+ return err
309+ }
310+ urlWithoutScheme := parsedPlatformURL .Host + parsedPlatformURL .Path
311+ return container .ContainerManagerLogin (
312+ urlWithoutScheme ,
313+ & container.ContainerManagerLoginConfig {ServerDetails : pmlc .serverDetails },
314+ containerManagerType ,
315+ )
316+ }
0 commit comments