Skip to content

Commit

Permalink
feat: add yarn berry support
Browse files Browse the repository at this point in the history
  • Loading branch information
favna committed Nov 29, 2023
1 parent 0a1ff9b commit 67172e2
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 7 deletions.
14 changes: 14 additions & 0 deletions src/nodejs/supply/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 15 additions & 6 deletions src/nodejs/supply/supply.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type NPM interface {

type Yarn interface {
Build(string, string) error
Rebuild(string, string) error
}

type Stager interface {
Expand Down Expand Up @@ -315,18 +316,26 @@ func (s *Supplier) BuildDependencies() error {
return err
}

if (s.IsVendored) {
s.Log.Info("Prebuild detected (node_modules already exists)")
switch {
case s.UseYarn:
if err := s.Yarn.Rebuild(s.Stager.BuildDir(), s.Stager.CacheDir()); err != nil {
return err;
}
default:
if err := s.NPM.Rebuild(s.Stager.BuildDir()); err != nil {
return err
}
}
}

switch {
case s.UseYarn:
if err := s.Yarn.Build(s.Stager.BuildDir(), s.Stager.CacheDir()); err != nil {
return err
}

case s.IsVendored:
s.Log.Info("Prebuild detected (node_modules already exists)")
if err := s.NPM.Rebuild(s.Stager.BuildDir()); err != nil {
return err
}

default:
if err := s.NPM.Build(s.Stager.BuildDir(), s.Stager.CacheDir()); err != nil {
return err
Expand Down
106 changes: 105 additions & 1 deletion src/nodejs/yarn/yarn.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/cloudfoundry/libbuildpack"
)
Expand All @@ -22,6 +23,80 @@ type Yarn struct {
func (y *Yarn) Build(buildDir, cacheDir string) error {
y.Log.Info("Installing node modules (yarn.lock)")

err := y.doBuild(buildDir, cacheDir);

if err != nil {
return err
}

return nil;
}

func (y *Yarn) Rebuild(buildDir, cacheDir string) error {
y.Log.Info("Rebuilding native dependencies")

err := y.doBuild(buildDir, cacheDir);

if err != nil {
return err
}

return nil;
}

func (y *Yarn) doBuild(buildDir, cacheDir string) error {
yarnVersion, err := y.getYarnVersion(buildDir)
if err != nil {
return err
}

if strings.HasPrefix(yarnVersion, "1") {
return y.doBuildClassic(buildDir, cacheDir)
}

return y.doBuildBerry(buildDir)
}

func (y *Yarn) getYarnVersion(buildDir string) (string, error) {
cmd := exec.Command("yarn", "--version")
cmd.Dir = buildDir
cmd.Stdout = y.Log.Output()
cmd.Stderr = y.Log.Output()
cmd.Env = append(os.Environ(), "npm_config_nodedir="+os.Getenv("NODE_HOME"))

versionOutput, err := cmd.Output()
if err != nil {
return "", err
}
yarnVersion := strings.TrimSpace(string(versionOutput))
return yarnVersion, nil
}

func (y *Yarn) isYarnLocalCacheEnabled(buildDir string) (bool, error) {
cmd := exec.Command("yarn", "config", "get", "enableGlobalCache")
cmd.Dir = buildDir
cmd.Stdout = y.Log.Output()
cmd.Stderr = y.Log.Output()
cmd.Env = append(os.Environ(), "npm_config_nodedir="+os.Getenv("NODE_HOME"))

cacheStrategyOutput, err := cmd.Output()
if err != nil {
return false, err
}

yarnCacheStrategy := strings.TrimSpace(string(cacheStrategyOutput))

if yarnCacheStrategy == "false" {
return true, nil
}

return false, nil
}

func (y *Yarn) doBuildClassic(buildDir, cacheDir string) error {
// Start by informing users that Yarn v1 is deprecated and they should upgrade to Yarn v4 (Berry)
y.Log.Protip("Yarn v1 is deprecated and has been replaced with Yarn Berry by the Yarn organisation. Please upgrade to Yarn v4 (Berry) to avoid future deprecation warnings.", "https://yarnpkg.com/migration/guide")

offline, err := libbuildpack.FileExists(filepath.Join(buildDir, "npm-packages-offline-cache"))
if err != nil {
return err
Expand All @@ -41,7 +116,7 @@ func (y *Yarn) Build(buildDir, cacheDir string) error {
yarnConfig["yarn-offline-mirror-pruning"] = "false"
} else {
y.Log.Info("Running yarn in online mode")
y.Log.Info("To run yarn in offline mode, see: https://yarnpkg.com/blog/2016/11/24/offline-mirror")
y.Log.Info("To run yarn in offline mode, see: https://classic.yarnpkg.com/blog/2016/11/24/offline-mirror/")

yarnConfig["yarn-offline-mirror"] = filepath.Join(cacheDir, "npm-packages-offline-cache")
yarnConfig["yarn-offline-mirror-pruning"] = "true"
Expand Down Expand Up @@ -73,3 +148,32 @@ func (y *Yarn) Build(buildDir, cacheDir string) error {

return nil
}

func (y *Yarn) doBuildBerry(buildDir string) error {
usesLocalCache, err := y.isYarnLocalCacheEnabled(buildDir)
if err != nil {
return err
}

installArgs := []string{"install", "--immutable"}

if usesLocalCache {
installArgs = append(installArgs, "--immutable-cache")
}

cmd := exec.Command("yarn", installArgs...)
cmd.Dir = buildDir
cmd.Stdout = y.Log.Output()
cmd.Stderr = y.Log.Output()
cmd.Env = append(os.Environ(), "npm_config_nodedir="+os.Getenv("NODE_HOME"))
if err := y.Command.Run(cmd); err != nil {
return err
}

err = os.RemoveAll(filepath.Join(buildDir, ".yarn/cache"))
if err != nil {
panic(err)
}

return nil
}

0 comments on commit 67172e2

Please sign in to comment.