Skip to content

feat: install a JavaScript workspace's dependencies before the analysis - #144

Draft
Svilen-Stefanov wants to merge 2 commits into
refactor/review-baseline-pipelinefrom
feat/install-workspace-dependencies
Draft

Svilen-Stefanov wants to merge 2 commits into
refactor/review-baseline-pipelinefrom
feat/install-workspace-dependencies

Conversation

@Svilen-Stefanov

Copy link
Copy Markdown
Contributor

Stacked on #143. Needs the Core release that contains CodeBoarding #639; with the current codeboarding==0.14.5 pin, the variable it sets is ignored.

Why

A call from one package of a JavaScript monorepo into another resolves only once the packages are installed, so the Action's fresh checkout showed no calls between them. On opencode, installing took package pairs with calls from 1 to 45.

What changes

Core now does the install itself when CODEBOARDING_INSTALL_DEPENDENCIES is set, for the head checkout and the merge-base worktree alike. The Action provides the rest:

  • Input install_dependencies (default true).
  • scripts/action/prepare-dependencies.sh:
    • detects a workspace and its package manager (the packageManager pin, else the lockfile's), using the same rules as Core;
    • skips Yarn Plug'n'Play;
    • points every package manager's cache (BUN_INSTALL_CACHE_DIR, npm_config_store_dir, YARN_CACHE_FOLDER, npm_config_cache) at one store under RUNNER_TEMP;
    • exports the variable.
  • Package manager: Bun from oven-sh/setup-bun@v2 at the pinned version; pnpm and Yarn from corepack enable.
  • The store is restored with actions/cache/restore@v4, keyed by the lockfile's hash, falling back to the previous lockfile's store.
  • Only sync saves it (actions/cache/save@v4). A cache saved inside a pull request is visible to no other pull request, so saving there would only use up the repository's quota.
  • README: a "JavaScript workspaces" section covering what runs, the cache size, Plug'n'Play, private registries (set the token .npmrc reads in the job's env) and the off switch.

Impact

  • Time: with a warm store an install is a link step. Locally, opencode took 5 s from a warm cache against 39–352 s cold. I haven't measured it on a GitHub-hosted runner yet.
  • Cache: about 0.8 GB compressed for opencode's store, one entry per lockfile, within the repository's 10 GB of free Actions cache. Repositories already near that limit lose their own least-recently-used entries first, which the README says.
  • Repositories that aren't JavaScript workspaces: only the preparation step runs, and it skips in under a second.

Tests

  • New tests/test_prepare_dependencies.py (12 tests): detection per package manager and pin, single packages, missing lockfiles, Plug'n'Play and the off switch; plus the wiring (input default, only sync saves, store restored before both analysis steps).
  • shellcheck is clean.
  • Suite: 250 passed locally. The 3 test_provider_table_drift failures compare against the Core installed on this machine, fail without this change too, and pass in the core-compatibility job against the pin.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T12:13:55.986086Z 68d0aef New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

A call from one package of a JavaScript monorepo into another resolves only
once the packages are installed, so a fresh checkout showed no calls between
them. Core now installs them itself when CODEBOARDING_INSTALL_DEPENDENCIES is
set (no install scripts, frozen lockfile, hard timeout), for the head
checkout and the merge-base worktree alike. The action provides the rest:

- `install_dependencies` (default true) turns it on.
- prepare-dependencies.sh detects a workspace and its package manager (the
  `packageManager` pin, else the lockfile's), skips Yarn Plug'n'Play, and
  points every package manager's cache at one store under RUNNER_TEMP.
- Bun comes from oven-sh/setup-bun at the pinned version; pnpm and Yarn
  from corepack.
- The store is restored per lockfile, falling back to the previous one, and
  saved only by sync: a cache saved inside a pull request is visible to no
  other, so it would only use up the repository's quota.

The install needs the Core release that adds it; with the current pin the
variable is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Svilen-Stefanov
Svilen-Stefanov force-pushed the feat/install-workspace-dependencies branch from 062a1a9 to bebc977 Compare October 11, 2026 09:28
@codeboarding-review

codeboarding-review Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

CodeBoarding review

Status: 0 changed components (no analysed file changed)

See the full change in CodeBoarding.

graph LR
    n_action_scripts["action_scripts"]
    classDef added fill:#1f883d,stroke:#0b5d23,color:#ffffff;
    classDef modified fill:#bf8700,stroke:#7d4e00,color:#ffffff;
    classDef deleted fill:#cf222e,stroke:#82071e,color:#ffffff,stroke-dasharray:5 3;
Loading

download artifacts · run 38138153193

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 062a1a9448

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/action/prepare-dependencies.sh Outdated

mkdir -p "$STORE_DIR"
{
echo "CODEBOARDING_INSTALL_DEPENDENCIES=1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bump the engine before enabling dependency installation

This export is ignored by the still-pinned codeboarding==0.14.5, so the default-on input, package-manager setup, and cache steps never cause dependencies to be installed and the advertised workspace-call improvement is absent in every run. Ship this only with the Core release that consumes CODEBOARDING_INSTALL_DEPENDENCIES, updating the pin in action.yml; this repository explicitly notes that engine changes reach users only through such a pin bump.

AGENTS.md reference: AGENTS.md:L13-L17

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This ships with the Core release that includes CODEBOARDING_INSTALL_DEPENDENCIES (CodeBoarding#639), together with the codeboarding== pin bump in this PR. I've moved it to draft until that release exists.

Comment thread action.yml
install_dependencies:
description: "Install the analyzed repository's JavaScript workspace dependencies before the analysis (no install scripts, frozen lockfile), so calls between its packages resolve. The package store is cached per lockfile. Set to false to skip."
required: false
default: 'true'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid installing fork-controlled packages with analysis secrets

Once the required engine pin enables this default-on path, a trusted /codeboarding command on a fork lets the fork control package-manager startup while with-auth.sh has exported direct-provider credentials. Disabling lifecycle scripts is insufficient: a checked-in Yarn plugin from .yarnrc.yml executes while Yarn starts, before install-script policy applies, and analogous manager hooks can inspect the environment or the restored dependency cache. Fork reviews should skip dependency installation or run it in an isolated environment without analysis/private-registry credentials or trusted caches.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 68d0aef. A fork's pull request installs nothing: the step skips before it exports anything. Core also removes model-provider keys and the runner's OIDC and runtime tokens from the install's environment, and runs pnpm with --ignore-pnpmfile (CodeBoarding#639). Same-repository pull requests still run a repository's own Yarn plugins, but that code comes from someone with write access.

Comment thread action.yml
Comment on lines +153 to +156
install_dependencies:
description: "Install the analyzed repository's JavaScript workspace dependencies before the analysis (no install scripts, frozen lockfile), so calls between its packages resolve. The package store is cached per lockfile. Set to false to skip."
required: false
default: 'true'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include dependency installation in the analysis cache identity

Changing install_dependencies from false to true does not change the configuration hash constructed by resolve-cache-keys.sh, so a review or sync can reuse analysis state produced without node_modules. When no analyzed source changed, the incremental run can retain the old graph and continue omitting workspace calls even though installation is now enabled. Include this setting—and any dependency-resolution fingerprint required by Core—in state compatibility, or force a full analysis when it changes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handled in Core (CodeBoarding#639, 2b3c542e). The static-analysis cache now records the installed dependency state, and a warm start whose state differs re-reads every file while keeping the cache as the incremental base. Turning the input on, and any later lockfile change, forces that full pass without any config-hash change here.

Comment on lines +47 to +50
declared = manifest.get("packageManager") if isinstance(manifest, dict) else None
match = re.match(r"^(bun|pnpm|yarn|npm)@([0-9][^+\s]*)", declared) if isinstance(declared, str) else None
if match:
manager, version = match.group(1), match.group(2)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor npm packageManager version pins

For a workspace declaring packageManager: "npm@<version>", this records the requested version but no later step consumes it: Bun alone receives steps.deps.outputs.version, and the corepack step is restricted to pnpm and Yarn. The engine therefore uses the runner's preinstalled npm, which can reject or reinterpret a frozen lockfile created by the pinned version. Set up the declared npm version as well, or do not claim that npm pins are honored.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68d0aef: a pinned npm is installed with npm install --global npm@<version> before the analysis.

Comment thread scripts/action/prepare-dependencies.sh Outdated
}

[ "${INSTALL_DEPENDENCIES:-true}" = true ] || skip "install_dependencies is false"
[ -f "$CHECKOUT_DIR/package.json" ] || skip "no package.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prepare dependencies separately for the merge base

When a pull-request head removes its root package.json or otherwise stops being a workspace, this check disables dependency installation globally before the merge-base worktree is created. If no published base is reusable, the later baseline analysis therefore examines a merge base that may still be a JavaScript workspace without installing its dependencies, omitting the very cross-package calls this change is meant to expose and producing an inaccurate comparison. Make the install decision for each checkout independently, or let Core detect the workspace in each worktree.

AGENTS.md reference: AGENTS.md:L48-L51

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68d0aef. CODEBOARDING_INSTALL_DEPENDENCIES is now exported whenever the input is on and the pull request isn't from a fork, and Core decides for each checkout. The head's detection only chooses which package manager to set up and cache. A merge base that uses another package manager falls back to Core's npm exec path.

Comment on lines +59 to +61
berry = version != "-" and not version.startswith("1.")
linker = re.search(r"^\s*nodeLinker:\s*['\"]?([\w-]+)", yarnrc.read_text(errors="ignore"), re.M) if yarnrc.is_file() else None
if (linker and linker.group(1) == "pnp") or (not linker and (yarnrc.is_file() or berry)):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detect Yarn Classic Plug'n'Play workspaces

A Yarn 1 workspace can enable Plug'n'Play through installConfig.pnp in package.json (and commonly has a .pnp.js) without any .yarnrc.yml. For that valid configuration berry is false and linker is absent, so this branch enables an install even though it creates no node_modules, contrary to the documented promise to skip Plug'n'Play repositories. Check the Yarn Classic PnP manifest setting or marker file before preparing the install.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68d0aef, and in Core: installConfig.pnp, .pnp.cjs or .pnp.js now skip the setup.

Comment thread scripts/action/prepare-dependencies.sh Outdated
}

[ "${INSTALL_DEPENDENCIES:-true}" = true ] || skip "install_dependencies is false"
[ -f "$CHECKOUT_DIR/package.json" ] || skip "no package.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow pnpm workspaces without a root package.json

A pnpm-workspace.yaml is sufficient to define a pnpm workspace, and pnpm install works from such a root even when only the member packages have manifests. This early exit makes the later explicit pnpm-workspace.yaml check unreachable for that valid layout, so its dependencies are never installed and cross-package calls remain unresolved. Treat the workspace file plus pnpm-lock.yaml as sufficient when the root manifest is absent.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 68d0aef, and in Core: pnpm-workspace.yaml plus pnpm-lock.yaml is now enough.

…e, set up a pinned npm

- a fork's pull request installs nothing: its package manager would start with the
  analysis credentials in reach
- CODEBOARDING_INSTALL_DEPENDENCIES is exported whenever the input is on, so Core decides for
  the head and the merge base on their own; the head's detection only picks what to set up
- a pinned npm is installed over the runner's
- npm-shrinkwrap.json, pnpm workspaces without a root package.json, and Yarn 1
  Plug'n'Play (installConfig.pnp, .pnp.cjs) are detected as Core detects them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Svilen-Stefanov
Svilen-Stefanov marked this pull request as draft October 11, 2026 12:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 68d0aefca5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread action.yml
run: "$GITHUB_ACTION_PATH/scripts/action/prepare-dependencies.sh"

- name: Setup Bun for dependency install
if: steps.guard.outputs.skip != 'true' && steps.deps.outputs.manager == 'bun'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Set up the merge base's package manager too

When the PR head removes its workspace or changes from Bun to another manager, steps.deps.outputs.manager is empty or names only the head manager, so this condition skips Bun setup even though Core subsequently analyzes a Bun-based merge-base worktree; the baseline install then lacks the required binary and its cross-package calls can disappear from the comparison. The updated no_setup path is fresh evidence that the earlier issue remains: it now exports CODEBOARDING_INSTALL_DEPENDENCIES, but still emits an empty manager that skips every setup step. Determine and provision the manager for each checkout, or otherwise ensure all managers Core may select are available.

AGENTS.md reference: AGENTS.md:L49-L52

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant