Skip to content

(size/L)feat:Added the option for bruno version edit in the collection overview#8424

Open
sachin-bruno wants to merge 2 commits into
usebruno:mainfrom
sachin-bruno:sachin-bruno/feature-collection-version-edit
Open

(size/L)feat:Added the option for bruno version edit in the collection overview#8424
sachin-bruno wants to merge 2 commits into
usebruno:mainfrom
sachin-bruno:sachin-bruno/feature-collection-version-edit

Conversation

@sachin-bruno

@sachin-bruno sachin-bruno commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Description

A collection has no visible, editable version in the Bruno UI. yml (opencollection) collections define info.version in their schema, but Bruno never reads, displays, or lets users set it. .bru collections have no collection-version field at all (bruno.json carries only the bru schema version). Users can't see what version a collection is at, or set one, in either format.

Proposed Solution
Add a Version section to the collection Overview page (Collection Settings → Overview) for both formats:

Display the current collection version. yml reads info.version; .bru reads a new collectionVersion field in bruno.json, added after the existing version field (which remains the bru schema version). Collections that have never set a version show "Not set".

A “Change” text button opens the Change Collection Version modal: the current version, a free-form New Version text field, and a preview line ("Updates info.version in collection YAML" for yml / "Updates collectionVersion in bruno.json" for .bru, from → ). Update Version saves.

New collections default the version to 1 (yml info.version and .bru collectionVersion both default to "1"). Existing collections are not auto-migrated; the value is written only when the user sets one.

https://usebruno.atlassian.net/browse/BRU-2545

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.

image image

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added “Version” support to the collection overview, including an edit popup to update the collection’s version.
    • Added clearer handling for missing versions via a “Not Set” display.
  • Bug Fixes

    • Improved collection version persistence and round-tripping across YAML/BRU import, export, migration, and related configuration updates.
    • Updated version serialization and parsing to correctly write/read user-facing version fields.
  • Tests

    • Added/updated component and end-to-end coverage for version display, editing, previews, and conversion/migration behavior.
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds collection version support across editing, display, serialization, and migration paths. The UI can now change a collection’s version, and BRU/YAML formats map the value through collectionVersion or info.version as appropriate.

Changes

Collection Version Edit Feature

