Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request replaces hardcoded package compilation in the lockfile check action with a dynamic script that resolves and compiles all in-repo linked workspace packages, including deep links. It introduces a Node.js helper script to list these directories by parsing workspace projects and scanning node_modules symlinks, accompanied by comprehensive unit tests. Review feedback recommends improving the robustness of the script by adding error handling and directory checks when reading the .pnpm store, and validating the JSON structure parsed from standard input to prevent runtime crashes.
| for (const name of fs.existsSync(store) ? fs.readdirSync(store) : []) { | ||
| // `.pnpm/node_modules` hoists every package for pnpm's own resolution; | ||
| // nothing in the repository loads from it. | ||
| if (name !== 'node_modules') { | ||
| nodeModulesDirs.push(path.join(store, name, 'node_modules')); | ||
| } | ||
| } |
There was a problem hiding this comment.
Using fs.existsSync alone does not guarantee that the path is a directory. If .pnpm exists but is a file or cannot be read, fs.readdirSync will throw an unhandled exception. Verifying that it is a directory using fs.statSync().isDirectory() and wrapping the operation in a try...catch block makes the file system operations more robust.
let storeEntries = [];
try {
if (fs.statSync(store).isDirectory()) {
storeEntries = fs.readdirSync(store);
}
} catch {
// Ignore if .pnpm directory does not exist or cannot be read.
}
for (const name of storeEntries) {
// `.pnpm/node_modules` hoists every package for pnpm's own resolution;
// nothing in the repository loads from it.
if (name !== 'node_modules') {
nodeModulesDirs.push(path.join(store, name, 'node_modules'));
}
}
| process.stdin.on('end', () => { | ||
| const projectDirs = JSON.parse(input).map(project => project.path); | ||
| for (const dir of linkedWorkspaceDirs(process.cwd(), projectDirs)) { | ||
| console.log(dir); | ||
| } | ||
| }); |
There was a problem hiding this comment.
When parsing JSON from external processes or APIs, it is important to validate that the input is not empty and that the parsed object has the expected structure (e.g., an array of objects with a path property) to prevent runtime crashes. This adheres to the general rule of validating JSON API responses before accessing their keys.
process.stdin.on('end', () => {
let projectDirs = [];
try {
if (input.trim()) {
const parsed = JSON.parse(input);
if (Array.isArray(parsed)) {
projectDirs = parsed
.filter(project => project && typeof project === 'object' && typeof project.path === 'string')
.map(project => project.path);
}
}
} catch (err) {
console.error('Failed to parse workspace projects JSON:', err);
process.exit(1);
}
for (const dir of linkedWorkspaceDirs(process.cwd(), projectDirs)) {
console.log(dir);
}
});
References
- When parsing and iterating over JSON API responses, validate that the root structure is of the expected type (e.g., a list) and that individual elements are mappings before accessing their keys to prevent runtime crashes on unexpected or error responses.
The "Link In-Repo Workspace Packages" step links matching in-repo packages after the frozen install, then restores the committed lockfile, so turbo doesn't compile them. The step compiles gaxios and teeny-request itself. A devDependency of @google-cloud/bigquery on @google-cloud/bigquery-storage is satisfied by handwritten/bigquery-storage, so the step links it, but nothing compiles it. Requiring it then fails with MODULE_NOT_FOUND because build/ doesn't exist. Compile it alongside gaxios and teeny-request.
73edb7d to
9bfb931
Compare
Context & Problem
The "Link In-Repo Workspace Packages" step that #9569 added to
pnpm-lockfile-checklinks matching in-repo packages after the frozen install, then restores the committed lockfile, so turbo doesn't compile them. The step compilesgaxiosandteeny-requestitself. The Arrow PRs for@google-cloud/bigquery(#9596–#9605) add a devDependency on@google-cloud/bigquery-storage, whichhandwritten/bigquery-storagesatisfies, so the step links it to source without abuild/directory and requiring it fails withMODULE_NOT_FOUNDin every unit and Bun job.Summary of Changes
.github/actions/pnpm-lockfile-check/action.yaml: compilehandwritten/bigquery-storagein the link step, alongsidegaxiosandteeny-request.Verification
Ran the step's commands locally after
pnpm install --frozen-lockfile --ignore-scripts:a7565174ed):@google-cloud/bigqueryunit tests go from 13 failing to 547 passing.a256f90f24), the top of the stack: 576 passing.