Skip to content

feat: allow collection environment and environment file to be used together in run command#6784

Merged
bijin-bruno merged 1 commit intousebruno:mainfrom
abhishek-bruno:feat/cli-allow-env-and-env-file-together
Jan 13, 2026
Merged

feat: allow collection environment and environment file to be used together in run command#6784
bijin-bruno merged 1 commit intousebruno:mainfrom
abhishek-bruno:feat/cli-allow-env-and-env-file-together

Conversation

@abhishek-bruno
Copy link
Member

@abhishek-bruno abhishek-bruno commented Jan 12, 2026

Description

  • Refactored the environment variable loading logic to streamline the process of loading from both file and collection environments.
  • Added support for loading environment variables from JSON, YAML, and custom .bru files.
  • Enhanced error handling for missing or invalid environment files.

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added multi-format environment file support for --env-file flag (.json, .yml, .yaml, .bru).
    • Combined --env and --env-file usage now works together with proper variable precedence (collection-level variables override global values).
    • Enhanced error handling and reporting for missing or malformed environment files.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

Walkthrough

Introduces a unified environment file loader supporting .json, .yml/.yaml, and .bru formats with centralized parsing, adds environment variable merging with precedence handling (collection env overrides global env), and includes comprehensive test coverage for combined --env and --env-file CLI scenarios.

Changes

Cohort / File(s) Summary
Core environment loading refactor
packages/bruno-cli/src/commands/run.js
Extracts new loadEnvFromFile helper to unify parsing of multiple env file formats; restructures env variable merging to layer global workspace env, collection-level env, env-file overrides, and CLI --env-var arguments; adds exit codes for file not found and parse errors.
Environment handling test suite
tests/runner/cli-env-combined/cli-env-combined.spec.ts
New acceptance test suite validating combined --env and --env-file CLI behavior; covers precedence rules (collection > global), fallback scenarios (env-file only, env only), and output verification.
Test collection fixtures
tests/runner/cli-env-combined/collection/(bruno.json, global-env.json, CollectionEnv.bru, request.bru)
Collection manifest, global and collection environment variable definitions, and templated HTTP request for verifying variable substitution across env layers.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI Entry
    participant Loader as loadEnvFromFile
    participant Parser as Format Parser
    participant Merger as Env Merger
    participant Executor as Request Executor

    CLI->>Loader: Load global workspace env
    Loader->>Parser: Parse global-env.yml/.json
    Parser-->>Loader: Global vars + __name__
    Loader-->>Merger: Global env data
    
    CLI->>Loader: Load collection env (--env)
    Loader->>Parser: Parse CollectionEnv.bru/json
    Parser-->>Loader: Collection vars + __name__
    Loader-->>Merger: Collection env data
    
    CLI->>Loader: Load env-file (--env-file)
    Loader->>Parser: Parse .json/.yaml/.bru
    Parser-->>Loader: File vars + __name__
    Loader-->>Merger: File env data
    
    CLI->>Merger: Apply --env-var CLI overrides
    Merger->>Merger: Merge with precedence:<br/>Collection > Global > File > CLI args
    Merger-->>Executor: Final merged env vars
    Executor->>Executor: Substitute {{var}} in requests
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • lohit-bruno
  • helloanoop
  • bijin-bruno

Poem

🌍 Environments merge in layers deep,
Global whispers, collections leap,
Templates dance through every request,
Precedence rules put vars to test!
🚀✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 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: enabling collection environment and environment files to work together in the run command, which is the core feature introduced across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@abhishek-bruno abhishek-bruno force-pushed the feat/cli-allow-env-and-env-file-together branch from 6d5f0a4 to 007e4be Compare January 12, 2026 12:12
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @tests/runner/cli-env-combined/cli-env-combined.spec.ts:
- Around line 11-18: The helper runFrom returns the CLI exit code but tests
never assert it, allowing failures to go unnoticed; update tests that call
runFrom to capture its return value and assert it equals 0 (e.g., const exit =
runFrom(...); expect(exit).toBe(0)) so CI fails on non‑zero exits, and
optionally enhance runFrom to surface stderr (or include the error message in
the thrown/returned value) so failing runs provide diagnostic output; locate the
runFrom function and all tests invoking it and add the exit assertions.
🧹 Nitpick comments (6)
packages/bruno-cli/src/commands/run.js (1)

