Skip to content

Vendor dotenvy .env parser to remove git dependency - #1351

Merged
DZakh merged 2 commits into
mainfrom
claude/nifty-galileo-46n5qz
Jun 25, 2026
Merged

Vendor dotenvy .env parser to remove git dependency#1351
DZakh merged 2 commits into
mainfrom
claude/nifty-galileo-46n5qz

Conversation

@DZakh

@DZakh DZakh commented Jun 25, 2026

Copy link
Copy Markdown
Member

Vendors a minimal .env file parser from the unreleased dotenvy 0.16 rewrite to eliminate the git dependency on github.com/enviodev/dotenvy. The vendored implementation includes only the parsing functionality needed by the CLI, dropping the builder, environment-merging sequences, unsafe env-modifying loaders, and CLI/macros.

Key changes:

  • Added packages/cli/src/utils/dotenv.rs with a complete .env parser implementation ported from dotenvy 0.16
    • Parses .env files into an EnvMap (HashMap-backed) without modifying process environment
    • Supports variable substitution ($VAR / ${VAR}) against process environment and earlier file entries
    • Handles quoted strings (single/double), escape sequences, comments, and BOM removal
    • Includes comprehensive test coverage for parsing edge cases
  • Updated packages/cli/src/config_parsing/system_config.rs to use vendored parser instead of dotenvy crate
  • Updated packages/cli/src/docker_env.rs to use vendored parser instead of dotenvy crate
  • Removed dotenvy git dependency from packages/cli/Cargo.toml
  • Exported new dotenv module from packages/cli/src/utils/mod.rs

The vendored code is MIT-licensed (© the dotenvy authors) and maintains API compatibility with the previous dotenvy usage while reducing build-time dependency resolution overhead.

https://claude.ai/code/session_01HEJGDhrXJQx1mvtdTwqUz7

Summary by CodeRabbit

  • New Features
    • The CLI now includes built-in support for reading .env files.
    • .env parsing supports comments, quoted strings, escaping, and $VAR / ${VAR} variable substitution.
  • Bug Fixes
    • Improved handling of malformed .env files (e.g., UTF-8 BOMs and edge-case formats) by warning and safely continuing as if no .env exists.
    • Environment value precedence remains consistent: process environment variables override .env values.
  • Chores
    • Removed reliance on the previously used external dotenv loader.

The `dotenvy` crate was pulled as a git dependency pinned to an
unreleased upstream commit (the EnvLoader/EnvMap/EnvSequence API never
shipped to crates.io). Cargo clones it from GitHub on every cache-cold
build — the release matrix runs uncached on purpose — which exhausts
GitHub's git egress and breaks compilation.

Only two call sites used it, both via `EnvSequence::InputOnly`: parse a
.env file into a map without reading or mutating the process env. Vendor
just that path into utils::dotenv (EnvMap + parser + line iterator),
dropping the builder, env-merging sequences, unsafe env-modifying
loaders, CLI, and macros. Upstream parser/substitution tests are ported
verbatim to lock in behavioral parity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEJGDhrXJQx1mvtdTwqUz7
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1e8c4c97-93aa-46eb-9b11-b071f93a3aa3

📥 Commits

Reviewing files that changed from the base of the PR and between c3a756a and 3624985.

📒 Files selected for processing (1)
  • packages/cli/src/docker_env.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/docker_env.rs

📝 Walkthrough

Walkthrough

The CLI replaces dotenvy with an internal .env parser module. The new module loads .env files into EnvMap, handles parsing and substitutions, and is used by EnvState::var and EnvConfig::from_project.

Changes

CLI dotenv loader migration

Layer / File(s) Summary
Public loader surface
packages/cli/Cargo.toml, packages/cli/src/utils/mod.rs, packages/cli/src/utils/dotenv.rs
The new dotenv module is exported, its public map/error/file-loading APIs are defined, and the dotenvy dependency is removed.
Streaming parse pipeline
packages/cli/src/utils/dotenv.rs
The loader streams .env input through BOM handling, line scanning, comment detection, and key/value parsing state.
Value substitution behavior
packages/cli/src/utils/dotenv.rs
Quoted values, escapes, substitutions, and the unit tests for parsing and edge cases are added.
CLI call-site migration
packages/cli/src/config_parsing/system_config.rs, packages/cli/src/docker_env.rs
The existing .env loading call sites now use crate::utils::dotenv instead of dotenvy.

Sequence Diagram(s)

