Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish multiple npm workspaces packages #1149

Merged
merged 12 commits into from
Mar 12, 2024
117 changes: 71 additions & 46 deletions artifactory/commands/npm/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package npm
import (
"archive/tar"
"compress/gzip"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -37,7 +38,7 @@ type NpmPublishCommandArgs struct {
executablePath string
workingDirectory string
collectBuildInfo bool
packedFilePath string
packedFilePaths []string
packageInfo *biutils.PackageInfo
publishPath string
tarballProvided bool
Expand Down Expand Up @@ -172,11 +173,11 @@ func (npc *NpmPublishCommand) Run() (err error) {
return err
}
// We should delete the tarball we created
return deleteCreatedTarballAndError(npc.packedFilePath, err)
return deleteCreatedTarballAndError(npc.packedFilePaths, err)
}

if !npc.tarballProvided {
if err := deleteCreatedTarball(npc.packedFilePath); err != nil {
if err := deleteCreatedTarball(npc.packedFilePaths); err != nil {
return err
}
}
Expand Down Expand Up @@ -217,6 +218,7 @@ func (npc *NpmPublishCommand) CommandName() string {
}

func (npc *NpmPublishCommand) preparePrerequisites() error {
npc.packedFilePaths = make([]string, 0)
currentDir, err := os.Getwd()
if err != nil {
return errorutils.CheckError(err)
Expand Down Expand Up @@ -251,7 +253,7 @@ func (npc *NpmPublishCommand) preparePrerequisites() error {

func (npc *NpmPublishCommand) pack() error {
log.Debug("Creating npm package.")
packageFileName, err := npm.Pack(npc.npmArgs, npc.executablePath)
packedFileNames, err := npm.Pack(npc.npmArgs, npc.executablePath)
if err != nil {
return err
}
Expand All @@ -261,8 +263,10 @@ func (npc *NpmPublishCommand) pack() error {
return err
}

npc.packedFilePath = filepath.Join(tarballDir, packageFileName)
log.Debug("Created npm package at", npc.packedFilePath)
for _, packageFileName := range packedFileNames {
npc.packedFilePaths = append(npc.packedFilePaths, filepath.Join(tarballDir, packageFileName))
}

return nil
}

Expand All @@ -279,34 +283,36 @@ func (npc *NpmPublishCommand) getTarballDir() (string, error) {
return dest, nil
}

func (npc *NpmPublishCommand) publish() error {
log.Debug("Deploying npm package.")
if err := npc.readPackageInfoFromTarball(); err != nil {
return err
}
target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath())

// If requested, perform a Xray binary scan before deployment. If a FailBuildError is returned, skip the deployment.
if npc.xrayScan {
fileSpec := spec.NewBuilder().
Pattern(npc.packedFilePath).
Target(npc.repo + "/").
BuildSpec()
err := commandsutils.ConditionalUploadScanFunc(npc.serverDetails, fileSpec, 1, npc.scanOutputFormat)
if err != nil {
return err
func (npc *NpmPublishCommand) publish() (err error) {
for _, packedFilePath := range npc.packedFilePaths {
log.Debug("Deploying npm package.")
if err = npc.readPackageInfoFromTarball(packedFilePath); err != nil {
return
}
target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath())

// If requested, perform a Xray binary scan before deployment. If a FailBuildError is returned, skip the deployment.
if npc.xrayScan {
fileSpec := spec.NewBuilder().
Pattern(packedFilePath).
Target(npc.repo + "/").
BuildSpec()
if err = commandsutils.ConditionalUploadScanFunc(npc.serverDetails, fileSpec, 1, npc.scanOutputFormat); err != nil {
return
}
}
err = errors.Join(err, npc.doDeploy(target, npc.serverDetails, packedFilePath))
}
return npc.doDeploy(target, npc.serverDetails)
return
}

func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerDetails) error {
func (npc *NpmPublishCommand) 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: npc.packedFilePath, Target: target}
up.CommonParams = &specutils.CommonParams{Pattern: packedFilePath, Target: target}
var totalFailed int
if npc.collectBuildInfo || npc.detailedSummary {
if npc.collectBuildInfo {
Expand Down Expand Up @@ -341,12 +347,11 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD
}
}
if npc.detailedSummary {
npc.result.SetReader(summary.TransferDetailsReader)
npc.result.SetFailCount(totalFailed)
npc.result.SetSuccessCount(summary.TotalSucceeded)
if err = npc.setDetailedSummary(summary); err != nil {
return err
}
} else {
err = summary.TransferDetailsReader.Close()
if err != nil {
if err = summary.TransferDetailsReader.Close(); err != nil {
return err
}
}
Expand All @@ -364,6 +369,29 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD
return nil
}

func (npc *NpmPublishCommand) setDetailedSummary(summary *specutils.OperationSummary) (err error) {
npc.result.SetFailCount(npc.result.FailCount() + summary.TotalFailed)
npc.result.SetSuccessCount(npc.result.SuccessCount() + summary.TotalSucceeded)
if npc.result.Reader() == nil {
npc.result.SetReader(summary.TransferDetailsReader)
} else {
if err = npc.appendReader(summary); err != nil {
return
}
}
return
}

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

func (npc *NpmPublishCommand) setPublishPath() error {
log.Debug("Reading Package Json.")

Expand Down Expand Up @@ -394,13 +422,12 @@ func (npc *NpmPublishCommand) setPackageInfo() error {
}
log.Debug("The provided path is not a directory, we assume this is a compressed npm package")
npc.tarballProvided = true
npc.packedFilePath = npc.publishPath
return npc.readPackageInfoFromTarball()
return npc.readPackageInfoFromTarball(npc.publishPath)
}

func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) {
log.Debug("Extracting info from npm package:", npc.packedFilePath)
tarball, err := os.Open(npc.packedFilePath)
func (npc *NpmPublishCommand) readPackageInfoFromTarball(packedFilePath string) (err error) {
log.Debug("Extracting info from npm package:", npc.packedFilePaths)
tarball, err := os.Open(packedFilePath)
if err != nil {
return errorutils.CheckError(err)
}
Expand All @@ -420,7 +447,7 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) {
hdr, err := tarReader.Next()
if err != nil {
if err == io.EOF {
return errorutils.CheckErrorf("Could not find 'package.json' in the compressed npm package: " + npc.packedFilePath)
return errorutils.CheckErrorf("Could not find 'package.json' in the compressed npm package: " + packedFilePath)
}
return errorutils.CheckError(err)
}
Expand All @@ -436,18 +463,16 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) {
}
}

func deleteCreatedTarballAndError(packedFilePath string, currentError error) error {
if err := deleteCreatedTarball(packedFilePath); err != nil {
errorText := fmt.Sprintf("Two errors occurred: \n%s \n%s", currentError, err)
return errorutils.CheckErrorf(errorText)
}
return currentError
func deleteCreatedTarballAndError(packedFilesPath []string, currentError error) error {
return errors.Join(currentError, deleteCreatedTarball(packedFilesPath))
}

func deleteCreatedTarball(packedFilePath string) error {
if err := os.Remove(packedFilePath); err != nil {
return errorutils.CheckError(err)
func deleteCreatedTarball(packedFilesPath []string) error {
for _, packedFilePath := range packedFilesPath {
if err := os.Remove(packedFilePath); err != nil {
return errorutils.CheckError(err)
}
log.Debug("Successfully deleted the created npm package:", packedFilePath)
}
log.Debug("Successfully deleted the created npm package:", packedFilePath)
return nil
}
13 changes: 10 additions & 3 deletions artifactory/commands/npm/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ import (

func TestReadPackageInfoFromTarball(t *testing.T) {
npmPublish := NewNpmPublishCommand()
npmPublish.packedFilePath = filepath.Join("..", "testdata", "npm", "npm-example-0.0.3.tgz")
err := npmPublish.readPackageInfoFromTarball()
assert.NoError(t, err)
npmPublish.packedFilePaths = append(npmPublish.packedFilePaths, filepath.Join("..", "testdata", "npm", "npm-example-0.0.3.tgz"))
npmPublish.packedFilePaths = append(npmPublish.packedFilePaths, filepath.Join("..", "testdata", "npm", "npm-example-0.0.4.tgz"))

err := npmPublish.readPackageInfoFromTarball(npmPublish.packedFilePaths[0])
assert.NoError(t, err)
assert.Equal(t, "npm-example", npmPublish.packageInfo.Name)
assert.Equal(t, "0.0.3", npmPublish.packageInfo.Version)

err = npmPublish.readPackageInfoFromTarball(npmPublish.packedFilePaths[1])
assert.NoError(t, err)
assert.Equal(t, "npm-example", npmPublish.packageInfo.Name)
assert.Equal(t, "0.0.4", npmPublish.packageInfo.Version)

}
Binary file not shown.
11 changes: 5 additions & 6 deletions artifactory/utils/npm/pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (
"github.com/jfrog/jfrog-client-go/utils/errorutils"
)

func Pack(npmFlags []string, executablePath string) (string, error) {
func Pack(npmFlags []string, executablePath string) ([]string, error) {
configListCmdConfig := createPackCmdConfig(executablePath, npmFlags)
output, err := gofrogcmd.RunCmdOutput(configListCmdConfig)
if err != nil {
return "", errorutils.CheckError(err)
return []string{}, errorutils.CheckError(err)
}
return getPackageFileNameFromOutput(output)
return getPackageFileNameFromOutput(output), nil
}

func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.NpmConfig {
Expand All @@ -27,8 +27,7 @@ func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.N
}
}

func getPackageFileNameFromOutput(output string) (string, error) {
func getPackageFileNameFromOutput(output string) []string {
output = strings.TrimSpace(output)
lines := strings.Split(output, "\n")
return strings.TrimSpace(lines[len(lines)-1]), nil
return strings.Split(output, "\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will work on windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like from the CLI test that it is working on windows 👍

}
36 changes: 0 additions & 36 deletions artifactory/utils/npm/pack_test.go
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this test as the test case was irrelevant.
We checked the whole output of the CMD and tried to extract the tar.gz file name, as in practice, the npm cmd already gives us the name. and all we have to do now is to split the file names if we have more then one.
I've deleted the test here, and added a full test in CLI side to publish multiple packages.

This file was deleted.

28 changes: 0 additions & 28 deletions artifactory/utils/testdata/npm/npmPackOutputV6

This file was deleted.

28 changes: 0 additions & 28 deletions artifactory/utils/testdata/npm/npmPackOutputV7

This file was deleted.

Loading