From 8dc6486b43b320f4edf610b804a2709c09380534 Mon Sep 17 00:00:00 2001 From: --global Date: Thu, 27 Apr 2023 14:25:47 -0400 Subject: [PATCH] Hooked up package manager to Go code --- Cargo.lock | 5 +- cli/internal/context/context.go | 8 +- cli/internal/context/context_test.go | 4 +- cli/internal/packagemanager/packagemanager.go | 68 +--- .../packagemanager/packagemanager_test.go | 349 ------------------ cli/internal/prune/prune.go | 6 +- cli/internal/run/run.go | 10 +- cli/internal/turbostate/turbostate.go | 2 - crates/turborepo-lib/Cargo.toml | 4 +- crates/turborepo-lib/src/execution_state.rs | 13 +- crates/turborepo-lib/src/package_json.rs | 22 +- crates/turborepo-lib/src/package_manager.rs | 11 +- .../integration/tests/package_manager.t | 35 ++ 13 files changed, 83 insertions(+), 454 deletions(-) create mode 100644 turborepo-tests/integration/tests/package_manager.t diff --git a/Cargo.lock b/Cargo.lock index bbafdd34c5c6c..b208b1cf36a39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1752,7 +1752,7 @@ checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.15", ] [[package]] @@ -3774,7 +3774,7 @@ checksum = "4c65c625186a9bcce6699394bee511e1b1aec689aa7e3be1bf4e996e75834153" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.15", ] [[package]] @@ -8962,7 +8962,6 @@ dependencies = [ "itertools", "lazy_static", "libc", - "log", "node-semver", "notify 5.1.0", "owo-colors", diff --git a/cli/internal/context/context.go b/cli/internal/context/context.go index 7e556a758facc..02dac233d618e 100644 --- a/cli/internal/context/context.go +++ b/cli/internal/context/context.go @@ -142,7 +142,7 @@ func isWorkspaceReference(packageVersion string, dependencyVersion string, cwd s } // SinglePackageGraph constructs a Context instance from a single package. -func SinglePackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (*Context, error) { +func SinglePackageGraph(rootPackageJSON *fs.PackageJSON, packageManagerName string) (*Context, error) { workspaceInfos := workspace.Catalog{ PackageJSONs: map[string]*fs.PackageJSON{util.RootPkgName: rootPackageJSON}, TurboConfigs: map[string]*fs.TurboJSON{}, @@ -152,7 +152,7 @@ func SinglePackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON * RootNode: core.ROOT_NODE_NAME, } c.WorkspaceGraph.Connect(dag.BasicEdge(util.RootPkgName, core.ROOT_NODE_NAME)) - packageManager, err := packagemanager.GetPackageManager(repoRoot, rootPackageJSON) + packageManager, err := packagemanager.GetPackageManager(packageManagerName) if err != nil { return nil, err } @@ -161,7 +161,7 @@ func SinglePackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON * } // BuildPackageGraph constructs a Context instance with information about the package dependency graph -func BuildPackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON) (*Context, error) { +func BuildPackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *fs.PackageJSON, packageManagerName string) (*Context, error) { c := &Context{} rootpath := repoRoot.ToStringDuringMigration() c.WorkspaceInfos = workspace.Catalog{ @@ -172,7 +172,7 @@ func BuildPackageGraph(repoRoot turbopath.AbsoluteSystemPath, rootPackageJSON *f var warnings Warnings - packageManager, err := packagemanager.GetPackageManager(repoRoot, rootPackageJSON) + packageManager, err := packagemanager.GetPackageManager(packageManagerName) if err != nil { return nil, err } diff --git a/cli/internal/context/context_test.go b/cli/internal/context/context_test.go index 7e04590416c25..ce67f12c63c1c 100644 --- a/cli/internal/context/context_test.go +++ b/cli/internal/context/context_test.go @@ -141,7 +141,7 @@ func TestBuildPackageGraph_DuplicateNames(t *testing.T) { PackageManager: "pnpm@7.15.0", } - _, actualErr := BuildPackageGraph(path, pkgJSON) + _, actualErr := BuildPackageGraph(path, pkgJSON, "pnpm") // Not asserting the full error message, because it includes a path with slashes and backslashes // getting the regex incantation to check that is not worth it. @@ -157,7 +157,7 @@ func Test_populateExternalDeps_NoTransitiveDepsWithoutLockfile(t *testing.T) { PackageManager: "pnpm@7.15.0", } - pm, err := packagemanager.GetPackageManager(path, pkgJSON) + pm, err := packagemanager.GetPackageManager("pnpm") assert.NilError(t, err) pm.UnmarshalLockfile = func(rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) { return nil, errors.New("bad lockfile") diff --git a/cli/internal/packagemanager/packagemanager.go b/cli/internal/packagemanager/packagemanager.go index dc5b9665884dc..99dcf4a452b7f 100644 --- a/cli/internal/packagemanager/packagemanager.go +++ b/cli/internal/packagemanager/packagemanager.go @@ -8,14 +8,12 @@ import ( "fmt" "path/filepath" "regexp" - "strings" "github.com/pkg/errors" "github.com/vercel/turbo/cli/internal/fs" "github.com/vercel/turbo/cli/internal/globby" "github.com/vercel/turbo/cli/internal/lockfile" "github.com/vercel/turbo/cli/internal/turbopath" - "github.com/vercel/turbo/cli/internal/util" ) // PackageManager is an abstraction across package managers @@ -80,58 +78,22 @@ var ( packageManagerRegex = regexp.MustCompile(packageManagerPattern) ) -// ParsePackageManagerString takes a package manager version string parses it into consituent components -func ParsePackageManagerString(packageManager string) (manager string, version string, err error) { - match := packageManagerRegex.FindString(packageManager) - if len(match) == 0 { - return "", "", fmt.Errorf("We could not parse packageManager field in package.json, expected: %s, received: %s", packageManagerPattern, packageManager) +// GetPackageManager reads the package manager name sent by the Rust side +func GetPackageManager(name string) (packageManager *PackageManager, err error) { + switch name { + case "yarn": + return &nodejsYarn, nil + case "berry": + return &nodejsBerry, nil + case "npm": + return &nodejsNpm, nil + case "pnpm": + return &nodejsPnpm, nil + case "pnpm6": + return &nodejsPnpm6, nil + default: + return nil, errors.New("Unknown package manager") } - - return strings.Split(match, "@")[0], strings.Split(match, "@")[1], nil -} - -// GetPackageManager attempts all methods for identifying the package manager in use. -func GetPackageManager(projectDirectory turbopath.AbsoluteSystemPath, pkg *fs.PackageJSON) (packageManager *PackageManager, err error) { - result, _ := readPackageManager(pkg) - if result != nil { - return result, nil - } - - return detectPackageManager(projectDirectory) -} - -// readPackageManager attempts to read the package manager from the package.json. -func readPackageManager(pkg *fs.PackageJSON) (packageManager *PackageManager, err error) { - if pkg.PackageManager != "" { - manager, version, err := ParsePackageManagerString(pkg.PackageManager) - if err != nil { - return nil, err - } - - for _, packageManager := range packageManagers { - isResponsible, err := packageManager.Matches(manager, version) - if isResponsible && (err == nil) { - return &packageManager, nil - } - } - } - - return nil, errors.New(util.Sprintf("We did not find a package manager specified in your root package.json. Please set the \"packageManager\" property in your root package.json (${UNDERLINE}https://nodejs.org/api/packages.html#packagemanager)${RESET} or run `npx @turbo/codemod add-package-manager` in the root of your monorepo.")) -} - -// detectPackageManager attempts to detect the package manager by inspecting the project directory state. -func detectPackageManager(projectDirectory turbopath.AbsoluteSystemPath) (packageManager *PackageManager, err error) { - for _, packageManager := range packageManagers { - isResponsible, err := packageManager.detect(projectDirectory, &packageManager) - if err != nil { - return nil, err - } - if isResponsible { - return &packageManager, nil - } - } - - return nil, errors.New(util.Sprintf("We did not detect an in-use package manager for your project. Please set the \"packageManager\" property in your root package.json (${UNDERLINE}https://nodejs.org/api/packages.html#packagemanager)${RESET} or run `npx @turbo/codemod add-package-manager` in the root of your monorepo.")) } // GetWorkspaces returns the list of package.json files for the current repository. diff --git a/cli/internal/packagemanager/packagemanager_test.go b/cli/internal/packagemanager/packagemanager_test.go index a5dc472273189..f04cdbbbc3ff0 100644 --- a/cli/internal/packagemanager/packagemanager_test.go +++ b/cli/internal/packagemanager/packagemanager_test.go @@ -2,9 +2,6 @@ package packagemanager import ( "os" - "path/filepath" - "reflect" - "sort" "testing" "github.com/vercel/turbo/cli/internal/fs" @@ -12,352 +9,6 @@ import ( "gotest.tools/v3/assert" ) -func TestParsePackageManagerString(t *testing.T) { - tests := []struct { - name string - packageManager string - wantManager string - wantVersion string - wantErr bool - }{ - { - name: "errors with a tag version", - packageManager: "npm@latest", - wantManager: "", - wantVersion: "", - wantErr: true, - }, - { - name: "errors with no version", - packageManager: "npm", - wantManager: "", - wantVersion: "", - wantErr: true, - }, - { - name: "requires fully-qualified semver versions (one digit)", - packageManager: "npm@1", - wantManager: "", - wantVersion: "", - wantErr: true, - }, - { - name: "requires fully-qualified semver versions (two digits)", - packageManager: "npm@1.2", - wantManager: "", - wantVersion: "", - wantErr: true, - }, - { - name: "supports custom labels", - packageManager: "npm@1.2.3-alpha.1", - wantManager: "npm", - wantVersion: "1.2.3-alpha.1", - wantErr: false, - }, - { - name: "only supports specified package managers", - packageManager: "pip@1.2.3", - wantManager: "", - wantVersion: "", - wantErr: true, - }, - { - name: "supports npm", - packageManager: "npm@0.0.1", - wantManager: "npm", - wantVersion: "0.0.1", - wantErr: false, - }, - { - name: "supports pnpm", - packageManager: "pnpm@0.0.1", - wantManager: "pnpm", - wantVersion: "0.0.1", - wantErr: false, - }, - { - name: "supports yarn", - packageManager: "yarn@111.0.1", - wantManager: "yarn", - wantVersion: "111.0.1", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotManager, gotVersion, err := ParsePackageManagerString(tt.packageManager) - if (err != nil) != tt.wantErr { - t.Errorf("ParsePackageManagerString() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotManager != tt.wantManager { - t.Errorf("ParsePackageManagerString() got manager = %v, want manager %v", gotManager, tt.wantManager) - } - if gotVersion != tt.wantVersion { - t.Errorf("ParsePackageManagerString() got version = %v, want version %v", gotVersion, tt.wantVersion) - } - }) - } -} - -func TestGetPackageManager(t *testing.T) { - cwdRaw, err := os.Getwd() - assert.NilError(t, err, "os.Getwd") - cwd, err := fs.GetCwd(cwdRaw) - assert.NilError(t, err, "GetCwd") - tests := []struct { - name string - projectDirectory turbopath.AbsoluteSystemPath - pkg *fs.PackageJSON - want string - wantErr bool - }{ - { - name: "finds npm from a package manager string", - projectDirectory: cwd, - pkg: &fs.PackageJSON{PackageManager: "npm@1.2.3"}, - want: "nodejs-npm", - wantErr: false, - }, - { - name: "finds pnpm6 from a package manager string", - projectDirectory: cwd, - pkg: &fs.PackageJSON{PackageManager: "pnpm@1.2.3"}, - want: "nodejs-pnpm6", - wantErr: false, - }, - { - name: "finds pnpm from a package manager string", - projectDirectory: cwd, - pkg: &fs.PackageJSON{PackageManager: "pnpm@7.8.9"}, - want: "nodejs-pnpm", - wantErr: false, - }, - { - name: "finds yarn from a package manager string", - projectDirectory: cwd, - pkg: &fs.PackageJSON{PackageManager: "yarn@1.2.3"}, - want: "nodejs-yarn", - wantErr: false, - }, - { - name: "finds berry from a package manager string", - projectDirectory: cwd, - pkg: &fs.PackageJSON{PackageManager: "yarn@2.3.4"}, - want: "nodejs-berry", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotPackageManager, err := GetPackageManager(tt.projectDirectory, tt.pkg) - if (err != nil) != tt.wantErr { - t.Errorf("GetPackageManager() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotPackageManager.Name != tt.want { - t.Errorf("GetPackageManager() = %v, want %v", gotPackageManager.Name, tt.want) - } - }) - } -} - -func Test_readPackageManager(t *testing.T) { - tests := []struct { - name string - pkg *fs.PackageJSON - want string - wantErr bool - }{ - { - name: "finds npm from a package manager string", - pkg: &fs.PackageJSON{PackageManager: "npm@1.2.3"}, - want: "nodejs-npm", - wantErr: false, - }, - { - name: "finds pnpm6 from a package manager string", - pkg: &fs.PackageJSON{PackageManager: "pnpm@1.2.3"}, - want: "nodejs-pnpm6", - wantErr: false, - }, - { - name: "finds pnpm from a package manager string", - pkg: &fs.PackageJSON{PackageManager: "pnpm@7.8.9"}, - want: "nodejs-pnpm", - wantErr: false, - }, - { - name: "finds yarn from a package manager string", - pkg: &fs.PackageJSON{PackageManager: "yarn@1.2.3"}, - want: "nodejs-yarn", - wantErr: false, - }, - { - name: "finds berry from a package manager string", - pkg: &fs.PackageJSON{PackageManager: "yarn@2.3.4"}, - want: "nodejs-berry", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotPackageManager, err := readPackageManager(tt.pkg) - if (err != nil) != tt.wantErr { - t.Errorf("readPackageManager() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotPackageManager.Name != tt.want { - t.Errorf("readPackageManager() = %v, want %v", gotPackageManager.Name, tt.want) - } - }) - } -} - -func Test_GetWorkspaces(t *testing.T) { - type test struct { - name string - pm PackageManager - rootPath turbopath.AbsoluteSystemPath - want []string - wantErr bool - } - - cwd, _ := os.Getwd() - - repoRoot, err := fs.GetCwd(cwd) - assert.NilError(t, err, "GetCwd") - rootPath := map[string]turbopath.AbsoluteSystemPath{ - "nodejs-npm": repoRoot.UntypedJoin("../../../examples/with-yarn"), - "nodejs-berry": repoRoot.UntypedJoin("../../../examples/with-yarn"), - "nodejs-yarn": repoRoot.UntypedJoin("../../../examples/with-yarn"), - "nodejs-pnpm": repoRoot.UntypedJoin("../../../examples/basic"), - "nodejs-pnpm6": repoRoot.UntypedJoin("../../../examples/basic"), - } - - want := map[string][]string{ - "nodejs-npm": { - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")), - }, - "nodejs-berry": { - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")), - }, - "nodejs-yarn": { - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/docs/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/apps/web/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/eslint-config-custom/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/tsconfig/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/with-yarn/packages/ui/package.json")), - }, - "nodejs-pnpm": { - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/docs/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/web/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/eslint-config-custom/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/tsconfig/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/ui/package.json")), - }, - "nodejs-pnpm6": { - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/docs/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/apps/web/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/eslint-config-custom/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/tsconfig/package.json")), - filepath.ToSlash(filepath.Join(cwd, "../../../examples/basic/packages/ui/package.json")), - }, - } - - tests := make([]test, len(packageManagers)) - for i, packageManager := range packageManagers { - tests[i] = test{ - name: packageManager.Name, - pm: packageManager, - rootPath: rootPath[packageManager.Name], - want: want[packageManager.Name], - wantErr: false, - } - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotWorkspaces, err := tt.pm.GetWorkspaces(tt.rootPath) - - gotToSlash := make([]string, len(gotWorkspaces)) - for index, workspace := range gotWorkspaces { - gotToSlash[index] = filepath.ToSlash(workspace) - } - - if (err != nil) != tt.wantErr { - t.Errorf("GetWorkspaces() error = %v, wantErr %v", err, tt.wantErr) - return - } - sort.Strings(gotToSlash) - if !reflect.DeepEqual(gotToSlash, tt.want) { - t.Errorf("GetWorkspaces() = %v, want %v", gotToSlash, tt.want) - } - }) - } -} - -func Test_GetWorkspaceIgnores(t *testing.T) { - type test struct { - name string - pm PackageManager - rootPath turbopath.AbsoluteSystemPath - want []string - wantErr bool - } - - cwdRaw, err := os.Getwd() - assert.NilError(t, err, "os.Getwd") - cwd, err := fs.GetCwd(cwdRaw) - assert.NilError(t, err, "GetCwd") - want := map[string][]string{ - "nodejs-npm": {"**/node_modules/**"}, - "nodejs-berry": {"**/node_modules", "**/.git", "**/.yarn"}, - "nodejs-yarn": {"apps/*/node_modules/**", "packages/*/node_modules/**"}, - "nodejs-pnpm": {"**/node_modules/**", "**/bower_components/**", "packages/skip"}, - "nodejs-pnpm6": {"**/node_modules/**", "**/bower_components/**", "packages/skip"}, - } - - tests := make([]test, len(packageManagers)) - for i, packageManager := range packageManagers { - tests[i] = test{ - name: packageManager.Name, - pm: packageManager, - rootPath: cwd.UntypedJoin("fixtures"), - want: want[packageManager.Name], - wantErr: false, - } - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotWorkspaceIgnores, err := tt.pm.GetWorkspaceIgnores(tt.rootPath) - - gotToSlash := make([]string, len(gotWorkspaceIgnores)) - for index, ignore := range gotWorkspaceIgnores { - gotToSlash[index] = filepath.ToSlash(ignore) - } - - if (err != nil) != tt.wantErr { - t.Errorf("GetWorkspaceIgnores() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(gotToSlash, tt.want) { - t.Errorf("GetWorkspaceIgnores() = %v, want %v", gotToSlash, tt.want) - } - }) - } -} - func Test_CanPrune(t *testing.T) { type test struct { name string diff --git a/cli/internal/prune/prune.go b/cli/internal/prune/prune.go index 2dc541e86b150..4d35f652afaf5 100644 --- a/cli/internal/prune/prune.go +++ b/cli/internal/prune/prune.go @@ -41,7 +41,7 @@ func ExecutePrune(helper *cmdutil.Helper, executionState *turbostate.ExecutionSt p := &prune{ base, } - if err := p.prune(executionState.CLIArgs.Command.Prune); err != nil { + if err := p.prune(executionState.CLIArgs.Command.Prune, executionState.PackageManager); err != nil { logError(p.base.Logger, p.base.UI, err) return err } @@ -59,13 +59,13 @@ type prune struct { } // Prune creates a smaller monorepo with only the required workspaces -func (p *prune) prune(opts *turbostate.PrunePayload) error { +func (p *prune) prune(opts *turbostate.PrunePayload, packageManagerName string) error { rootPackageJSONPath := p.base.RepoRoot.UntypedJoin("package.json") rootPackageJSON, err := fs.ReadPackageJSON(rootPackageJSONPath) if err != nil { return fmt.Errorf("failed to read package.json: %w", err) } - ctx, err := context.BuildPackageGraph(p.base.RepoRoot, rootPackageJSON) + ctx, err := context.BuildPackageGraph(p.base.RepoRoot, rootPackageJSON, packageManagerName) if err != nil { return errors.Wrap(err, "could not construct graph") } diff --git a/cli/internal/run/run.go b/cli/internal/run/run.go index 0f41d54f7fed5..f33a793be4e47 100644 --- a/cli/internal/run/run.go +++ b/cli/internal/run/run.go @@ -50,7 +50,7 @@ func ExecuteRun(ctx gocontext.Context, helper *cmdutil.Helper, signalWatcher *si opts.runOpts.PassThroughArgs = passThroughArgs run := configureRun(base, opts, signalWatcher) - if err := run.run(ctx, tasks); err != nil { + if err := run.run(ctx, tasks, executionState); err != nil { base.LogError("run failed: %v", err) return err } @@ -148,21 +148,21 @@ type run struct { processes *process.Manager } -func (r *run) run(ctx gocontext.Context, targets []string) error { +func (r *run) run(ctx gocontext.Context, targets []string, executionState *turbostate.ExecutionState) error { startAt := time.Now() packageJSONPath := r.base.RepoRoot.UntypedJoin("package.json") rootPackageJSON, err := fs.ReadPackageJSON(packageJSONPath) if err != nil { - return fmt.Errorf("failed to read package.json: %w", err) + return err } isStructuredOutput := r.opts.runOpts.GraphDot || r.opts.runOpts.DryRunJSON var pkgDepGraph *context.Context if r.opts.runOpts.SinglePackage { - pkgDepGraph, err = context.SinglePackageGraph(r.base.RepoRoot, rootPackageJSON) + pkgDepGraph, err = context.SinglePackageGraph(rootPackageJSON, executionState.PackageManager) } else { - pkgDepGraph, err = context.BuildPackageGraph(r.base.RepoRoot, rootPackageJSON) + pkgDepGraph, err = context.BuildPackageGraph(r.base.RepoRoot, rootPackageJSON, executionState.PackageManager) } if err != nil { var warnings *context.Warnings diff --git a/cli/internal/turbostate/turbostate.go b/cli/internal/turbostate/turbostate.go index 710c886018c72..4efe4058e6eb4 100644 --- a/cli/internal/turbostate/turbostate.go +++ b/cli/internal/turbostate/turbostate.go @@ -4,7 +4,6 @@ package turbostate import ( - "github.com/vercel/turbo/cli/internal/fs" "github.com/vercel/turbo/cli/internal/util" ) @@ -93,7 +92,6 @@ type ParsedArgsFromRust struct { type ExecutionState struct { APIClientConfig APIClientConfig `json:"api_client_config"` PackageManager string `json:"package_manager"` - RootPackageJson fs.PackageJSON `json:"root_package_json"` CLIArgs ParsedArgsFromRust `json:"cli_args"` } diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index be78be9e4ddac..c59e8b53dbb14 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -73,10 +73,10 @@ url = "2.3.1" const_format = "0.2.30" go-parse-duration = "0.1.1" is-terminal = "0.4.7" -owo-colors.workspace = true -tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } node-semver = "2.1.0" +owo-colors.workspace = true regex.workspace = true +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing.workspace = true turbo-updater = { workspace = true } turbopath = { workspace = true } diff --git a/crates/turborepo-lib/src/execution_state.rs b/crates/turborepo-lib/src/execution_state.rs index 0f83f14d2c992..3b1de78e038b4 100644 --- a/crates/turborepo-lib/src/execution_state.rs +++ b/crates/turborepo-lib/src/execution_state.rs @@ -9,7 +9,6 @@ use crate::{ pub struct ExecutionState<'a> { pub api_client_config: APIClientConfig<'a>, package_manager: PackageManager, - root_package_json: PackageJson, pub cli_args: &'a Args, } @@ -25,14 +24,17 @@ pub struct APIClientConfig<'a> { pub timeout: u64, } -impl<'a> TryFrom<&'a mut CommandBase> for ExecutionState<'a> { +impl<'a> TryFrom<&'a CommandBase> for ExecutionState<'a> { type Error = anyhow::Error; - fn try_from(base: &'a mut CommandBase) -> Result { + fn try_from(base: &'a CommandBase) -> Result { let root_package_json = PackageJson::load(&AbsoluteSystemPathBuf::new( base.repo_root.join("package.json"), - )?)?; - let package_manager = PackageManager::get_package_manager(base, &root_package_json)?; + )?) + .ok(); + + let package_manager = + PackageManager::get_package_manager(base, root_package_json.as_ref())?; let repo_config = base.repo_config()?; let user_config = base.user_config()?; @@ -51,7 +53,6 @@ impl<'a> TryFrom<&'a mut CommandBase> for ExecutionState<'a> { Ok(ExecutionState { api_client_config, package_manager, - root_package_json, cli_args: base.args(), }) } diff --git a/crates/turborepo-lib/src/package_json.rs b/crates/turborepo-lib/src/package_json.rs index c99b045c005e8..665dcba6ce1a8 100644 --- a/crates/turborepo-lib/src/package_json.rs +++ b/crates/turborepo-lib/src/package_json.rs @@ -1,30 +1,10 @@ -use std::collections::{BTreeMap, HashMap}; - use anyhow::Result; use serde::{Deserialize, Serialize}; -use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPathBuf}; +use turbopath::AbsoluteSystemPathBuf; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct PackageJson { - name: String, - version: String, - pub scripts: BTreeMap, - dependencies: BTreeMap, - dev_dependencies: BTreeMap, - optional_dependencies: BTreeMap, - peer_dependencies: BTreeMap, pub package_manager: Option, - os: Vec, - workspaces: Vec, - private: bool, - package_json_path: Option, - dir: Option, - internal_deps: Vec, - unresolved_external_deps: BTreeMap, - #[serde(alias = "turbo")] - pub(crate) legacy_turbo_config: Option<()>, - #[serde(flatten)] - raw_json: HashMap, } impl PackageJson { diff --git a/crates/turborepo-lib/src/package_manager.rs b/crates/turborepo-lib/src/package_manager.rs index 5ca0e78887c59..1d581d3d35e01 100644 --- a/crates/turborepo-lib/src/package_manager.rs +++ b/crates/turborepo-lib/src/package_manager.rs @@ -49,6 +49,7 @@ impl From for Vec { } #[derive(Debug, Serialize, PartialEq, Eq, Clone)] +#[serde(rename_all = "lowercase")] pub enum PackageManager { Berry, Npm, @@ -152,11 +153,13 @@ impl PackageManager { })) } - pub fn get_package_manager(base: &mut CommandBase, pkg: &PackageJson) -> Result { + pub fn get_package_manager(base: &CommandBase, pkg: Option<&PackageJson>) -> Result { // We don't surface errors for `read_package_manager` as we can fall back to // `detect_package_manager` - if let Ok(Some(package_manager)) = Self::read_package_manager(pkg) { - return Ok(package_manager); + if let Some(package_json) = pkg { + if let Ok(Some(package_manager)) = Self::read_package_manager(package_json) { + return Ok(package_manager); + } } Self::detect_package_manager(base) @@ -198,7 +201,7 @@ impl PackageManager { Ok(manager) } - fn detect_package_manager(base: &mut CommandBase) -> Result { + fn detect_package_manager(base: &CommandBase) -> Result { let mut detected_package_managers = vec![]; let project_directory = AbsoluteSystemPathBuf::new(&base.repo_root)?; let npm_lockfile = project_directory diff --git a/turborepo-tests/integration/tests/package_manager.t b/turborepo-tests/integration/tests/package_manager.t new file mode 100644 index 0000000000000..a21ec87da9245 --- /dev/null +++ b/turborepo-tests/integration/tests/package_manager.t @@ -0,0 +1,35 @@ +Setup + $ . ${TESTDIR}/../../helpers/setup.sh + $ . ${TESTDIR}/_helpers/setup_monorepo.sh $(pwd) basic_monorepo "npm@8.19.4" + +Run test run + $ ${TURBO} run build --__test-run | jq .package_manager + "npm" + +Set package manager to yarn in package.json + $ jq '.package_manager = "yarn@1.22.7"' package.json > package.json.tmp && mv package.json.tmp package.json + +Run test run + $ ${TURBO} run build --__test-run | jq .package_manager + "yarn" + +Set package manager to berry in package.json + $ jq '.package_manager = "yarn@2.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json + +Run test run + $ ${TURBO} run build --__test-run | jq .package_manager + "berry" + +Set package manager to pnpm6 in package.json + $ jq '.package_manager = "pnpm@6.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json + +Run test run + $ ${TURBO} run build --__test-run | jq .package_manager + "pnpm6" + +Set package manager to pnpm in package.json + $ jq '.package_manager = "pnpm@7.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json + +Run test run + $ ${TURBO} run build --__test-run | jq .package_manager + "pnpm"