feat: #5 add .env config file support#62
Merged
Conversation
velocitysystems
requested changes
May 6, 2026
…se source attribution Addresses PR #62 review comment from @velocitysystems: a user who copies example/.env.example, forgets to fill in a value (or types only whitespace), would get an opaque HTTP 401/404 from Raygun instead of the friendly 'Missing ...' error. The empty-value passthrough was actually codified as the expected behavior in two tests, with a misleading comment. Changes: - ConfigProp.load now treats empty ('') and whitespace-only (' ', '\t') values at any tier (CLI arg, env var, .env file) as missing and falls through to the next source. Implemented via a single _isPresent(value) => value != null && value.trim().isNotEmpty helper. - ConfigProp.load gains a verbose: parameter. When -v/--verbose is passed, each property prints '[VERBOSE] Resolved <name> from <source>' for the winning tier and '[VERBOSE] Ignoring blank value for <name> from <source>; falling through' when a present-but-blank value is skipped. - Threaded verbose: through all 10 ConfigProp.load() call sites across 6 command files. - Updated the user-facing error message to mention that empty/whitespace-only values are treated as missing. - README updated with the new behavior + verbose hint. Test changes: - Flipped the lock-step test in config_file_test.dart that documented the buggy behavior; rewrote its comment so the contract is unambiguous. - Added 13 net-new tests in config_props_test.dart and e2e_config_file_test.dart covering: empty fall-through at every tier, whitespace fall-through (CLI / env / tab), exit-code-2 when all tiers are blank, verbose attribution lines for each tier, and 'Ignoring blank value' notices. - Total test count: 126 -> 139, all passing. Verification: - dart format . / dart analyze / dart test: all clean - Manual smoke test confirms friendly error replaces opaque HTTP failure
Addresses PR #62 review comments #2 and #3 from @velocitysystems. The bug: when neither HOME nor USERPROFILE is set (sandboxed CI runners, minimal containers, systemd PrivateUsers=true), _defaultStopDir() fell back to the filesystem root prefix (e.g. '/'). The discovery loop in _discover() would then walk every parent of CWD all the way up to '/', meaning a stray /.env or /etc/.env could be silently picked up — a correctness and potential security concern. The fix: _defaultStopDir() now returns String? and returns null when neither home env var is set. ConfigFile.load() handles the null case by checking only the start directory (CWD) — no upward walking. Behavior when HOME/USERPROFILE IS set is unchanged. Users in HOME-less environments who need a .env from elsewhere can use --config-file=<path> (the existing escape hatch). Also closes review comment #3 (README ambiguity about 'up to $HOME' when not under $HOME) by rewriting the discovery section in both README.md and AGENT.md. Test seam: load() gains an optional environmentOverride: Map<String, String>? parameter (test-only) so we can simulate empty/partial environments without spawning a child process. Production callers pass null (the default) and read from Platform.environment as before. Test changes: - New unit group 'discovery without HOME' in config_file_test.dart (5 tests): finds .env in CWD when HOME unset; does NOT walk to parent dirs (regression for the bug); empty HOME string treated as unset; USERPROFILE honored as Windows fallback; verbose hint is printed. - New E2E test in e2e_config_file_test.dart: spawns the CLI with environment: const {} (no HOME), with .env in a parent dir; asserts the parent .env is NOT loaded and the friendly Missing error is emitted. - Total test count: 139 -> 145, all passing. Verification: - dart format . / dart analyze / dart test: all clean - Manual smoke: env -i dart run bin/raygun_cli.dart ... from a CWD with a parent .env confirms the parent .env is ignored and the verbose hint is shown AGENT.md updated to reflect the new discovery contract.
velocitysystems
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#5: add
.envconfig file supportCloses #5.
Description 📝
raygun-clivia a project-root config file instead of having to pass every credential as a CLI argument or environment variable on every invocation. This is a follow-up to perf: #5 refactor config props #15, which restructuredConfigPropso each property is loaded independently — a prerequisite for adding a third source.ConfigProp.load(). Lookup order (highest priority first): CLI argument → environment variable →.envfile. The.envis discovered automatically (CWD, then walking up parent directories to$HOME) or explicitly via a new--config-file=<path>global flag. Parsing uses thedotenvpackage so we get correct handling of quoted values,# comments,export KEY=valuesyntax, and other.envconventions out of the box.Type of change
Updates
👉 New
lib/src/config_file.dart:ConfigFileclass with discovery (walks parent dirs, stops at$HOME), explicit-path support, dotenv parsing, and a singleton +setInstance/resetForTesttest seam mirroringEnvironment.👉
lib/src/config_props.dart: extendedload()to fall through to the.envfile when arg + env are both absent. Updated error message to mention all three sources.👉
bin/raygun_cli.dart: added--config-file=<path>global flag and initializesConfigFilebefore any subcommand runs.👉 New dependencies:
dotenv: ^4.2.0andpath: ^1.9.0(the latter was already transitive — promoted to direct since we use it directly).👉 README + AGENT.md updated, sample
example/.env.examplecommitted.👉 Opportunistic test debt cleanup (separate commits): added previously missing tests for
Environment(singleton,[]operator) andRaygunMultipartRequestBuilder/RaygunPostRequestBuilder(the shared HTTP request builders used by every command).Test plan 🧪
The PR ships with +68 net new tests (58 → 126 total). All green locally and in CI:
Test coverage breakdown for the new feature:
test/config_file_test.darttest/config_props_test.darttest/e2e_config_file_test.darttest/environment_test.darttest/core/raygun_api_test.dartManual smoke test (with verbose output to confirm values flow through):
Reviewers can also try:
--config-file=<path>to point at an explicit fileBackward compatibility
This is an additive change:
.envis a silent no-op — existing scripts using args or env vars are unaffected.Author to check 👓
Reviewer to check ✔️