Skip to content
Open
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
6 changes: 5 additions & 1 deletion artifactory/commands/npm/npmcommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,11 @@ func (nc *NpmCommand) setNpmConfigAuthEnv(value, authKey string) error {
if nc.isNpmVersionSupportsScopedAuthEnv() {
// Get registry name without the protocol name but including the '//'
registryWithoutProtocolName := nc.registry[strings.Index(nc.registry, "://")+1:]
// Set "npm_config_//<registry-url>:_auth" environment variable to allow authentication with Artifactory
// Ensure registry ends with / (required for scoped auth)
if !strings.HasSuffix(registryWithoutProtocolName, "/") {
registryWithoutProtocolName += "/"
}
// Set "npm_config_//<registry-url>/:_auth" environment variable to allow authentication with Artifactory
scopedRegistryEnv := fmt.Sprintf(npmConfigAuthEnv, registryWithoutProtocolName, authKey)
return os.Setenv(scopedRegistryEnv, value)
}
Expand Down
8 changes: 4 additions & 4 deletions artifactory/commands/npm/npmcommand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ func TestPrepareConfigData(t *testing.T) {
}

// Assert that NPM_CONFIG__AUTH environment variable was set
assert.Equal(t, getTestCredentialValue(), os.Getenv(fmt.Sprintf(npmConfigAuthEnv, "//goodRegistry", utils.NpmConfigAuthKey)))
testsUtils.UnSetEnvAndAssert(t, fmt.Sprintf(npmConfigAuthEnv, "//goodRegistry", utils.NpmConfigAuthKey))
assert.Equal(t, getTestCredentialValue(), os.Getenv(fmt.Sprintf(npmConfigAuthEnv, "//goodRegistry/", utils.NpmConfigAuthKey)))
testsUtils.UnSetEnvAndAssert(t, fmt.Sprintf(npmConfigAuthEnv, "//goodRegistry/", utils.NpmConfigAuthKey))
}