369-378: Extension handling inconsistency in __name__ derivation.

For YAML files (line 373), fileExt includes the leading dot (e.g., .yml), which is correct for path.basename(filePath, fileExt). However, for the fallback branch (lines 374-378), unknown extensions are treated as .bru format but always strip .bru from the filename, even if the actual extension differs.

This could result in incorrect __name__ values for files with non-standard extensions.

Suggested improvement
     } else {
       const content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
       const envJson = parseEnvironment(content);
       result = getEnvVars(envJson);
-      result.__name__ = nameOverride || path.basename(filePath, '.bru');
+      const actualExt = path.extname(filePath);
+      result.__name__ = nameOverride || path.basename(filePath, actualExt || '.bru');
     }
tests/runner/cli-env-combined/collection/bruno.json (1)

1-5: Consider moving to fixtures/collection subdirectory.

Per the coding guidelines, test-specific collections should follow the tests/**/fixtures/collection pattern. The current path tests/runner/cli-env-combined/collection/ should ideally be tests/runner/cli-env-combined/fixtures/collection/.

The JSON content itself is valid. Based on learnings, this pattern helps maintain consistency across test fixtures.

tests/runner/cli-env-combined/cli-env-combined.spec.ts (4)

7-8: Fixtures should be nested inside a fixtures folder.

Per coding guidelines, test fixtures should follow the pattern tests/**/fixtures/collection. The collection directory should be at tests/runner/cli-env-combined/fixtures/collection rather than tests/runner/cli-env-combined/collection.

Suggested structure
- const collectionPath = path.resolve(__dirname, 'collection');
+ const collectionPath = path.resolve(__dirname, 'fixtures/collection');

Move the collection directory into a new fixtures folder accordingly.


20-36: Use test.afterEach for cleanup and test.step for report readability.

Per coding guidelines:

  1. Promote the use of test.step so generated reports are easier to read.
  2. Repeated cleanup logic in each test should be consolidated into test.afterEach.
Proposed refactor
const outputFiles: string[] = [];

test.afterEach(async () => {
  for (const file of outputFiles) {
    try {
      fs.unlinkSync(file);
    } catch (_) {}
  }
  outputFiles.length = 0;
});

test('CLI: Should allow --env and --env-file to be used together', async () => {
  await test.step('Run CLI with both --env and --env-file', async () => {
    const envFilePath = path.join(collectionPath, 'global-env.json');
    const outputPath = path.join(collectionPath, 'combined-out.json');
    outputFiles.push(outputPath);

    const exitCode = runFrom(
      collectionPath,
      `run request.bru --env CollectionEnv --env-file "${envFilePath}" --reporter-json "${outputPath}"`
    );
    expect(exitCode).toBe(0);
  });

  await test.step('Verify output file was created', async () => {
    expect(fs.existsSync(outputPath)).toBe(true);
  });
});

Also applies to: 38-68, 70-89, 91-113


33-35: Empty catch blocks silently swallow errors.

The cleanup try/catch blocks with empty catches (catch (_) {}) hide potential issues. If cleanup fails for unexpected reasons (e.g., permissions), you'd want visibility.

Optional improvement
  try {
    fs.unlinkSync(outputPath);
- } catch (_) {}
+ } catch (e) {
+   if ((e as NodeJS.ErrnoException).code !== 'ENOENT') {
+     console.warn(`Cleanup warning: ${e}`);
+   }
+ }

