Skip to content

fix: temp dir locking#339

Merged
zkochan merged 1 commit into
masterfrom
pnpm_inprogress
Aug 31, 2016
Merged

fix: temp dir locking#339
zkochan merged 1 commit into
masterfrom
pnpm_inprogress

Conversation

@zkochan

@zkochan zkochan commented Aug 31, 2016

Copy link
Copy Markdown
Member

This was broken by commit 0c247a1

The fix is just reverting the unnecessary changes that have broken the tmp dir locking.

Issue introduced in v0.25.0

This was broken by commit 0c247a1
The fix is just reverting the unnecessary changes that have broken
the tmp dir locking.

PR #339
@zkochan

zkochan commented Aug 31, 2016

Copy link
Copy Markdown
Member Author

I don't know currently a fast, easy way to cover this with tests, but the issue is real. It was sometimes causing errors during pnpm install on pnpm. I started noticing them when we started to use pnpm to install its dependencies.

So I guess it is sometimes causing fails for packages with many dependencies. Better to publish it ASAP.

I tested it manually by running pnpm install many-many times on pnpm.

I'll create a separate issue for covering this with tests.

@zkochan zkochan merged commit 1366186 into master Aug 31, 2016
@zkochan zkochan deleted the pnpm_inprogress branch September 3, 2016 20:28
pull Bot pushed a commit to dwongdev/pnpm that referenced this pull request May 14, 2026
pnpm#349)

* feat(reporter): add NDJSON reporting engine with pnpm:stage smoke test

Introduces `pacquet-reporter` carrying the typed `LogEvent` enum, the
no-`self` `Reporter` capability trait per pnpm#339, and `NdjsonReporter` /
`SilentReporter` implementations. Adds the `--reporter=ndjson|silent`
flag and threads a `R: Reporter` generic through `Install::run`,
emitting `pnpm:stage` `importing_started` / `importing_done` to
bracket the install — one channel wired end-to-end as a smoke test
for the schema-mirror approach.

The wire format mirrors what `@pnpm/core-loggers` defines and
`@pnpm/cli.default-reporter` consumes under `pnpm --reporter=ndjson`.

