diff --git a/crates/turborepo-lockfiles/fixtures/pnpm-injected-file.yaml b/crates/turborepo-lockfiles/fixtures/pnpm-injected-file.yaml new file mode 100644 index 0000000000000..dd964903676dc --- /dev/null +++ b/crates/turborepo-lockfiles/fixtures/pnpm-injected-file.yaml @@ -0,0 +1,18 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + services/application: + dependencies: + library: + specifier: workspace:^ + version: file:../../../libraries/library + dependenciesMeta: + library: + injected: true + +packages: {} +snapshots: {} \ No newline at end of file diff --git a/crates/turborepo-lockfiles/fixtures/pnpm-injected-link.yaml b/crates/turborepo-lockfiles/fixtures/pnpm-injected-link.yaml new file mode 100644 index 0000000000000..8b5602a5912fb --- /dev/null +++ b/crates/turborepo-lockfiles/fixtures/pnpm-injected-link.yaml @@ -0,0 +1,29 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + devDependencies: + turbo: + specifier: 2.0.0-canary.0 + version: 2.0.0-canary.0 + + services/application: + dependencies: + library: + specifier: workspace:^ + version: link:../../../libraries/library + dependenciesMeta: + library: + injected: true + +packages: + turbo@2.0.0-canary.0: + resolution: {integrity: sha512-test} + hasBin: true + +snapshots: + turbo@2.0.0-canary.0: {} \ No newline at end of file diff --git a/crates/turborepo-lockfiles/src/pnpm/data.rs b/crates/turborepo-lockfiles/src/pnpm/data.rs index 9c0cbf8244836..7d2077a6dde11 100644 --- a/crates/turborepo-lockfiles/src/pnpm/data.rs +++ b/crates/turborepo-lockfiles/src/pnpm/data.rs @@ -174,6 +174,7 @@ pub struct PackageResolution { struct LockfileSettings { auto_install_peers: Option, exclude_links_from_lockfile: Option, + inject_workspace_packages: Option, } impl PnpmLockfile { @@ -473,10 +474,14 @@ impl crate::Lockfile for PnpmLockfile { .find_resolution(dependency) .ok_or_else(|| Error::MissingInjectedPackage(dependency.clone()))?; - let entry = self - .get_packages(version) - .ok_or_else(|| crate::Error::MissingPackage(version.into()))?; - pruned_packages.insert(version.to_string(), entry.clone()); + // Skip adding to packages if this is a local workspace link (link: or file: protocol) + // These don't have entries in the packages section as they're just symlinks + if !version.starts_with("link:") && !version.starts_with("file:") { + let entry = self + .get_packages(version) + .ok_or_else(|| crate::Error::MissingPackage(version.into()))?; + pruned_packages.insert(version.to_string(), entry.clone()); + } } } @@ -649,6 +654,10 @@ mod tests { const PNPM6_TURBO: &[u8] = include_bytes!("../../fixtures/pnpm6turbo.yaml").as_slice(); const PNPM8_TURBO: &[u8] = include_bytes!("../../fixtures/pnpm8turbo.yaml").as_slice(); const PNPM10_PATCH: &[u8] = include_bytes!("../../fixtures/pnpm-10-patch.lock").as_slice(); + const PNPM_INJECTED_LINK: &[u8] = + include_bytes!("../../fixtures/pnpm-injected-link.yaml").as_slice(); + const PNPM_INJECTED_FILE: &[u8] = + include_bytes!("../../fixtures/pnpm-injected-file.yaml").as_slice(); use super::*; use crate::{Lockfile, Package}; @@ -1479,4 +1488,30 @@ c: crate::Error::MissingWorkspace("apps/docs".to_string()).to_string() ); } + + #[test] + fn test_injected_link_dependency_subgraph() { + let lockfile = PnpmLockfile::from_bytes(PNPM_INJECTED_LINK).unwrap(); + + // This should not error - injected link: dependencies shouldn't require package entries + let result = lockfile.subgraph(&["services/application".to_string()], &[]); + + assert!( + result.is_ok(), + "Subgraph should succeed for injected link: dependencies" + ); + } + + #[test] + fn test_injected_file_dependency_subgraph() { + let lockfile = PnpmLockfile::from_bytes(PNPM_INJECTED_FILE).unwrap(); + + // This should not error - injected file: dependencies shouldn't require package entries + let result = lockfile.subgraph(&["services/application".to_string()], &[]); + + assert!( + result.is_ok(), + "Subgraph should succeed for injected file: dependencies" + ); + } }