sequenceDiagram
  participant EnvState_var as "EnvState::var"
  participant dotenv_from_path as "dotenv::from_path"
  participant Iter_load as "Iter::load"
  participant Lines_next as "Lines::next"
  participant LineParser as "LineParser"
  participant EnvMap as "EnvMap"

  EnvState_var->>dotenv_from_path: load `.env` from project_root
  dotenv_from_path->>Iter_load: stream parsed lines
  Iter_load->>Lines_next: read logical line
  Lines_next->>LineParser: parse key and value
  LineParser->>EnvMap: insert parsed entry
  EnvState_var->>EnvMap: look up requested key
  EnvMap-->>EnvState_var: return value or NotPresent
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: vendoring dotenvy’s .env parser to eliminate the git dependency.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/cli/src/docker_env.rs (1)

286-286: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

.ok() silently swallows .env parse errors.

from_path(...).ok() discards dotenv::Error::LineParse the same as a missing file, so a malformed .env silently falls back to the hardcoded defaults (default DB credentials, ports, etc.) with no signal to the user. This diverges from EnvState::var in system_config.rs, which prints a warning for non-IO errors. Consider matching that behavior and only ignoring Error::Io.

♻️ Surface non-IO errors instead of swallowing them
-        let dotenv = dotenv::from_path(project_root.join(".env")).ok();
+        let dotenv = match dotenv::from_path(project_root.join(".env")) {
+            Ok(map) => Some(map),
+            Err(dotenv::Error::Io(_, _)) => None,
+            Err(err) => {
+                println!("Warning: Failed loading .env file with unexpected error: {err}");
+                None
+            }
+        };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/docker_env.rs` at line 286, The dotenv load in
docker_env::from_path is swallowing parse failures by converting all errors with
.ok(), which makes malformed .env files look like missing files. Update the
dotenv handling to distinguish dotenv::Error::Io from other error kinds, ignore
only the I/O case, and surface non-IO parse errors with a warning similar to
EnvState::var in system_config.rs. Keep the fix localized around the existing
dotenv::from_path(project_root.join(".env")) call so malformed .env inputs are
visible instead of silently falling back to defaults.
packages/cli/src/utils/dotenv.rs (1)

582-582: 📐 Maintainability & Code Quality | 🔵 Trivial

Switch the test helpers to tempfile

packages/cli/Cargo.toml still depends on deprecated tempdir, and this file is one of several test helpers using TempDir::new(...). Migrate these tests to tempfile::tempdir() and drop tempdir from dev-dependencies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/utils/dotenv.rs` at line 582, The test helper in dotenv.rs
still uses the deprecated tempdir::TempDir::new pattern, so migrate it to
tempfile::tempdir() and update any related test setup in the same helper block
to use the new API. Make sure the test code references the tempfile crate
consistently, and then remove tempdir from the dev-dependencies so the CLI tests
no longer depend on the deprecated crate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/cli/src/docker_env.rs`:
- Line 286: The dotenv load in docker_env::from_path is swallowing parse
failures by converting all errors with .ok(), which makes malformed .env files
look like missing files. Update the dotenv handling to distinguish
dotenv::Error::Io from other error kinds, ignore only the I/O case, and surface
non-IO parse errors with a warning similar to EnvState::var in system_config.rs.
Keep the fix localized around the existing
dotenv::from_path(project_root.join(".env")) call so malformed .env inputs are
visible instead of silently falling back to defaults.

In `@packages/cli/src/utils/dotenv.rs`:
- Line 582: The test helper in dotenv.rs still uses the deprecated
tempdir::TempDir::new pattern, so migrate it to tempfile::tempdir() and update
any related test setup in the same helper block to use the new API. Make sure
the test code references the tempfile crate consistently, and then remove
tempdir from the dev-dependencies so the CLI tests no longer depend on the
deprecated crate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a2e55a7-6670-47c4-a80e-603c50fbb472

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7273b and c3a756a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • packages/cli/Cargo.toml
  • packages/cli/src/config_parsing/system_config.rs
  • packages/cli/src/docker_env.rs
  • packages/cli/src/utils/dotenv.rs
  • packages/cli/src/utils/mod.rs
💤 Files with no reviewable changes (1)
  • packages/cli/Cargo.toml

`.ok()` discarded LineParse errors the same as a missing file, silently
falling back to default DB credentials/ports on a malformed .env. Match
EnvState::var: ignore only Io errors, warn on the rest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HEJGDhrXJQx1mvtdTwqUz7
@DZakh
DZakh merged commit 99031de into main Jun 25, 2026
7 of 8 checks passed
@DZakh
DZakh deleted the claude/nifty-galileo-46n5qz branch June 25, 2026 14:22
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.

2 participants