Engine only. The JS-reporter spawn-and-pipe (`--reporter=default`),
the backfill of missing log events in already-ported code (pnpm#347), and
the porting convention in AGENTS.md (pnpm#346) land in follow-up PRs. The
default reporter is `silent` until the spawn-and-pipe exists, so user-
facing output is unchanged.

Refs pnpm#345. Design: pnpm#344.

* docs(package-manager): name pnpm's `lockfileDir` and link findWorkspaceDir

Upstream emits stage events with `prefix: lockfileDir` — the directory
holding `pnpm-lock.yaml`, which collapses to the workspace root when a
workspace is present. The previous comment described the *result* in
pacquet's no-workspace world but didn't name the upstream concept or
point at the helper to mirror once workspaces land. Replacing the
comment with a TODO that links `findWorkspaceDir` makes the migration
path explicit so the next person editing this site doesn't have to
re-derive it.

No behavior change.

* fix(cli): make --reporter accepted on either side of the subcommand

Adding `global = true` to the clap attribute lets users write either
`pacquet --reporter=ndjson install` or `pacquet install --reporter=ndjson`,
matching pnpm. Without it the flag is parsed by the top-level `CliArgs`
only, so a sub-command-side use ("pacquet install --reporter=...")
produced "unexpected argument '--reporter' found".

* refactor(reporter,package-manager): apply review fixes from pnpm#349

Address feedback on the reporter PR.

reporter:
- Drop the dependency-injection issue link (pnpm#339) from `Reporter`,
  the recording-fake test, and the module-level docs; convention is
  visible from the code.
- Wrap `bunyan` and `bole` references as markdown links.
- Demote `Envelope`'s `#[serde(flatten)]` rationale to a regular `//`
  comment so private impl detail isn't part of `///` rustdoc.
- Introduce `pub trait EnvVar` + `pub struct RealEnvVar` (reporter-
  local capability trait) and split `hostname` into a generic
  `resolve_hostname<E>` plus a non-generic cached production wrapper.
  Add four unit tests covering `HOSTNAME`, `COMPUTERNAME` fallback,
  precedence, and the unset case.
- Switch the wire-shape test to `pipe-trait`; add `pipe-trait` to
  dev-dependencies.
- Fix intra-link rule violation in the `SilentReporter` test doc.

package-manager:
- Tighten the install `prefix` extraction to fail loudly on
  non-UTF-8 / parentless manifest paths instead of silently emitting
  an empty string. Workspace-aware resolution tracked at pnpm#357.
- Replace `concat!` YAML literals in two tests with
  `text_block_macros::text_block!`; add as dev-dependency.
- Convert bare-prose identifiers in
  `install_emits_stage_events_bracketing_the_run` to intra-doc
  links; drop the recording-fake DI prose.

Long inline `mod tests` extraction tracked at pnpm#358.

* fix(reporter): drop private-item link from `EnvVar` public doc

`EnvVar` is `pub` but `resolve_hostname` is private; rustdoc rejects
the intra-link with `-D rustdoc::private-intra-doc-links` (the rule
added to `CODE_STYLE_GUIDE.md` in pnpm#351). Rephrase the doc to talk
about "env-dependent helpers" generally without naming the private
function.

* refactor(reporter): switch hostname to gethostname syscall + DI capability

Address the second round of review feedback on pnpm#349.

reporter:
- Replace env-var-based hostname (HOSTNAME / COMPUTERNAME) with the
  real gethostname(2) syscall via the `gethostname` crate. The
  env-var approach was unsound: shells set `HOST` (zsh) or
  `HOSTNAME` (bash) as private variables that don't propagate to
  spawned binaries, so a packaged `pacquet` would have observed an
  empty hostname in most production environments.
- Introduce `pub trait GetHostName` + `pub struct RealApi`. Real
  resolution lives in `RealApi::get_host_name`. Tests can supply
  their own impl.
- Cache the production value in `static HOSTNAME: LazyLock<String>
  = LazyLock::new(RealApi::get_host_name)`. The wire emit path
  reads `&HOSTNAME` directly; the previous `hostname()` wrapper is
  no longer needed.
- Drop the now-redundant `EnvVar` trait, `RealEnvVar`,
  `resolve_hostname`, and the four env-resolution unit tests (those
  scenarios no longer exist after the syscall switch).

reporter test layout:
- Move the tests module into its own file at
  `crates/reporter/src/tests.rs` per the unit-test-layout rule in
  `CODE_STYLE_GUIDE.md`. Drop `use super::*` in favor of explicit
  merged imports of just the items the tests touch.
- Two new tests: `get_host_name_capability_is_mockable` (proves the
  trait dispatch works for fakes) and
  `real_api_returns_a_non_empty_host_name` (smoke-checks the real
  syscall path).

Documentation style:
- Restructure the workspace-prefix and stage-bracketing comments to
  drop em dashes per `CONTRIBUTING.md`'s writing-style guidance and
  to render `bunyan` as a markdown link.
- Fix the `@pnpm/core-loggers` link to point at the package
  directory rather than its `src` subdirectory.

Imports:
- Replace seven occurrences of `pacquet_reporter::SilentReporter`
  qualified at the call site with a single `use pacquet_reporter::
  SilentReporter` in the test module.
pull Bot pushed a commit to dwongdev/pnpm that referenced this pull request May 14, 2026
Adds the `Context` variant to `LogEvent` (camelCase serde so the wire
shape matches `@pnpm/cli.default-reporter`'s expectations) and emits it
once from `Install::run`, immediately before `pnpm:stage importing_started`.

Mirrors pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/installing/context/src/index.ts#L196.

`currentLockfileExists` is hard-coded `false` for now because pacquet
doesn't read or write `node_modules/.pnpm/lock.yaml` yet. The site
carries a TODO so the value gets flipped when that path lands.

Test: extends the existing recording-fake DI test (per pnpm#339) to assert
the full event sequence (`Context`, `ImportingStarted`, `ImportingDone`)
and spot-checks the context payload's directory fields. Verified the
test catches the regression by temporarily commenting out the emit and
confirming a fail; restored.

Refs pnpm#347. Engine: pnpm#345.
pull Bot pushed a commit to dwongdev/pnpm that referenced this pull request May 14, 2026
…m#476)

* feat(network): add ThrottledClient::for_installs with proxy support

Ports pnpm v11's `getDispatcher` (`network/fetch/src/dispatcher.ts` at
SHA 94240bc) onto reqwest, with the resolved proxy configuration
modeled by the new `ProxyConfig` + `NoProxySetting` types in
`pacquet-network`. HTTPS targets route through `https_proxy`; HTTP
targets through `http_proxy`; the `no_proxy` field short-circuits both
via a reverse-dot-segment-prefix matcher that mirrors upstream's
`checkNoProxy` semantics (`npmjs.org` matches `registry.npmjs.org` but
not `evilnpmjs.org`).

The proxy types live in `pacquet-network` rather than `pacquet-config`
because `pacquet-config` already depends on `pacquet-network` for the
auth-headers plumbing (pnpm#337), so the reverse direction would form a
cycle. The downstream `pacquet-config` will hold a
`Config.proxy: ProxyConfig` and populate it from `.npmrc` + env in the
follow-up commit.

Basic-auth userinfo embedded in the proxy URL is stripped and
percent-decoded before being forwarded via `Proxy::basic_auth`, matching
pnpm's `decodeURIComponent(user):decodeURIComponent(pass)` step. The
percent-decoder is a 15-line inline helper rather than a new direct
`percent-encoding` dep, since it only runs against the two halves of a
proxy userinfo. Unlike JavaScript's `decodeURIComponent`, which throws
on malformed sequences, the helper keeps invalid `%XX` escapes verbatim
— the safer behavior in a config path where the alternative would be
rejecting a half-broken password.

`parse_proxy_url` retries failed parses with an `http://` prefix to
support shorthand values like `proxy.example:8080`, matching pnpm's
`parseProxyUrl`. Rust's `url` parser is permissive enough to accept the
shorthand as scheme + opaque path, so the parser also rejects any first-
attempt parse that lacks a host — forcing the retry through that
authority-aware path.

Invalid proxy URLs surface as `ProxyError::InvalidProxy` with diagnostic
code `ERR_PNPM_INVALID_PROXY`, matching upstream's error code. Failure
is detected eagerly at client-build time (same as pnpm's
`getProxyAgent`) rather than lazily per-request.

Enables reqwest's `socks` feature so socks4/socks4a/socks5 URLs are
honored — pnpm supports the same set via its socks-client wrapper.

The existing `new_for_installs()` is preserved as a thin wrapper around
`for_installs(&ProxyConfig::default())` so test fixtures and the
benchmark harness keep their call sites unchanged.

Tests port the unit-testable describe blocks from
`network/fetch/test/dispatcher.test.ts`: per-URL routing, basic-auth
decoding, noProxy reverse-dot-prefix match, bypass-all literal, invalid
URL diagnostic code, and SOCKS-URL parse smoke. Two mockito integration
tests cover end-to-end HTTP proxy forwarding (with decoded
`Proxy-Authorization`) and the noProxy-bypass path.

* feat(config): parse proxy keys from .npmrc with env-var fallback cascade

Adds `Config.proxy: ProxyConfig` (the type lives in `pacquet-network`,
see preceding commit) and extends `NpmrcAuth` to capture the four
proxy keys (`https-proxy`, `http-proxy`, `proxy`, `no-proxy`, `noproxy`)
plus the env-var fallback cascade pnpm 11 runs in
`config/reader/src/index.ts:591-600` (SHA 94240bc). The cascade now
runs unconditionally from `Config::current` — even when no `.npmrc` is
present — so the env fallback fires the same way it does in pnpm.

The new `NpmrcAuth::apply_proxy_cascade::<Api: EnvVar>` is generic over
the project-wide `EnvVar` capability trait (introduced by pnpm#339), so
cascade unit tests inject the env without taking `EnvGuard`'s global
lock. The existing `apply_to` test helper now runs the full three-phase
sequence (`apply_registry_and_warn` → `apply_proxy_cascade` →
`build_auth_headers`).

`no-proxy=true` (literal) is upstream's `noProxy: string | true`
"bypass every proxy" shape and is parsed as `NoProxySetting::Bypass`.
Comma-separated host lists become `NoProxySetting::List`, trimmed with
empties dropped — the network layer reverse-dot-prefix-matches against
`List` entries when applying the cascade.

The cascade is invoked from `Config::current` between
`apply_registry_and_warn` (phase 1) and `build_auth_headers` (phase 2)
of the existing auth flow. Phase placement is incidental — the proxy
cascade is independent of the registry and creds layers — but slotting
it there keeps every `.npmrc`-consuming step in one block of the
function for the reader.

Tests cover the parse arms (each proxy key, the `no-proxy`/`noproxy`
last-wins alias), the cascade branches (legacy `proxy` → https slot,
http inheriting resolved https, env fallback only when .npmrc unset,
.npmrc winning over env, `PROXY` env fallback, lowercase-only env), and
the `noProxy: true` → `Bypass` parse. A `static_env!` macro keeps each
test's env-table inline. A real-`std::env::var` smoke test in `lib.rs`
exercises the path through `Config::current` under `EnvGuard`.

The `Config` literal in
`crates/package-manager/src/install_package_from_registry/tests.rs`
gains the `proxy` field (defaults to `ProxyConfig::default()`).

* feat(cli): wire proxy config through State::init

Switches `crates/cli/src/state.rs` from `ThrottledClient::new_for_installs()`
to `ThrottledClient::for_installs(&config.proxy)` so the install client
honors the `.npmrc` / env proxy cascade landed in the preceding two
commits. Proxy build failures surface as a new `InitStateError::Proxy`
variant carrying `ProxyError` (transparently diagnosed as
`ERR_PNPM_INVALID_PROXY`).

Drops the `Load` prefix on `InitStateError`'s variants
(`LoadManifest` → `Manifest`, `LoadLockfile` → `Lockfile`) so clippy's
`enum_variant_names` lint stops firing once a third `Load*`-prefixed
variant pushes the type past its shared-prefix threshold. The variants
are still self-descriptive inside `InitStateError::*`; no public
consumers exist outside `state.rs`.

Folds in `cargo fmt` reflows of three test files
(`crates/config/src/npmrc_auth/tests.rs`, `crates/network/src/lib.rs`,
`crates/network/src/tests.rs`) — trivial line-joins on lines that just
fit under the 100-column budget.
@KSXGitHub KSXGitHub mentioned this pull request May 18, 2026
3 tasks
github-actions Bot pushed a commit to Eyalm321/pnpm that referenced this pull request May 18, 2026
pnpm#349)

* feat(reporter): add NDJSON reporting engine with pnpm:stage smoke test

Introduces `pacquet-reporter` carrying the typed `LogEvent` enum, the
no-`self` `Reporter` capability trait per pnpm#339, and `NdjsonReporter` /
`SilentReporter` implementations. Adds the `--reporter=ndjson|silent`
flag and threads a `R: Reporter` generic through `Install::run`,
emitting `pnpm:stage` `importing_started` / `importing_done` to
bracket the install — one channel wired end-to-end as a smoke test
for the schema-mirror approach.

The wire format mirrors what `@pnpm/core-loggers` defines and
`@pnpm/cli.default-reporter` consumes under `pnpm --reporter=ndjson`.

Engine only. The JS-reporter spawn-and-pipe (`--reporter=default`),
the backfill of missing log events in already-ported code (pnpm#347), and
the porting convention in AGENTS.md (pnpm#346) land in follow-up PRs. The
default reporter is `silent` until the spawn-and-pipe exists, so user-
facing output is unchanged.

Refs pnpm#345. Design: pnpm#344.

* docs(package-manager): name pnpm's `lockfileDir` and link findWorkspaceDir

Upstream emits stage events with `prefix: lockfileDir` — the directory
holding `pnpm-lock.yaml`, which collapses to the workspace root when a
workspace is present. The previous comment described the *result* in
pacquet's no-workspace world but didn't name the upstream concept or
point at the helper to mirror once workspaces land. Replacing the
comment with a TODO that links `findWorkspaceDir` makes the migration
path explicit so the next person editing this site doesn't have to
re-derive it.

No behavior change.

* fix(cli): make --reporter accepted on either side of the subcommand

Adding `global = true` to the clap attribute lets users write either
`pacquet --reporter=ndjson install` or `pacquet install --reporter=ndjson`,
matching pnpm. Without it the flag is parsed by the top-level `CliArgs`
only, so a sub-command-side use ("pacquet install --reporter=...")
produced "unexpected argument '--reporter' found".

* refactor(reporter,package-manager): apply review fixes from pnpm#349

Address feedback on the reporter PR.

reporter:
- Drop the dependency-injection issue link (pnpm#339) from `Reporter`,
  the recording-fake test, and the module-level docs; convention is
  visible from the code.
- Wrap `bunyan` and `bole` references as markdown links.
- Demote `Envelope`'s `#[serde(flatten)]` rationale to a regular `//`
  comment so private impl detail isn't part of `///` rustdoc.
- Introduce `pub trait EnvVar` + `pub struct RealEnvVar` (reporter-
  local capability trait) and split `hostname` into a generic
  `resolve_hostname<E>` plus a non-generic cached production wrapper.
  Add four unit tests covering `HOSTNAME`, `COMPUTERNAME` fallback,
  precedence, and the unset case.
- Switch the wire-shape test to `pipe-trait`; add `pipe-trait` to
  dev-dependencies.
- Fix intra-link rule violation in the `SilentReporter` test doc.

package-manager:
- Tighten the install `prefix` extraction to fail loudly on
  non-UTF-8 / parentless manifest paths instead of silently emitting
  an empty string. Workspace-aware resolution tracked at pnpm#357.
- Replace `concat!` YAML literals in two tests with
  `text_block_macros::text_block!`; add as dev-dependency.
- Convert bare-prose identifiers in
  `install_emits_stage_events_bracketing_the_run` to intra-doc
  links; drop the recording-fake DI prose.

Long inline `mod tests` extraction tracked at pnpm#358.

* fix(reporter): drop private-item link from `EnvVar` public doc

`EnvVar` is `pub` but `resolve_hostname` is private; rustdoc rejects
the intra-link with `-D rustdoc::private-intra-doc-links` (the rule
added to `CODE_STYLE_GUIDE.md` in pnpm#351). Rephrase the doc to talk
about "env-dependent helpers" generally without naming the private
function.

* refactor(reporter): switch hostname to gethostname syscall + DI capability

Address the second round of review feedback on pnpm#349.

reporter:
- Replace env-var-based hostname (HOSTNAME / COMPUTERNAME) with the
  real gethostname(2) syscall via the `gethostname` crate. The
  env-var approach was unsound: shells set `HOST` (zsh) or
  `HOSTNAME` (bash) as private variables that don't propagate to
  spawned binaries, so a packaged `pacquet` would have observed an
  empty hostname in most production environments.
- Introduce `pub trait GetHostName` + `pub struct RealApi`. Real
  resolution lives in `RealApi::get_host_name`. Tests can supply
  their own impl.
- Cache the production value in `static HOSTNAME: LazyLock<String>
  = LazyLock::new(RealApi::get_host_name)`. The wire emit path
  reads `&HOSTNAME` directly; the previous `hostname()` wrapper is
  no longer needed.
- Drop the now-redundant `EnvVar` trait, `RealEnvVar`,
  `resolve_hostname`, and the four env-resolution unit tests (those
  scenarios no longer exist after the syscall switch).

reporter test layout:
- Move the tests module into its own file at
  `crates/reporter/src/tests.rs` per the unit-test-layout rule in
  `CODE_STYLE_GUIDE.md`. Drop `use super::*` in favor of explicit
  merged imports of just the items the tests touch.
- Two new tests: `get_host_name_capability_is_mockable` (proves the
  trait dispatch works for fakes) and
  `real_api_returns_a_non_empty_host_name` (smoke-checks the real
  syscall path).

Documentation style:
- Restructure the workspace-prefix and stage-bracketing comments to
  drop em dashes per `CONTRIBUTING.md`'s writing-style guidance and
  to render `bunyan` as a markdown link.
- Fix the `@pnpm/core-loggers` link to point at the package
  directory rather than its `src` subdirectory.

Imports:
- Replace seven occurrences of `pacquet_reporter::SilentReporter`
  qualified at the call site with a single `use pacquet_reporter::
  SilentReporter` in the test module.
github-actions Bot pushed a commit to Eyalm321/pnpm that referenced this pull request May 18, 2026
Adds the `Context` variant to `LogEvent` (camelCase serde so the wire
shape matches `@pnpm/cli.default-reporter`'s expectations) and emits it
once from `Install::run`, immediately before `pnpm:stage importing_started`.

Mirrors pnpm's emit at
https://github.com/pnpm/pnpm/blob/086c5e91e8/installing/context/src/index.ts#L196.

`currentLockfileExists` is hard-coded `false` for now because pacquet
doesn't read or write `node_modules/.pnpm/lock.yaml` yet. The site
carries a TODO so the value gets flipped when that path lands.

Test: extends the existing recording-fake DI test (per pnpm#339) to assert
the full event sequence (`Context`, `ImportingStarted`, `ImportingDone`)
and spot-checks the context payload's directory fields. Verified the
test catches the regression by temporarily commenting out the emit and
confirming a fail; restored.

Refs pnpm#347. Engine: pnpm#345.
github-actions Bot pushed a commit to Eyalm321/pnpm that referenced this pull request May 18, 2026
…m#476)

* feat(network): add ThrottledClient::for_installs with proxy support

Ports pnpm v11's `getDispatcher` (`network/fetch/src/dispatcher.ts` at
SHA 94240bc) onto reqwest, with the resolved proxy configuration
modeled by the new `ProxyConfig` + `NoProxySetting` types in
`pacquet-network`. HTTPS targets route through `https_proxy`; HTTP
targets through `http_proxy`; the `no_proxy` field short-circuits both
via a reverse-dot-segment-prefix matcher that mirrors upstream's
`checkNoProxy` semantics (`npmjs.org` matches `registry.npmjs.org` but
not `evilnpmjs.org`).

The proxy types live in `pacquet-network` rather than `pacquet-config`
because `pacquet-config` already depends on `pacquet-network` for the
auth-headers plumbing (pnpm#337), so the reverse direction would form a
cycle. The downstream `pacquet-config` will hold a
`Config.proxy: ProxyConfig` and populate it from `.npmrc` + env in the
follow-up commit.

Basic-auth userinfo embedded in the proxy URL is stripped and
percent-decoded before being forwarded via `Proxy::basic_auth`, matching
pnpm's `decodeURIComponent(user):decodeURIComponent(pass)` step. The
percent-decoder is a 15-line inline helper rather than a new direct
`percent-encoding` dep, since it only runs against the two halves of a
proxy userinfo. Unlike JavaScript's `decodeURIComponent`, which throws
on malformed sequences, the helper keeps invalid `%XX` escapes verbatim
— the safer behavior in a config path where the alternative would be
rejecting a half-broken password.

`parse_proxy_url` retries failed parses with an `http://` prefix to
support shorthand values like `proxy.example:8080`, matching pnpm's
`parseProxyUrl`. Rust's `url` parser is permissive enough to accept the
shorthand as scheme + opaque path, so the parser also rejects any first-
attempt parse that lacks a host — forcing the retry through that
authority-aware path.

Invalid proxy URLs surface as `ProxyError::InvalidProxy` with diagnostic
code `ERR_PNPM_INVALID_PROXY`, matching upstream's error code. Failure
is detected eagerly at client-build time (same as pnpm's
`getProxyAgent`) rather than lazily per-request.

Enables reqwest's `socks` feature so socks4/socks4a/socks5 URLs are
honored — pnpm supports the same set via its socks-client wrapper.

The existing `new_for_installs()` is preserved as a thin wrapper around
`for_installs(&ProxyConfig::default())` so test fixtures and the
benchmark harness keep their call sites unchanged.

Tests port the unit-testable describe blocks from
`network/fetch/test/dispatcher.test.ts`: per-URL routing, basic-auth
decoding, noProxy reverse-dot-prefix match, bypass-all literal, invalid
URL diagnostic code, and SOCKS-URL parse smoke. Two mockito integration
tests cover end-to-end HTTP proxy forwarding (with decoded
`Proxy-Authorization`) and the noProxy-bypass path.

* feat(config): parse proxy keys from .npmrc with env-var fallback cascade

Adds `Config.proxy: ProxyConfig` (the type lives in `pacquet-network`,
see preceding commit) and extends `NpmrcAuth` to capture the four
proxy keys (`https-proxy`, `http-proxy`, `proxy`, `no-proxy`, `noproxy`)
plus the env-var fallback cascade pnpm 11 runs in
`config/reader/src/index.ts:591-600` (SHA 94240bc). The cascade now
runs unconditionally from `Config::current` — even when no `.npmrc` is
present — so the env fallback fires the same way it does in pnpm.

The new `NpmrcAuth::apply_proxy_cascade::<Api: EnvVar>` is generic over
the project-wide `EnvVar` capability trait (introduced by pnpm#339), so
cascade unit tests inject the env without taking `EnvGuard`'s global
lock. The existing `apply_to` test helper now runs the full three-phase
sequence (`apply_registry_and_warn` → `apply_proxy_cascade` →
`build_auth_headers`).

`no-proxy=true` (literal) is upstream's `noProxy: string | true`
"bypass every proxy" shape and is parsed as `NoProxySetting::Bypass`.
Comma-separated host lists become `NoProxySetting::List`, trimmed with
empties dropped — the network layer reverse-dot-prefix-matches against
`List` entries when applying the cascade.

The cascade is invoked from `Config::current` between
`apply_registry_and_warn` (phase 1) and `build_auth_headers` (phase 2)
of the existing auth flow. Phase placement is incidental — the proxy
cascade is independent of the registry and creds layers — but slotting
it there keeps every `.npmrc`-consuming step in one block of the
function for the reader.

Tests cover the parse arms (each proxy key, the `no-proxy`/`noproxy`
last-wins alias), the cascade branches (legacy `proxy` → https slot,
http inheriting resolved https, env fallback only when .npmrc unset,
.npmrc winning over env, `PROXY` env fallback, lowercase-only env), and
the `noProxy: true` → `Bypass` parse. A `static_env!` macro keeps each
test's env-table inline. A real-`std::env::var` smoke test in `lib.rs`
exercises the path through `Config::current` under `EnvGuard`.

The `Config` literal in
`crates/package-manager/src/install_package_from_registry/tests.rs`
gains the `proxy` field (defaults to `ProxyConfig::default()`).

* feat(cli): wire proxy config through State::init

Switches `crates/cli/src/state.rs` from `ThrottledClient::new_for_installs()`
to `ThrottledClient::for_installs(&config.proxy)` so the install client
honors the `.npmrc` / env proxy cascade landed in the preceding two
commits. Proxy build failures surface as a new `InitStateError::Proxy`
variant carrying `ProxyError` (transparently diagnosed as
`ERR_PNPM_INVALID_PROXY`).

Drops the `Load` prefix on `InitStateError`'s variants
(`LoadManifest` → `Manifest`, `LoadLockfile` → `Lockfile`) so clippy's
`enum_variant_names` lint stops firing once a third `Load*`-prefixed
variant pushes the type past its shared-prefix threshold. The variants
are still self-descriptive inside `InitStateError::*`; no public
consumers exist outside `state.rs`.

Folds in `cargo fmt` reflows of three test files
(`crates/config/src/npmrc_auth/tests.rs`, `crates/network/src/lib.rs`,
`crates/network/src/tests.rs`) — trivial line-joins on lines that just
fit under the 100-column budget.
zkochan pushed a commit that referenced this pull request May 18, 2026
* test: fill coverage holes across lockfile, package-manifest, fs, and friends

Adds ~44 unit and integration tests to close the easier targets in the
coverage analysis at #339-style boundaries. Touches:

- `lockfile::resolved_dependency`: cover `as_alias` / `ver_peer` for
  non-matching variants, alias / parse error variants, `TryFrom<Cow>`,
  serialize-alias / serialize-link, `From<PkgVerPeer> / From<PkgNameVerPeer>`,
  and a Display vs. `String` round-trip.
- `lockfile::freshness`: cover the plural arms of `SpecDiff::Display`
  and the comma separator inside the removed/modified loops.
- `lockfile::pkg_name`: cover `TryFrom<String>` and `TryFrom<Cow>` happy
  and empty-input paths.
- `lockfile::snapshot_dep_ref`: cover `ver_peer` and `From<PkgVerPeer>`.
- `lockfile::save_lockfile`: cover the `CreateDir` / `RemoveFile` /
  `RenameFile` error classifications by planting a regular file or
  directory where the writer expects a file or a writable path.
- `registry::package`: cover `PartialEq`, `latest`, and `pinned_version`
  happy and no-match paths.
- `graph-hasher::engine_name`: cover `detect_node_version` /
  `detect_node_major` when `node` is on PATH; skip cleanly otherwise.
- `graph-hasher::object_hasher`: cover the null / bool / array arms of
  the bytestream serializer.
- `patching::apply`: cover non-NotFound read-patch error, partial-delete
  non-empty result, unsupported rename/copy operation, and `Create`
  with an unwritable parent.
- `workspace-state`: cover the `CreateDir` / `ReadFile` / `ParseJson`
  error variants.
- `package-manifest`: cover `from_path` ENOENT, `add_dependency` on a
  non-object field, `safe_read_package_json_from_dir` non-NotFound IO
  error, and `convert_engines_runtime_to_dependencies` for unsupported
  shapes.
- `fs::file_mode`: cover `EXEC_MASK` / `EXEC_MODE` constants,
  `is_executable` for all positions, and `make_file_executable` on Unix.
- `executor`: cover `execute_shell` happy and non-zero-exit paths.
- `cli/tests/run.rs`: new integration tests for `pacquet run`,
  including argument forwarding and `--if-present`.

Also bumps `hex_decode` in `graph-hasher::tests` to use
`is_multiple_of` so test-time clippy stays clean under Rust 1.95.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

* style(package-manifest): drop trailing comma in single-line `assert!`

Dylint's perfectionist::macro-trailing-comma rule rejected the single-
line `assert!` formatting I'd accidentally inherited from the multi-
line shape — remove the trailing comma so the lint clears.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

* test(graph-hasher): make `node` a hard prerequisite for detect tests

The two `detect_node_*` tests previously skipped silently when `node`
was missing from `PATH`. `node` is a documented prerequisite of the
test suite (see `pacquet/CONTRIBUTING.md`'s setup section), so a
missing binary is a test-env bug to surface, not a condition to paper
over. Switch the `let Some(...) = ... else { return }` skips to
`expect` so a missing `node` fails loudly with a clear message.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

* test(cli,patching): switch fixtures to `json!` and `text_block_fnl!`

Addresses six review comments on #11710:

- `cli/tests/run.rs`: the three `package.json` fixtures used
  `format!("{{ ... }}", marker = …)` with literal-brace escapes,
  which is awkward and brittle when path strings contain
  JSON-special characters. Switched to
  `json!({...}).to_string()` so serde handles escaping and the
  shape reads as JSON, not as a brace-escaped template.
- `patching/src/apply/tests.rs`: the three patch fixtures I
  added used `"\<newline>...\n"` raw strings. Converted them to
  `text_block_fnl!`, matching the convention the rest of the
  workspace (lockfile, package-manager, testing-utils) uses for
  multi-line fixture text. The `_fnl` variant keeps the trailing
  newline that git-diff parsers expect.

Pre-existing fixtures in the same file (`IS_POSITIVE_PATCH`,
etc.) were not touched — keeping the scope to the lines
reviewers flagged.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

* style(registry): use `assert_ne!` over `assert!(lhs != rhs)`

Idiomatic Rust and produces a better failure message when the
assertion trips. Caught during a self-review pass over #11710.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

* test: address zkochan + Copilot review feedback on #11710

- Move executor + fs::file_mode unit tests from inline modules
  to the project's standard `src/<parent>/tests.rs` layout. The
  convention is documented in `CODE_STYLE_GUIDE.md` under "Unit
  test file layout"; zkochan flagged the violation in the
  executor file.

- Gate `pacquet-executor::tests` on `cfg(all(test, unix))` at
  the declaration site so the `use super::execute_shell` import
  isn't dead on Windows. Copilot flagged that
  `clippy --tests --deny warnings` would fail there.

- Drop `execute_shell_propagates_nonzero_exit_as_ok`. Copilot
  flagged that it regression-pinned a behavior that *should*
  change: pnpm/npm `run` exits with the script's status, but
  pacquet's wrapper currently returns `Ok(())` regardless. A
  fix belongs in its own PR; until then we should not add tests
  that block that fix.

- Quote the temp-path redirect targets in the `cli/tests/run.rs`
  shell fixtures so a tempdir path containing a space
  (`/var/folders/...` on macOS) doesn't split the `touch` /
  redirect argument. Copilot flagged the unquoted paths.

The `fs::file_mode::make_file_executable_sets_exec_bits` test
keeps `#[cfg(unix)]` at the test site (and moves its
`make_file_executable` import inside) rather than gating the
whole `tests` module — the other two tests
(`exec_constants_pin_pnpm_layout`,
`is_executable_matches_any_exec_bit`) are platform-neutral and
should still run on Windows.

Copilot's concern about `detect_node_version`'s `expect` (in
`engine_name.rs`) is intentionally not addressed: KSXGitHub
asked for the hard-fail in 5d0987c on grounds that `node` is a
documented prerequisite of the test suite, and the human
reviewer's call wins over the bot's.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL

---------

Co-authored-by: Claude <noreply@anthropic.com>
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