diff --git a/cli/internal/backends/nodejs/nodejs.go b/cli/internal/backends/nodejs/nodejs.go index 7f2f1d9291adc..92cc67b5ec483 100644 --- a/cli/internal/backends/nodejs/nodejs.go +++ b/cli/internal/backends/nodejs/nodejs.go @@ -3,6 +3,8 @@ package nodejs import ( "fmt" "io/ioutil" + "log" + "path/filepath" "turbo/internal/api" "turbo/internal/fs" "turbo/internal/util" @@ -42,7 +44,7 @@ var NodejsYarnBackend = api.LanguageBackend{ return false, nil } - isBerry, err := util.IsBerry(cwd, version) + isBerry, err := util.IsBerry(cwd, version, true) if err != nil { return false, fmt.Errorf("could not determine yarn version (v1 or berry): %w", err) } @@ -50,6 +52,20 @@ var NodejsYarnBackend = api.LanguageBackend{ if !isBerry { return true, nil } + } else { + log.Println("[WARNING] Did not find \"packageManager\" in your package.json. Please run \"npx @turbo/codemod add-package-manager\"") + + specfileExists := fs.FileExists(filepath.Join(cwd, backend.Specfile)) + lockfileExists := fs.FileExists(filepath.Join(cwd, backend.Lockfile)) + + isBerry, err := util.IsBerry(cwd, "", false) + if err != nil { + return false, fmt.Errorf("could not check if yarn is berry: %w", err) + } + + if specfileExists && lockfileExists && !isBerry { + return true, nil + } } return false, nil @@ -85,7 +101,7 @@ var NodejsBerryBackend = api.LanguageBackend{ return false, nil } - isBerry, err := util.IsBerry(cwd, version) + isBerry, err := util.IsBerry(cwd, version, true) if err != nil { return false, fmt.Errorf("could not determine yarn version (v1 or berry): %w", err) } @@ -98,6 +114,27 @@ var NodejsBerryBackend = api.LanguageBackend{ return false, fmt.Errorf("only yarn v2/v3 with `nodeLinker: node-modules` is supported at this time") } + return true, nil + } + } else { + log.Println("[WARNING] Did not find \"packageManager\" in your package.json. Please set the \"packageManager\" field to your package.json") + + specfileExists := fs.FileExists(filepath.Join(cwd, backend.Specfile)) + lockfileExists := fs.FileExists(filepath.Join(cwd, backend.Lockfile)) + + isBerry, err := util.IsBerry(cwd, "", false) + if err != nil { + return false, fmt.Errorf("could not check if yarn is berry: %w", err) + } + + if specfileExists && lockfileExists && isBerry { + isNMLinker, err := util.IsNMLinker(cwd) + if err != nil { + return false, fmt.Errorf("could not check if yarn is using nm-linker: %w", err) + } else if !isNMLinker { + return false, fmt.Errorf("only yarn nm-linker is supported") + } + return true, nil } } @@ -139,13 +176,22 @@ var NodejsPnpmBackend = api.LanguageBackend{ GetRunCommand: func() []string { return []string{"pnpm", "run"} }, - Detect: func(_ string, pkg *fs.PackageJSON, backend *api.LanguageBackend) (bool, error) { + Detect: func(cwd string, pkg *fs.PackageJSON, backend *api.LanguageBackend) (bool, error) { if pkg.PackageManager != "" { packageManager, _ := util.GetPackageManagerAndVersion(pkg.PackageManager) if packageManager == "pnpm" { return true, nil } + } else { + log.Println("[WARNING] Did not find \"packageManager\" in your package.json. Please run \"npx @turbo/codemod add-package-manager\"") + + specfileExists := fs.FileExists(filepath.Join(cwd, backend.Specfile)) + lockfileExists := fs.FileExists(filepath.Join(cwd, backend.Lockfile)) + + if specfileExists && lockfileExists { + return true, nil + } } return false, nil @@ -173,13 +219,22 @@ var NodejsNpmBackend = api.LanguageBackend{ GetRunCommand: func() []string { return []string{"npm", "run"} }, - Detect: func(_ string, pkg *fs.PackageJSON, backend *api.LanguageBackend) (bool, error) { + Detect: func(cwd string, pkg *fs.PackageJSON, backend *api.LanguageBackend) (bool, error) { if pkg.PackageManager != "" { packageManager, _ := util.GetPackageManagerAndVersion(pkg.PackageManager) if packageManager == "npm" { return true, nil } + } else { + log.Println("[WARNING] Did not find \"packageManager\" in your package.json. Please run \"npx @turbo/codemod add-package-manager\"") + + specfileExists := fs.FileExists(filepath.Join(cwd, backend.Specfile)) + lockfileExists := fs.FileExists(filepath.Join(cwd, backend.Lockfile)) + + if specfileExists && lockfileExists { + return true, nil + } } return false, nil diff --git a/cli/internal/util/backends.go b/cli/internal/util/backends.go index 8dfa362a19410..1f4b6241bf97a 100644 --- a/cli/internal/util/backends.go +++ b/cli/internal/util/backends.go @@ -3,6 +3,7 @@ package util import ( "fmt" "io/ioutil" + "os/exec" "path/filepath" "regexp" "strings" @@ -19,7 +20,8 @@ func IsYarn(backendName string) bool { return backendName == "nodejs-yarn" || backendName == "nodejs-berry" } -func IsBerry(cwd string, version string) (bool, error) { +func IsBerry(cwd string, version string, pkgManager bool) (bool, error) { + if pkgManager { v, err := semver.NewVersion(version) if err != nil { return false, fmt.Errorf("could not parse yarn version: %w", err) @@ -30,6 +32,25 @@ func IsBerry(cwd string, version string) (bool, error) { } return c.Check(v), nil + } else { + cmd := exec.Command("yarn", "--version") + cmd.Dir = cwd + out, err := cmd.Output() + if err != nil { + return false, fmt.Errorf("could not detect yarn version: %w", err) + } + + v, err := semver.NewVersion(strings.TrimSpace(string(out))) + if err != nil { + return false, fmt.Errorf("could not parse yarn version: %w", err) + } + c, err := semver.NewConstraint(">=2.0.0") + if err != nil { + return false, fmt.Errorf("could not create constraint: %w", err) + } + + return c.Check(v), nil + } } func IsNMLinker(cwd string) (bool, error) { @@ -53,4 +74,3 @@ func GetPackageManagerAndVersion(packageManager string) (string, string) { return strings.Split(match, "@")[0], strings.Split(match, "@")[1] } -