Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions artifactory/commands/setup/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,54 @@ import (
"golang.org/x/exp/maps"
)

// packageManagerToConfigLocation names the configuration each package manager is
// written to, so the command can say what it changed. Every entry is user-level:
// the settings live in the user's home directory, not in the current project, so
// they take effect for every project this user builds. Saying so matters because
// nothing else in the output reveals that the change is not scoped to the
// directory the command was run in.
var packageManagerToConfigLocation = map[project.ProjectType]string{
project.Npm: "your user-level npm configuration (.npmrc)",
project.Pnpm: "your user-level pnpm configuration (.npmrc)",
project.Yarn: "your user-level Yarn configuration (.yarnrc)",
project.Pip: "your user-level pip configuration (pip.conf)",
project.Pipenv: "your user-level pip configuration (pip.conf)",
project.Poetry: "your user-level Poetry configuration",
project.Twine: "your user-level Twine configuration (.pypirc)",
project.UV: "your user-level uv configuration (uv.toml)",
project.Nuget: "your user-level NuGet configuration (NuGet.Config)",
project.Dotnet: "your user-level NuGet configuration (NuGet.Config)",
project.Go: "your Go environment (GOPROXY)",
project.Gradle: "a Gradle init script in your Gradle user home",
project.Maven: "your user-level Maven settings (settings.xml)",
project.Docker: "your Docker credential store",
project.Podman: "your Podman credential store",
project.Helm: "your Helm registry credential store",
}

// containerLoginPackageManagers authenticate to the platform instead of redirecting
// resolution, so the note must not claim that their projects now resolve through
// Artifactory: an unqualified `docker pull alpine` still goes to Docker Hub.
var containerLoginPackageManagers = map[project.ProjectType]bool{
project.Docker: true,
project.Podman: true,
project.Helm: true,
}

// configScopeNote describes what the command changed and how widely it applies, or
// an empty string for a package manager we have nothing accurate to say about.
func configScopeNote(packageManager project.ProjectType) string {
location, ok := packageManagerToConfigLocation[packageManager]
if !ok {
return ""
}
if containerLoginPackageManagers[packageManager] {
return fmt.Sprintf("Credentials were saved to %s for your user account.", location)
}
return fmt.Sprintf("This updated %s, so it applies to every %s project for this user, not only the current directory.",
location, packageManager.String())
}

// packageManagerToRepositoryPackageType maps project types to corresponding Artifactory repository package types.
var packageManagerToRepositoryPackageType = map[project.ProjectType]string{
// Npm package managers
Expand Down Expand Up @@ -195,6 +243,9 @@ func (sc *SetupCommand) Run() (err error) {
repoPrefix = coreutils.PrintBoldTitle(fmt.Sprintf(" repository '%s'", sc.repoName))
}
log.Output(fmt.Sprintf("Successfully configured %s to use JFrog%s.", coreutils.PrintBoldTitle(sc.packageManager.String()), repoPrefix))
if note := configScopeNote(sc.packageManager); note != "" {
log.Output(note)
}
return nil
}

Expand Down
36 changes: 36 additions & 0 deletions artifactory/commands/setup/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -923,3 +923,39 @@ func TestSetupCommand_MavenCorrupted(t *testing.T) {
assert.NotContains(t, content, testCredential(), "Old token should be replaced")
})
}

// Every supported package manager must describe what it changed: the output is the
// only place a user learns the configuration is user-level rather than scoped to the
// directory they ran the command in.
func TestConfigScopeNote_CoversEverySupportedPackageManager(t *testing.T) {
for _, name := range GetSupportedPackageManagersList() {
packageManager := project.FromString(name)
note := configScopeNote(packageManager)
assert.NotEmptyf(t, note, "no scope note for supported package manager %q", name)
assert.Containsf(t, note, "your", "scope note for %q should name the configuration it changed: %s", name, note)
}
}

// Container logins authenticate rather than redirect resolution, so their note must
// not promise that projects now resolve through Artifactory — an unqualified
// `docker pull alpine` still reaches Docker Hub after `jf setup docker`.
func TestConfigScopeNote_ContainerLoginsDoNotClaimResolution(t *testing.T) {
for _, packageManager := range []project.ProjectType{project.Docker, project.Podman, project.Helm} {
note := configScopeNote(packageManager)
assert.Contains(t, note, "Credentials were saved", packageManager.String())
assert.NotContains(t, note, "applies to every", packageManager.String())
}

// Resolution-changing package managers must state the scope explicitly.
for _, packageManager := range []project.ProjectType{project.Npm, project.Maven, project.Go, project.Pip} {
note := configScopeNote(packageManager)
assert.Contains(t, note, "applies to every", packageManager.String())
assert.Contains(t, note, "not only the current directory", packageManager.String())
}
}

// An unsupported package manager has nothing accurate to say, so it must stay silent
// rather than print a misleading note.
func TestConfigScopeNote_UnknownPackageManagerIsSilent(t *testing.T) {
assert.Empty(t, configScopeNote(project.Cocoapods))
}
Loading