func TestSetNpmConfigAuthEnv(t *testing.T) {
Expand All @@ -93,7 +93,7 @@ func TestSetNpmConfigAuthEnv(t *testing.T) {
},
authKey: utils.NpmConfigAuthKey,
value: "some_auth_token",
expectedEnv: "npm_config_//registry.example.com:_auth",
expectedEnv: "npm_config_//registry.example.com/:_auth",
},
{
name: "set scoped registry authToken env",
Expand All @@ -102,7 +102,7 @@ func TestSetNpmConfigAuthEnv(t *testing.T) {
},
authKey: utils.NpmConfigAuthTokenKey,
value: "some_auth_token",
expectedEnv: "npm_config_//registry.example.com:_authToken",
expectedEnv: "npm_config_//registry.example.com/:_authToken",
},
{
name: "set legacy auth env",
Expand Down
36 changes: 36 additions & 0 deletions artifactory/commands/pnpm/artifactoryinstall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package pnpm

import "github.com/jfrog/jfrog-client-go/utils/log"

type pnpmRtInstall struct {
*PnpmCommand
}

func (pri *pnpmRtInstall) PrepareInstallPrerequisites(repo string) (err error) {
log.Debug("Executing pnpm install command using jfrog RT on repository: ", repo)
if err = pri.setArtifactoryAuth(); err != nil {
return err
}

if err = pri.setNpmAuthRegistry(repo); err != nil {
return err
}

return pri.setRestoreNpmrcFunc()
}

func (pri *pnpmRtInstall) Run() (err error) {
if err = pri.CreateTempNpmrc(); err != nil {
return
}
if err = pri.prepareBuildInfoModule(); err != nil {
return
}
err = pri.collectDependencies()
return
}

func (pri *pnpmRtInstall) RestoreNpmrc() (err error) {
// Restore the npmrc file, since we are using our own npmrc
return pri.restoreNpmrcFunc()
}
156 changes: 156 additions & 0 deletions artifactory/commands/pnpm/artifactoryupload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package pnpm

import (
"errors"
"fmt"

buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-cli-artifactory/artifactory/utils/civcs"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory"
"github.com/jfrog/jfrog-client-go/artifactory/services"
specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/content"
)

type pnpmRtUpload struct {
*PnpmPublishCommand
}

func (pru *pnpmRtUpload) upload() (err error) {
for _, packedFilePath := range pru.packedFilePaths {
if err = pru.readPackageInfoFromTarball(packedFilePath); err != nil {
return
}
target := fmt.Sprintf("%s/%s", pru.repo, pru.packageInfo.GetDeployPath())

// If requested, perform a Xray binary scan before deployment. If a FailBuildError is returned, skip the deployment.
if pru.xrayScan {
if err = performXrayScan(packedFilePath, pru.repo, pru.serverDetails, pru.scanOutputFormat); err != nil {
return
}
}
err = errors.Join(err, pru.doDeploy(target, pru.serverDetails, packedFilePath))
}
return
}

func (pru *pnpmRtUpload) getBuildArtifacts() []buildinfo.Artifact {
return ConvertArtifactsDetailsToBuildInfoArtifacts(pru.artifactsDetailsReader, specutils.ConvertArtifactsDetailsToBuildInfoArtifacts)
}

func (pru *pnpmRtUpload) doDeploy(target string, artDetails *config.ServerDetails, packedFilePath string) error {
servicesManager, err := utils.CreateServiceManager(artDetails, -1, 0, false)
if err != nil {
return err
}
up := services.NewUploadParams()
up.CommonParams = &specutils.CommonParams{Pattern: packedFilePath, Target: target}
if err = pru.addDistTagIfSet(up.CommonParams); err != nil {
return err
}
// Add CI VCS properties if in CI environment
if err = pru.addCIVcsProps(up.CommonParams); err != nil {
return err
}
var totalFailed int
if pru.collectBuildInfo || pru.detailedSummary {
if pru.collectBuildInfo {
up.BuildProps, err = pru.getBuildPropsForArtifact()
if err != nil {
return err
}
}
summary, err := servicesManager.UploadFilesWithSummary(artifactory.UploadServiceOptions{}, up)
if err != nil {
return err
}
totalFailed = summary.TotalFailed
if pru.collectBuildInfo {
pru.artifactsDetailsReader = append(pru.artifactsDetailsReader, summary.ArtifactsDetailsReader)
} else {
err = summary.ArtifactsDetailsReader.Close()
if err != nil {
return err
}
}
if pru.detailedSummary {
if err = pru.setDetailedSummary(summary); err != nil {
return err
}
} else {
if err = summary.TransferDetailsReader.Close(); err != nil {
return err
}
}
} else {
_, totalFailed, err = servicesManager.UploadFiles(artifactory.UploadServiceOptions{}, up)
if err != nil {
return err
}
}

// We are deploying only one Artifact which have to be deployed, in case of failure we should fail
if totalFailed > 0 {
return errorutils.CheckErrorf("Failed to upload the pnpm package to Artifactory. See Artifactory logs for more details.")
}
return nil
}

func (pru *pnpmRtUpload) addDistTagIfSet(params *specutils.CommonParams) error {
if pru.distTag == "" {
return nil
}
props, err := specutils.ParseProperties(DistTagPropKey + "=" + pru.distTag)
if err != nil {
return err
}
params.TargetProps = props
return nil
}

// addCIVcsProps adds CI VCS properties to the upload params if in CI environment.
func (pru *pnpmRtUpload) addCIVcsProps(params *specutils.CommonParams) error {
ciProps := civcs.GetCIVcsPropsString()
if ciProps == "" {
return nil
}
if params.TargetProps == nil {
props, err := specutils.ParseProperties(ciProps)
if err != nil {
return err
}
params.TargetProps = props
} else {
// Merge with existing properties
if err := params.TargetProps.ParseAndAddProperties(ciProps); err != nil {
return err
}
}
return nil
}

func (pru *pnpmRtUpload) appendReader(summary *specutils.OperationSummary) error {
readersSlice := []*content.ContentReader{pru.result.Reader(), summary.TransferDetailsReader}
reader, err := content.MergeReaders(readersSlice, content.DefaultKey)
if err != nil {
return err
}
pru.result.SetReader(reader)
return nil
}

func (pru *pnpmRtUpload) setDetailedSummary(summary *specutils.OperationSummary) (err error) {
pru.result.SetFailCount(pru.result.FailCount() + summary.TotalFailed)
pru.result.SetSuccessCount(pru.result.SuccessCount() + summary.TotalSucceeded)
if pru.result.Reader() == nil {
pru.result.SetReader(summary.TransferDetailsReader)
} else {
if err = pru.appendReader(summary); err != nil {
return
}
}
return
}
43 changes: 43 additions & 0 deletions artifactory/commands/pnpm/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pnpm

import (
"github.com/jfrog/jfrog-cli-core/v2/common/build"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
)

type CommonArgs struct {
repo string
buildConfiguration *build.BuildConfiguration
pnpmArgs []string
serverDetails *config.ServerDetails
useNative bool
}

func (ca *CommonArgs) SetServerDetails(serverDetails *config.ServerDetails) *CommonArgs {
ca.serverDetails = serverDetails
return ca
}

func (ca *CommonArgs) SetPnpmArgs(pnpmArgs []string) *CommonArgs {
ca.pnpmArgs = pnpmArgs
return ca
}

func (ca *CommonArgs) SetBuildConfiguration(buildConfiguration *build.BuildConfiguration) *CommonArgs {
ca.buildConfiguration = buildConfiguration
return ca
}

func (ca *CommonArgs) SetRepo(repo string) *CommonArgs {
ca.repo = repo
return ca
}

func (ca *CommonArgs) UseNative() bool {
return ca.useNative
}

func (ca *CommonArgs) SetUseNative(useNpmRc bool) *CommonArgs {
ca.useNative = useNpmRc
return ca
}
41 changes: 41 additions & 0 deletions artifactory/commands/pnpm/installstrategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package pnpm

import "github.com/jfrog/jfrog-client-go/utils/log"

type Installer interface {
PrepareInstallPrerequisites(repo string) error
Run() error
RestoreNpmrc() error
}

type PnpmInstallStrategy struct {
strategy Installer
strategyName string
}

// Get pnpm implementation
func NewPnpmInstallStrategy(useNativeClient bool, pnpmCommand *PnpmCommand) *PnpmInstallStrategy {
ppi := PnpmInstallStrategy{}
if useNativeClient {
ppi.strategy = &pnpmInstall{pnpmCommand}
ppi.strategyName = "native"
} else {
ppi.strategy = &pnpmRtInstall{pnpmCommand}
ppi.strategyName = "artifactory"
}
return &ppi
}

func (ppi *PnpmInstallStrategy) PrepareInstallPrerequisites(repo string) error {
log.Debug("Using strategy for preparing install prerequisites: ", ppi.strategyName)
return ppi.strategy.PrepareInstallPrerequisites(repo)
}

func (ppi *PnpmInstallStrategy) Install() error {
log.Debug("Using strategy for pnpm install: ", ppi.strategyName)
return ppi.strategy.Run()
}

func (ppi *PnpmInstallStrategy) RestoreNpmrc() error {
return ppi.strategy.RestoreNpmrc()
}
Loading
Loading