Skip to content

feat: add frozen-lockfile and ci install modes - #1

Open
sebdanielsson wants to merge 4 commits into
mainfrom
claude/pnpm-install-options-82heax
Open

feat: add frozen-lockfile and ci install modes#1
sebdanielsson wants to merge 4 commits into
mainfrom
claude/pnpm-install-options-82heax

Conversation

@sebdanielsson

@sebdanielsson sebdanielsson commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Closes pnpm#8. Closes pnpm#10.

What this adds

The install input was a boolean. It now picks which install command runs:

install command
true (default) or install pnpm install
frozen-lockfile pnpm install --frozen-lockfile
ci pnpm ci
false nothing

true and false behave as before, so existing workflows keep working.

How it works

src/inputs/index.ts parses the input into InstallMode | false instead of a boolean. Unknown and empty values throw. An empty value is an error because the action.yml default only applies when the input is left out, so an expression that resolves to an empty string would otherwise run the default install without anyone asking for it.

src/pnpm-install/index.ts builds the argument list from the mode: install, install --frozen-lockfile, or ci. When the runtime input is set, --no-runtime is appended, same as before, and this works on all three modes.

The install: false check moved out of src/index.ts and into runPnpmInstall, so the skip decision lives in one place.

pnpm ci has existed since pnpm v11, which is the oldest version this action installs, so no version check is needed.

Why frozen-lockfile is a separate mode

pnpm does not enable --frozen-lockfile on its own in CI. Checked against 12.0.0-beta.4: with CI=true and a lockfile that does not match package.json, plain pnpm install exits 0 and rewrites the lockfile. So it has to be opt-in.

About the default

Issue pnpm#10 also says frozen installs should be the default. This PR does not change the default, since that would break workflows that rely on the lockfile being updated. It only makes the strict modes available. Let me know if you want the default flipped instead.

One caveat on pnpm ci

A clean script in package.json overrides pnpm clean, so pnpm ci runs that script and node_modules is not removed. That is pnpm's behaviour, not something the action can change. It is written down in action.yml and the README so nobody picks ci expecting a guaranteed clean tree.

Tests

Three jobs added to test.yaml:

  • install: frozen-lockfile — installs from a matching lockfile, then adds a dependency that is not in the lockfile and checks the step fails and the lockfile is byte-identical afterwards.
  • install: ci — plants a stale directory in node_modules and checks it is gone afterwards while the real dependency is present. devEngines.runtime is set to a different node version than the runtime input, so this job also covers --no-runtime.
  • install: rejects an unknown valueinstall: frozen and install: '' both fail the step, while a valid value on the same runner passes. The passing step is there so the failures cannot be blamed on the network or the runner.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FQ4xoewnc8tAGuQ8cyawRC

Copilot AI lite review requested due to automatic review settings August 7, 2026 22:10

Copilot AI 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.

Pull request overview

This PR extends the action’s install input from a boolean into a mode selector, enabling stricter dependency installation behaviors (frozen-lockfile and ci) while preserving backward compatibility with existing true/false usage.

Changes:

  • Replaced install: boolean with install: InstallMode | false, adding parsing/validation that hard-fails on unknown values.
  • Updated install execution to support pnpm install, pnpm install --frozen-lockfile, and pnpm ci, while still appending --no-runtime when an explicit runtime input is provided.
  • Added CI workflow jobs covering the new install modes and invalid input rejection; updated docs and action metadata accordingly.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/pnpm-install/index.ts Adds install-mode argument building and updates logging/error messages for the selected pnpm command.
src/inputs/index.ts Introduces InstallMode, implements install input parsing/validation, and updates the Inputs contract.
src/index.ts Always invokes the install step (which now self-skips when install: false).
README.md Documents the new install modes and provides usage examples.
action.yml Updates the install input description to reflect the new mode behavior and semantics.
.github/workflows/test.yaml Adds workflow coverage for install: frozen-lockfile, install: ci, and invalid install mode handling.
Suppressed comments (1)

src/pnpm-install/index.ts:35

  • spawnSync can return { status: null, signal: 'SIGTERM' } when the pnpm process is terminated by a signal. The current if (status) check will treat null as success and not fail the action in that case. Consider capturing signal and failing when status !== 0, using the signal as the failure reason when present.
  const { error, status } = spawnSync('pnpm', args, {
    stdio: 'inherit',
    cwd: GITHUB_WORKSPACE,
    shell: true,
  })

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/pnpm-install/index.ts:17

  • command is built from installArgs, but the actual executed args may include --no-runtime (when inputs.runtime is set). This makes the skip logs and the failure message (${command} exited...) inaccurate (e.g. it will report pnpm ci instead of pnpm ci --no-runtime). Build command from the final args array instead.
  const installArgs = buildArgs(inputs.install)
  const command = `pnpm ${installArgs.join(' ')}`

@sebdanielsson
sebdanielsson force-pushed the claude/pnpm-install-options-82heax branch from efdf886 to 0f24b57 Compare August 7, 2026 22:42
The `install` input now selects which install runs: `true`/`install`
(`pnpm install`, unchanged default), `frozen-lockfile`
(`pnpm install --frozen-lockfile`), `ci` (`pnpm ci`), or `false` to skip.

Closes pnpm#8

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FQ4xoewnc8tAGuQ8cyawRC
@sebdanielsson
sebdanielsson force-pushed the claude/pnpm-install-options-82heax branch from 0f24b57 to fc2e94d Compare August 7, 2026 22:47
claude added 3 commits August 8, 2026 10:22
Review feedback on pnpm#23:

- `command` was built before `--no-runtime` was appended, so a failing
  install reported `pnpm ci` while the log showed `pnpm ci --no-runtime`.
  Build it from the final args so every message matches.
- `if (status)` treated a signal-terminated install as success, since
  spawnSync reports `status: null` with no `error` in that case. Fail on
  `signal`, and use `status !== 0`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FQ4xoewnc8tAGuQ8cyawRC
…ile`

Review feedback on pnpm#23. The value now describes what it guarantees — the
install must be fully described by pnpm-lock.yaml — rather than naming the
pnpm flag it happens to pass. The flag itself is unchanged.

Docs now spell out that this is not the same as pnpm's own CI default: pnpm 11
only blocks updates to an existing lockfile, and pnpm 12 does not apply the CI
default at all as of 12.0.0-rc.3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FQ4xoewnc8tAGuQ8cyawRC
…e run

The checksum was recorded after the successful install, so only the failing
run was ever compared against it. Record it right after the lockfile is
written instead, and assert it on both runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FQ4xoewnc8tAGuQ8cyawRC
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.

Support installing frozen lock files Option for using pnpm ci automatically

3 participants