Or better yet, use fs.rmSync(outputPath, { force: true }) which ignores missing files:

- try {
-   fs.unlinkSync(outputPath);
- } catch (_) {}
+ fs.rmSync(outputPath, { force: true });

Also applies to: 65-67, 86-88, 110-112


20-36: Tests are async but don't await anything.

All test functions are declared async but contain no await expressions. Either remove async or restructure to use test.step with async callbacks for consistency.

Also applies to: 38-68, 70-89, 91-113

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 071ee9a and 007e4be.

📒 Files selected for processing (6)
  • packages/bruno-cli/src/commands/run.js
  • tests/runner/cli-env-combined/cli-env-combined.spec.ts
  • tests/runner/cli-env-combined/collection/bruno.json
  • tests/runner/cli-env-combined/collection/environments/CollectionEnv.bru
  • tests/runner/cli-env-combined/collection/global-env.json
  • tests/runner/cli-env-combined/collection/request.bru
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • tests/runner/cli-env-combined/cli-env-combined.spec.ts
  • packages/bruno-cli/src/commands/run.js
tests/**/**.*

⚙️ CodeRabbit configuration file

tests/**/**.*: Review the following e2e test code written using the Playwright test library. Ensure that:

  • Follow best practices for Playwright code and e2e automation

  • Try to reduce usage of page.waitForTimeout(); in code unless absolutely necessary and the locator cannot be found using existing expect() playwright calls

  • Avoid using page.pause() in code

  • Use locator variables for locators

  • Avoid using test.only

  • Use multiple assertions

  • Promote the use of test.step as much as possible so the generated reports are easier to read

  • Ensure that the fixtures like the collections are nested inside the fixtures folder

    Fixture Example*: Here's an example of possible fixture and test pair

    .
    ├── fixtures
    │   └── collection
    │       ├── base.bru
    │       ├── bruno.json
    │       ├── collection.bru
    │       ├── ws-test-request-with-headers.bru
    │       ├── ws-test-request-with-subproto.bru
    │       └── ws-test-request.bru
    ├── connection.spec.ts # <- Depends on the collection in ./fixtures/collection
    ├── headers.spec.ts
    ├── persistence.spec.ts
    ├── variable-interpolation
    │   ├── fixtures
    │   │   └── collection
    │   │       ├── environments
    │   │       ├── bruno.json
    │   │       └── ws-interpolation-test.bru
    │   ├── init-user-data
    │   └── variable-interpolation.spec.ts # <- Depends on the collection in ./variable-interpolation/fixtures/collection
    └── subproto.spec.ts
    

Files:

  • tests/runner/cli-env-combined/cli-env-combined.spec.ts
  • tests/runner/cli-env-combined/collection/request.bru
  • tests/runner/cli-env-combined/collection/environments/CollectionEnv.bru
  • tests/runner/cli-env-combined/collection/bruno.json
  • tests/runner/cli-env-combined/collection/global-env.json
🧠 Learnings (4)
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.

Applied to files:

  • tests/runner/cli-env-combined/cli-env-combined.spec.ts
  • tests/runner/cli-env-combined/collection/request.bru
  • tests/runner/cli-env-combined/collection/environments/CollectionEnv.bru
  • tests/runner/cli-env-combined/collection/bruno.json
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.test.{js,jsx,ts,tsx} : Add tests for any new functionality or meaningful changes. If code is added, removed, or significantly modified, corresponding tests should be updated or created

Applied to files:

  • tests/runner/cli-env-combined/cli-env-combined.spec.ts
📚 Learning: 2026-01-07T18:53:37.000Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6735
File: packages/bruno-electron/src/ipc/collection.js:936-939
Timestamp: 2026-01-07T18:53:37.000Z
Learning: In the bruno repository, the Redux reducer determines collection format by checking for the `opencollection` property in brunoConfig. The `version` property is not used for format detection, so having both `version` and `opencollection` properties together doesn't cause issues since `opencollection` takes precedence.