Layer / File(s) Summary
Types and version helpers
packages/bruno-converters/src/opencollection/types.ts, packages/bruno-app/src/utils/collections/index.js
BrunoConfig gains collectionVersion and opencollection, and shared helpers resolve the active version from collection format.
YAML parse and stringify version fields
packages/bruno-filestore/src/formats/yml/parseCollection.ts, packages/bruno-filestore/src/formats/yml/stringifyCollection.ts, packages/bruno-filestore/src/formats/yml/*.spec.ts
YAML collection parsing now reads info.version, and YAML serialization writes it back conditionally; tests cover missing, numeric, and round-trip cases.
OpenCollection conversion version mapping
packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts, packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts, packages/bruno-converters/tests/opencollection/collection-version.spec.js
Conversion now maps version values through the correct Bruno config field for BRU and OpenCollection collections, with import/export round-trip coverage.
Electron config persistence and Redux save flow
packages/bruno-electron/src/app/collections.js, packages/bruno-electron/src/ipc/collection.js, packages/bruno-electron/src/utils/collection-import.js, packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js, packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
Creation, import, migration, and update paths now carry collectionVersion, and the Redux save flow persists version edits through IPC and slice updates.
ChangeCollectionVersion modal and overview row
packages/bruno-app/src/components/CollectionSettings/Overview/Info/index.js, packages/bruno-app/src/components/CollectionSettings/Overview/Info/StyledWrapper.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/StyledWrapper.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.spec.js
The overview gains a Version row and yellow icon styling, and the new modal handles editing, previewing, copying, and missing-collection fallback.
Documentation version display
packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js, packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.spec.js, tests/collection/generate-docs/*
Documentation version display now renders unset values as Not Set, uses the shared version helper, and updates related tests and fixture data.
Playwright coverage for version changes and migration
tests/collection/change-version/*, tests/collection/change-version-bru/*, tests/collection/migrate-to-yml/*
End-to-end tests cover version editing for YAML and BRU collections, migration output, and persisted file updates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • usebruno/bruno#7669: Touches the same CollectionSettings/Overview/Info component that now gains the Version row and modal entry point.
  • usebruno/bruno#8268: Modifies the same documentation version display area that now renders Not Set and uses the shared version helper.
  • usebruno/bruno#6735: Works in the YAML import/export and collection format plumbing that this PR extends for version handling.

Suggested reviewers: helloanoop, bijin-bruno, lohit-bruno, sid-bruno

Poem

A version found its place at last,
in BRU and YAML, held fast.
From modal click to disk-bound write,
the strings now travel straight and right.
No semver masks, just values clear,
and “Not Set” when none is here ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change: adding editable Bruno collection version support in the collection overview.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@sachin-bruno sachin-bruno force-pushed the sachin-bruno/feature-collection-version-edit branch from 042d893 to aeb5890 Compare June 30, 2026 08:17

@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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/bruno-electron/src/utils/collection-import.js (1)

96-116: 🗄️ Data Integrity & Integration | ��� Major | ⚡ Quick win

Don't overwrite an imported YAML version here either.

This helper has the same regression: when brunoConfig.version exists on an OpenCollection import but collectionVersion does not, Line 97 backfills '1', and Lines 113-115 then persist that fallback as the YAML version. Existing collection versions get rewritten on import.

Suggested fix
-    } else if (!brunoConfig.collectionVersion) {
-      brunoConfig.collectionVersion = '1';
+    } else if (!brunoConfig.collectionVersion) {
+      brunoConfig.collectionVersion = brunoConfig.opencollection
+        ? (brunoConfig.version || '1')
+        : '1';
     }
🤖 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/bruno-electron/src/utils/collection-import.js` around lines 96 -
116, The YAML import path in collection-import.js is still overwriting an
existing imported version by backfilling collectionVersion to '1' and then
copying it into brunoConfig.version. Update getBrunoJsonConfig and the format
=== 'yml' branch so that an existing brunoConfig.version is preserved for
OpenCollection imports, only defaulting when neither version nor
collectionVersion is present, and avoid assigning the fallback value back into
the exported YAML version.
packages/bruno-electron/src/ipc/collection.js (1)

1395-1427: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve imported OpenCollection versions instead of forcing '1'.

If the source YAML already populated brunoConfig.version but not collectionVersion, Line 1395 backfills collectionVersion = '1', and Lines 1424-1426 immediately copy that fallback back into version. That rewrites an existing info.version to "1" during import. Seed collectionVersion from the existing YAML version first, and only default to '1' when neither field exists.

Suggested fix
-          } else if (!brunoConfig.collectionVersion) {
-            // Imports create new collection files; default the user-facing version when the
-            // source didn't carry one (a present version, e.g. OpenCollection info.version, is kept).
-            brunoConfig.collectionVersion = '1';
+          } else if (!brunoConfig.collectionVersion) {
+            brunoConfig.collectionVersion = brunoConfig.opencollection
+              ? (brunoConfig.version || '1')
+              : '1';
           }
🤖 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/bruno-electron/src/ipc/collection.js` around lines 1395 - 1427, The
import path in collection handling is overwriting an existing
OpenCollection/YAML version by defaulting brunoConfig.collectionVersion to '1'
when only brunoConfig.version is present, then later copying that fallback back
into version. Update the logic in getBrunoJsonConfig and the subsequent format
=== 'yml' mapping so collectionVersion is seeded from an existing version first,
and only falls back to '1' when both version and collectionVersion are missing.
Preserve the original imported version for brunoConfig.opencollection imports
and keep the delete of collectionVersion after mapping unchanged.
🧹 Nitpick comments (1)
tests/collection/change-version/change-version.spec.ts (1)

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

Avoid styling-class selectors in this E2E assertion.

preview.locator('.old') and .new tie the spec to modal internals instead of observable behavior, so a markup/style refactor can break the test without changing the feature. Prefer asserting the visible preview text or exposing dedicated data-testids for the old/new values. As per coding guidelines, "E2E tests must verify user-visible behaviour, not implementation details." As per path instructions, "Replace brittle text/index selectors with role, label, test id, or stable user-facing selectors."

🤖 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 `@tests/collection/change-version/change-version.spec.ts` around lines 43 - 47,
The change-version E2E assertion is using brittle styling-class selectors for
the preview values, so update the test in change-version.spec.ts to avoid
preview.locator('.old') and .new. Use user-visible text assertions or stable
dedicated data-testid hooks on the change-version-preview elements so the test
targets observable behavior instead of modal internals.

Sources: Coding guidelines, Path instructions

🤖 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.

Inline comments:
In `@packages/bruno-app/src/components/CollectionSettings/Overview/Info/index.js`:
- Line 24: The collection version row is using getCollectionVersion() in a way
that hides the “Not Set” state for legacy YAML collections because the helper
falls back to a default version. Update the Info component’s collectionVersion
handling to read from the explicitly persisted version field (or change
getCollectionVersion() so it only returns a saved value and no YAML fallback),
and keep “Not Set” as the display until the user saves a version. Make sure the
fix preserves the existing behavior for OpenCollection without auto-migrating
legacy data.
- Around line 52-67: The Version row in the Overview Info component is
implemented as a clickable div, which prevents proper keyboard activation.
Update the interactive wrapper around the Version label and Change action in
Info to use a real button (or equivalent semantic control) while preserving the
existing onClick that opens ChangeCollectionVersion. Keep the current
layout/styling and data-testid hooks intact so the action remains accessible via
Tab, Enter, and Space.

In
`@packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.js`:
- Around line 44-55: The submit guard in ChangeCollectionVersion/index.js is
blocking the “clear version” flow because canSubmit requires
trimmedVersion.length > 0; update the canSubmit logic so an empty trimmedVersion
is allowed when it differs from currentVersion, while still preventing no-op
submits. Keep the change localized to the change handler flow around
trimmedVersion, canSubmit, and handleConfirm so saveCollectionVersion() can
receive an empty string and clear the stored collectionVersion.

In `@packages/bruno-app/src/utils/collections/index.js`:
- Around line 1264-1267: The version helper for OpenCollection YAML collections
is reintroducing a hardcoded fallback, which prevents missing versions from
staying unset. Update getCollectionVersion in collections/index.js so it returns
only the stored brunoConfig.version and does not substitute '1'; keep the
defaulting behavior only in the new-collection creation flow where
brunoConfig.version is initially seeded. Make sure the logic around
isOpenCollectionFormat and the version-clearing reducer still allows the value
to remain absent.

In `@packages/bruno-converters/tests/opencollection/collection-version.spec.js`:
- Around line 1-45: The collection-version tests are missing coverage for the
cleared-version case, even though both converter directions treat an empty
string as unset. Update the existing openCollectionToBruno and
brunoToOpenCollection specs to assert that info.version: '' imports to an
undefined brunoConfig.collectionVersion, and that an empty collectionVersion
exports to no info.version. Use the current converter entry points
brunoToOpenCollection and openCollectionToBruno so refactors can’t reintroduce
empty-string versions.

In `@packages/bruno-filestore/src/formats/yml/stringifyCollection.spec.ts`:
- Around line 51-77: The version serialization tests in stringifyCollection
should also cover the empty-string clear-version path, since stringifyCollection
special-cases version === ''. Add an explicit assertion in
stringifyCollection.spec that passes version: '' through stringifyCollection and
verifies parseCollection reads back an empty string (or the expected cleared
value), alongside the existing undefined and free-form version cases.

---

Outside diff comments:
In `@packages/bruno-electron/src/ipc/collection.js`:
- Around line 1395-1427: The import path in collection handling is overwriting
an existing OpenCollection/YAML version by defaulting
brunoConfig.collectionVersion to '1' when only brunoConfig.version is present,
then later copying that fallback back into version. Update the logic in
getBrunoJsonConfig and the subsequent format === 'yml' mapping so
collectionVersion is seeded from an existing version first, and only falls back
to '1' when both version and collectionVersion are missing. Preserve the
original imported version for brunoConfig.opencollection imports and keep the
delete of collectionVersion after mapping unchanged.

In `@packages/bruno-electron/src/utils/collection-import.js`:
- Around line 96-116: The YAML import path in collection-import.js is still
overwriting an existing imported version by backfilling collectionVersion to '1'
and then copying it into brunoConfig.version. Update getBrunoJsonConfig and the
format === 'yml' branch so that an existing brunoConfig.version is preserved for
OpenCollection imports, only defaulting when neither version nor
collectionVersion is present, and avoid assigning the fallback value back into
the exported YAML version.

---

Nitpick comments:
In `@tests/collection/change-version/change-version.spec.ts`:
- Around line 43-47: The change-version E2E assertion is using brittle
styling-class selectors for the preview values, so update the test in
change-version.spec.ts to avoid preview.locator('.old') and .new. Use
user-visible text assertions or stable dedicated data-testid hooks on the
change-version-preview elements so the test targets observable behavior instead
of modal internals.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 98ac1ada-7dc2-47c4-9586-a796587d9bd9

📥 Commits

Reviewing files that changed from the base of the PR and between 49b9af1 and aeb5890.

📒 Files selected for processing (33)
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/StyledWrapper.js
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/StyledWrapper.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.spec.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts
  • packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts
  • packages/bruno-converters/src/opencollection/types.ts
  • packages/bruno-converters/tests/opencollection/collection-version.spec.js
  • packages/bruno-electron/src/app/collections.js
  • packages/bruno-electron/src/ipc/collection.js
  • packages/bruno-electron/src/utils/collection-import.js
  • packages/bruno-filestore/src/formats/yml/parseCollection.spec.ts
  • packages/bruno-filestore/src/formats/yml/parseCollection.ts
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.spec.ts
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.ts
  • tests/collection/change-version-bru/change-version-bru.spec.ts
  • tests/collection/change-version-bru/fixtures/collection/bruno.json
  • tests/collection/change-version-bru/init-user-data/preferences.json
  • tests/collection/change-version/change-version.spec.ts
  • tests/collection/change-version/fixtures/collection/opencollection.yml
  • tests/collection/change-version/init-user-data/preferences.json
  • tests/collection/generate-docs/fixtures/collection/bruno.json
  • tests/collection/generate-docs/generate-docs.spec.ts
  • tests/collection/migrate-to-yml/fixtures/collection/bruno.json
  • tests/collection/migrate-to-yml/migrate-to-yml.spec.ts
Comment thread packages/bruno-app/src/utils/collections/index.js
@sachin-bruno sachin-bruno force-pushed the sachin-bruno/feature-collection-version-edit branch from fef1ad2 to 65a9d08 Compare July 1, 2026 18:41

const handleCopy = () => {
if (!trimmedVersion) return;
navigator.clipboard?.writeText(trimmedVersion);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we need optional chaining here? if navigator.clipboard is not available, it doesn't make sense to setCopied as true.

Comment on lines +73 to +74
title="Change Collection Version"
customHeader={<ModalTitle>Change Collection Version</ModalTitle>}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
title="Change Collection Version"
customHeader={<ModalTitle>Change Collection Version</ModalTitle>}
customHeader={<ModalTitle>Change Collection Version</ModalTitle>}

@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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
tests/collection/change-version-bru/change-version-bru.spec.ts (1)

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

Hoist the reused Playwright locators.

These steps keep re-resolving the same test ids, which makes failures noisier than necessary. Please store the modal/value/button locators once and reuse them across the steps. As per path instructions, "Use locator variables for locators".

🤖 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 `@tests/collection/change-version-bru/change-version-bru.spec.ts` around lines
26 - 47, The Playwright test in change-version-bru.spec.ts keeps re-querying the
same test ids across steps, so hoist the repeated locators into variables and
reuse them throughout the scenario. Update the relevant step setup around the
overview/version flow to store the version value, change button, current value,
input, and submit button locators once, then reference those variables in each
step instead of calling getByTestId repeatedly.

Source: Path instructions

tests/collection/change-version/change-version.spec.ts (1)

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

Avoid CSS-class selectors in this E2E assertion.

.old and .new are presentation hooks, so a style-only rename will break the test without changing user behavior. Please expose stable test ids for the preview values (or assert the full preview text) and use those here instead. As per coding guidelines, "Add data-testid to testable elements for Playwright"; as per path instructions, "Replace brittle text/index selectors with role, label, test id, or stable user-facing selectors".

🤖 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 `@tests/collection/change-version/change-version.spec.ts` around lines 43 - 47,
The E2E assertion in the change-version preview is relying on brittle CSS class
selectors, which should be replaced with stable test hooks. Update the preview
component that renders the old/new values so it exposes testable identifiers
(for example in the change-version preview UI), then change the assertions in
change-version.spec.ts to target those stable identifiers or assert the full
preview text instead of using .old and .new.

Sources: Coding guidelines, Path instructions

🤖 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.

Inline comments:
In `@packages/bruno-electron/src/ipc/collection.js`:
- Around line 1395-1398: `collectionVersion` is being checked with truthiness in
the import/migration flow, which incorrectly treats `0` as missing and can reset
or drop valid numeric versions. Update the null handling in the `collection.js`
paths around `brunoConfig.collectionVersion` and `info.version` to use explicit
null/undefined checks instead of falsy checks, so imported versions round-trip
correctly without changing `0`.
- Around line 1711-1722: The save flow in collection.js should not continue when
`collectionRoot` is missing and `parseCollection()` fails while recovering the
YAML root. Update the `rootToWrite` recovery path so that the `catch` in the
`opencollection.yml` read/parse block surfaces the failure instead of falling
back to `collectionRoot`, and prevent `stringifyCollection()` from writing when
the root cannot be reconstructed. Use the `rootToWrite`, `parseCollection()`,
and `stringifyCollection()` logic in this handler to fail the save with an error
rather than overwriting the existing document payload.

---

Nitpick comments:
In `@tests/collection/change-version-bru/change-version-bru.spec.ts`:
- Around line 26-47: The Playwright test in change-version-bru.spec.ts keeps
re-querying the same test ids across steps, so hoist the repeated locators into
variables and reuse them throughout the scenario. Update the relevant step setup
around the overview/version flow to store the version value, change button,
current value, input, and submit button locators once, then reference those
variables in each step instead of calling getByTestId repeatedly.

In `@tests/collection/change-version/change-version.spec.ts`:
- Around line 43-47: The E2E assertion in the change-version preview is relying
on brittle CSS class selectors, which should be replaced with stable test hooks.
Update the preview component that renders the old/new values so it exposes
testable identifiers (for example in the change-version preview UI), then change
the assertions in change-version.spec.ts to target those stable identifiers or
assert the full preview text instead of using .old and .new.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d7714d57-cbd4-4111-930b-f5af375dde18

📥 Commits

Reviewing files that changed from the base of the PR and between aeb5890 and 65a9d08.

📒 Files selected for processing (33)
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/StyledWrapper.js
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/StyledWrapper.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.spec.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts
  • packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts
  • packages/bruno-converters/src/opencollection/types.ts
  • packages/bruno-converters/tests/opencollection/collection-version.spec.js
  • packages/bruno-electron/src/app/collections.js
  • packages/bruno-electron/src/ipc/collection.js
  • packages/bruno-electron/src/utils/collection-import.js
  • packages/bruno-filestore/src/formats/yml/parseCollection.spec.ts
  • packages/bruno-filestore/src/formats/yml/parseCollection.ts
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.spec.ts
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.ts
  • tests/collection/change-version-bru/change-version-bru.spec.ts
  • tests/collection/change-version-bru/fixtures/collection/bruno.json
  • tests/collection/change-version-bru/init-user-data/preferences.json
  • tests/collection/change-version/change-version.spec.ts
  • tests/collection/change-version/fixtures/collection/opencollection.yml
  • tests/collection/change-version/init-user-data/preferences.json
  • tests/collection/generate-docs/fixtures/collection/bruno.json
  • tests/collection/generate-docs/generate-docs.spec.ts
  • tests/collection/migrate-to-yml/fixtures/collection/bruno.json
  • tests/collection/migrate-to-yml/migrate-to-yml.spec.ts
✅ Files skipped from review due to trivial changes (8)
  • tests/collection/change-version/init-user-data/preferences.json
  • tests/collection/change-version-bru/fixtures/collection/bruno.json
  • tests/collection/change-version/fixtures/collection/opencollection.yml
  • tests/collection/migrate-to-yml/fixtures/collection/bruno.json
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
  • tests/collection/change-version-bru/init-user-data/preferences.json
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/StyledWrapper.js
  • packages/bruno-filestore/src/formats/yml/parseCollection.spec.ts
🚧 Files skipped from review as they are similar to previous changes (21)
  • tests/collection/migrate-to-yml/migrate-to-yml.spec.ts
  • tests/collection/generate-docs/fixtures/collection/bruno.json
  • packages/bruno-filestore/src/formats/yml/parseCollection.ts
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.spec.js
  • packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.ts
  • packages/bruno-electron/src/utils/collection-import.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/StyledWrapper.js
  • packages/bruno-converters/tests/opencollection/collection-version.spec.js
  • packages/bruno-electron/src/app/collections.js
  • packages/bruno-app/src/components/CollectionSettings/Overview/Info/index.js
  • tests/collection/generate-docs/generate-docs.spec.ts
  • packages/bruno-converters/src/opencollection/types.ts
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js
  • packages/bruno-filestore/src/formats/yml/stringifyCollection.spec.ts
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/ChangeCollectionVersion/index.js
  • packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
Comment on lines +1395 to +1398
} else if (!brunoConfig.collectionVersion) {
// Imports create new collection files; default the user-facing version when the
// source didn't carry one (a present version, e.g. OpenCollection info.version, is kept).
brunoConfig.collectionVersion = '1';

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use nullish checks for collectionVersion.

These truthiness checks treat 0 as “missing”, so an imported/migrated numeric version can be reset to '1' or dropped entirely before it reaches info.version. Please gate on null/undefined instead of falsiness so numeric versions round-trip correctly.

Proposed fix
-          } else if (!brunoConfig.collectionVersion) {
+          } else if (brunoConfig.collectionVersion == null) {
             // Imports create new collection files; default the user-facing version when the
             // source didn't carry one (a present version, e.g. OpenCollection info.version, is kept).
             brunoConfig.collectionVersion = '1';
           }
...
-          if (brunoConfig.collectionVersion) {
+          if (brunoConfig.collectionVersion != null) {
             brunoConfig.version = brunoConfig.collectionVersion;
           }
...
-      if (ymlBrunoConfig.collectionVersion) {
+      if (ymlBrunoConfig.collectionVersion != null) {
         ymlBrunoConfig.version = ymlBrunoConfig.collectionVersion;
       }

Also applies to: 1424-1426, 2700-2703

🤖 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/bruno-electron/src/ipc/collection.js` around lines 1395 - 1398,
`collectionVersion` is being checked with truthiness in the import/migration
flow, which incorrectly treats `0` as missing and can reset or drop valid
numeric versions. Update the null handling in the `collection.js` paths around
`brunoConfig.collectionVersion` and `info.version` to use explicit
null/undefined checks instead of falsy checks, so imported versions round-trip
correctly without changing `0`.
Comment on lines +1711 to +1722
if (!rootToWrite) {
const ocYmlPath = path.join(collectionPath, 'opencollection.yml');
if (fs.existsSync(ocYmlPath)) {
try {
const existing = fs.readFileSync(ocYmlPath, 'utf8');
rootToWrite = parseCollection(existing, { format }).collectionRoot;
} catch (e) {
rootToWrite = collectionRoot;
}
}
}
const content = await stringifyCollection(rootToWrite, transformedBrunoConfig, { format });

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Fail the save if the YAML root cannot be recovered.

If collectionRoot is omitted and parseCollection() throws here, rootToWrite stays unset and the handler still writes opencollection.yml. That turns a config-only update into a destructive overwrite of the existing root/documentation payload instead of surfacing the read/parse failure.

Proposed fix
         let rootToWrite = collectionRoot;
         if (!rootToWrite) {
           const ocYmlPath = path.join(collectionPath, 'opencollection.yml');
           if (fs.existsSync(ocYmlPath)) {
-            try {
-              const existing = fs.readFileSync(ocYmlPath, 'utf8');
-              rootToWrite = parseCollection(existing, { format }).collectionRoot;
-            } catch (e) {
-              rootToWrite = collectionRoot;
-            }
+            const existing = fs.readFileSync(ocYmlPath, 'utf8');
+            rootToWrite = parseCollection(existing, { format }).collectionRoot;
           }
         }
+        if (!rootToWrite) {
+          throw new Error('Unable to update YAML config without a collection root');
+        }
         const content = await stringifyCollection(rootToWrite, transformedBrunoConfig, { format });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!rootToWrite) {
const ocYmlPath = path.join(collectionPath, 'opencollection.yml');
if (fs.existsSync(ocYmlPath)) {
try {
const existing = fs.readFileSync(ocYmlPath, 'utf8');
rootToWrite = parseCollection(existing, { format }).collectionRoot;
} catch (e) {
rootToWrite = collectionRoot;
}
}
}
const content = await stringifyCollection(rootToWrite, transformedBrunoConfig, { format });
let rootToWrite = collectionRoot;
if (!rootToWrite) {
const ocYmlPath = path.join(collectionPath, 'opencollection.yml');
if (fs.existsSync(ocYmlPath)) {
const existing = fs.readFileSync(ocYmlPath, 'utf8');
rootToWrite = parseCollection(existing, { format }).collectionRoot;
}
}
if (!rootToWrite) {
throw new Error('Unable to update YAML config without a collection root');
}
const content = await stringifyCollection(rootToWrite, transformedBrunoConfig, { format });
🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 1714-1714: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(ocYmlPath, 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename)

🤖 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/bruno-electron/src/ipc/collection.js` around lines 1711 - 1722, The
save flow in collection.js should not continue when `collectionRoot` is missing
and `parseCollection()` fails while recovering the YAML root. Update the
`rootToWrite` recovery path so that the `catch` in the `opencollection.yml`
read/parse block surfaces the failure instead of falling back to
`collectionRoot`, and prevent `stringifyCollection()` from writing when the root
cannot be reconstructed. Use the `rootToWrite`, `parseCollection()`, and
`stringifyCollection()` logic in this handler to fail the save with an error
rather than overwriting the existing document payload.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. modal resizes with long string input.
  2. Add input validation for version?
<span className="version-value" data-testid="version-value">{`Version: ${version}`}</span>
) : null}
) : (
<span className="version-value unset" data-testid="version-value">Not Set</span>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not Set is probably unclear without a label

};

const config = toOpenCollectionConfig(collection.brunoConfig as BrunoConfig);
const brunoConfig = collection.brunoConfig as BrunoConfig | undefined;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is there any case were collection.brunoConfig is undefined ?


const isOpenCollectionFormat = Boolean(brunoConfig?.opencollection);
const collectionVersion = isOpenCollectionFormat ? brunoConfig?.version : brunoConfig?.collectionVersion;
if (openCollection.info && collectionVersion != null && collectionVersion !== '') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

openCollection.info is always truthy here

version: Yup.string().when('opencollection', {
is: (opencollection) => Boolean(opencollection),
then: Yup.string().notRequired(),
otherwise: Yup.string().oneOf(['1']).notRequired()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Might need to allow more values

Comment on lines +2 to +9
"maximized": false,
"lastOpenedCollections": ["{{collectionPath}}"],
"preferences": {
"onboarding": {
"hasLaunchedBefore": true,
"hasSeenWelcomeModal": true
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Keep only the fields which we want to override

Suggested change
"maximized": false,
"lastOpenedCollections": ["{{collectionPath}}"],
"preferences": {
"onboarding": {
"hasLaunchedBefore": true,
"hasSeenWelcomeModal": true
}
}
"lastOpenedCollections": ["{{collectionPath}}"],
Comment on lines +178 to +181
// bru only: the user-facing collection version (bruno.json key, sibling of the marker).
collectionVersion?: string;
// present only for OpenCollection (yml) collections; its presence marks the format.
opencollection?: string;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should avoid lang specific fields inside the app (BrunoConfig).

eg: if we have BrunoConfig.collectionVersion, it should map to collectionVersion in .bru and info.version in .yml/OpenCollection.

The internal model should remain format-agnostic, with the mapping handled by the respective parsers/serializers.

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

Labels

3 participants