Applied to files:

  • tests/runner/cli-env-combined/collection/bruno.json
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-cli/src/commands/run.js
🧬 Code graph analysis (2)
tests/runner/cli-env-combined/cli-env-combined.spec.ts (3)
packages/bruno-cli/src/commands/run.js (5)
  • collectionPath (314-314)
  • path (3-3)
  • envFilePath (386-386)
  • result (359-359)
  • result (649-660)
packages/bruno-js/src/sandbox/quickjs/shims/bru.js (1)
  • cwd (8-10)
packages/bruno-cli/src/commands/import.js (1)
  • outputPath (258-258)
packages/bruno-cli/src/commands/run.js (3)
packages/bruno-cli/src/utils/environment.js (1)
  • parseEnvironmentJson (5-22)
packages/bruno-cli/src/utils/bru.js (2)
  • getEnvVars (130-144)
  • envVars (136-136)
packages/bruno-filestore/src/index.ts (1)
  • parseEnvironment (115-122)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: Unit Tests
  • GitHub Check: CLI Tests
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: SSL Tests - Linux
🔇 Additional comments (7)
packages/bruno-cli/src/commands/run.js (3)

384-397: LGTM!

Clean error handling with specific exit codes. The try-catch properly captures parsing failures from loadEnvFromFile.


399-414: LGTM!

The merging logic correctly applies collection environment precedence over env-file values. Consistent error handling pattern.


470-473: LGTM!

Correct precedence: global env serves as base, then overlaid by env-file/collection values. The __name__ fallback logic is sensible.

tests/runner/cli-env-combined/collection/global-env.json (1)

1-8: LGTM!

Well-structured environment JSON matching the expected schema. Variable naming clearly indicates origin for test assertions.

tests/runner/cli-env-combined/collection/environments/CollectionEnv.bru (1)

1-5: LGTM!

Clean environment definition with clear variable naming to distinguish collection-level values from global ones for precedence testing.

tests/runner/cli-env-combined/collection/request.bru (1)

1-19: LGTM!

Well-designed test request that exercises all three variable scenarios: override (present in both), global-only, and collection-only. This effectively validates the environment merging logic.

tests/runner/cli-env-combined/cli-env-combined.spec.ts (1)

49-63: Good coverage of override precedence and fallback behavior.

The assertions properly verify:

  • Collection env overrides env-file values
  • Env-file values are used when collection env is absent
  • Template placeholders remain when neither source provides a value

This covers the key scenarios for the merged environment feature.

Also applies to: 78-84, 98-108

Comment on lines +11 to +18
const runFrom = (cwd: string, args: string): number => {
try {
execSync(`cd "${cwd}" && ${BRU} ${args}`, { stdio: 'pipe' });
return 0;
} catch (error: any) {
return error?.status ?? 1;
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Exit code not validated; failures may go unnoticed.

The runFrom helper returns an exit code, but tests ignore it. If the CLI fails, tests only check for output file existence—which may still pass if a previous run left artifacts behind. Consider asserting the exit code.

Proposed fix
- runFrom(
+ const exitCode = runFrom(
    collectionPath,
    `run request.bru --env CollectionEnv --env-file "${envFilePath}" --reporter-json "${outputPath}"`
  );
+ expect(exitCode).toBe(0);
🤖 Prompt for AI Agents
In @tests/runner/cli-env-combined/cli-env-combined.spec.ts around lines 11 - 18,
The helper runFrom returns the CLI exit code but tests never assert it, allowing
failures to go unnoticed; update tests that call runFrom to capture its return
value and assert it equals 0 (e.g., const exit = runFrom(...);
expect(exit).toBe(0)) so CI fails on non‑zero exits, and optionally enhance
runFrom to surface stderr (or include the error message in the thrown/returned
value) so failing runs provide diagnostic output; locate the runFrom function
and all tests invoking it and add the exit assertions.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants