Skip to content

feat: add branching support to single-step import - #3471

Merged
bdshadow merged 3 commits into
mainfrom
dkrizan/branching-single-step-import
Feb 17, 2026
Merged

feat: add branching support to single-step import#3471
bdshadow merged 3 commits into
mainfrom
dkrizan/branching-single-step-import

Conversation

@dkrizan

@dkrizan dkrizan commented Feb 16, 2026

Copy link
Copy Markdown
Member

Summary

  • Fixes single-step import to properly support branching by resolving the branch via BranchService.getActiveOrDefault and setting it on the Import entity, instead of relying on StoredDataImporter to look up the branch from project.branches
  • Adds ProjectFeatureGuard.checkIfUsed validation in the controller to reject branch params when the branching feature is not enabled
  • Adds comprehensive EE tests covering import to specific branch, default branch fallback, branch isolation, feature gate enforcement, and non-existent branch handling

Test plan

  • Import to specified branch assigns keys to that branch
  • Import without branch param assigns keys to default branch
  • Keys imported to a branch are not visible on default branch
  • Specifying branch when feature is disabled returns 400
  • Import without branch works when feature is disabled
  • Non-existent branch returns 404

Summary by CodeRabbit

  • New Features

    • Branch-aware import: import directly into a specified branch when branching is enabled; defaults to main branch when unspecified. Import attempts to a branch now enforce branching feature availability.
  • Tests

    • Added end-to-end tests covering imports to feature and default branches, visibility rules, error cases for disabled or non-existent branches, and improved test teardown for isolation.

@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This pull request implements branch-aware single-step file import functionality. Changes include feature guard enforcement in the controller, branch resolution and storage in the service layer, and comprehensive test coverage for various branching scenarios.

Changes

Cohort / File(s) Summary
Feature Guard Enforcement
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/SingleStepImportController.kt
Added ProjectFeatureGuard dependency injection and branching feature check before processing files in the singleStepFromFiles flow.
Service Layer Branch Handling
backend/data/src/main/kotlin/io/tolgee/service/dataImport/SingleStepImportService.kt, backend/data/src/main/kotlin/io/tolgee/service/dataImport/StoredDataImporter.kt
Injected BranchService into SingleStepImportService and added getBranch helper to resolve branches. Removed redundant branch resolution from StoredDataImporter by simplifying createNewKey signature and using import.branch directly.
Test Data and Setup
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/SingleStepImportBranchTestData.kt
Created new test data class that establishes German language, default branch, and feature branch for branch-aware import testing.
Test Coverage
ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt
Added comprehensive test suite with 6 test cases covering: imports to specified branch, imports to default branch, cross-branch visibility, feature flag enforcement, non-existent branch handling, and feature disable scenarios.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Controller as SingleStepImportController
    participant Guard as ProjectFeatureGuard
    participant Service as SingleStepImportService
    participant BranchSvc as BranchService
    participant Importer as StoredDataImporter
    participant DB as Database

    Client->>Controller: POST single-step import with branch param
    Controller->>Guard: checkIfUsed(BRANCHING, branch)
    Guard->>DB: verify feature enabled
    alt Feature not enabled & branch specified
        Guard-->>Controller: throw exception
        Controller-->>Client: 400 error
    else Feature enabled or no branch
        Controller->>Service: singleStepImport(files, params)
        Service->>BranchSvc: getActiveOrDefault(projectId, branch)
        BranchSvc-->>Service: Branch entity
        Service->>Importer: process with branch-aware Import
        Importer->>DB: store keys with branch reference
        DB-->>Importer: success
        Importer-->>Service: import complete
        Service-->>Controller: result
        Controller-->>Client: success response
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #3246: Main PR introducing branching checks and branch propagation to single-step import controller/service infrastructure that these changes build upon.

Suggested reviewers

  • JanCizmar
  • bdshadow
  • gabrielshanahan

Poem

🐰 Branch by branch, files now flow,
Through guarded gates, where features show,
Default or custom, each in its place,
Import spreads wide with elegant grace!

🚥 Pre-merge checks | ✅ 3 | ❌ 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 (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add branching support to single-step import' accurately summarizes the main change: adding branching functionality to the single-step import feature.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dkrizan/branching-single-step-import

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.

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
backend/data/src/main/kotlin/io/tolgee/service/dataImport/SingleStepImportService.kt (1)

106-172: ⚠️ Potential issue | 🟡 Minor

Add feature guard check to singleStepResolvableImport endpoint or clarify branching limitation.

The singleStepResolvableImport controller endpoint lacks a projectFeatureGuard.checkIfUsed(Feature.BRANCHING, ...) check, unlike the regular singleStepFromFiles endpoint. Additionally, SingleStepImportResolvableRequest has no branch field to forward to the import logic, meaning the resolvable import path cannot support branching. Either add the feature guard (and branch field to the request DTO) if branching should be supported, or add a comment documenting that branching is intentionally unsupported for resolvable imports.

🤖 Fix all issues with AI agents
In
`@ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt`:
- Around line 35-41: Add an `@AfterEach` teardown to mirror the setup: implement a
method (annotated with `@AfterEach`) that calls
testDataService.cleanTestData(testData.root) and resets
enabledFeaturesProvider.forceEnabled = null to avoid test state leakage; place
it alongside the existing setup() in SingleStepImportBranchingTest so it runs
after each test and uses the same testData instance created in setup().
🧹 Nitpick comments (3)
backend/data/src/main/kotlin/io/tolgee/service/dataImport/SingleStepImportService.kt (1)

155-161: Unnecessary block wrapping for single-expression branches.

These when branches now wrap single expressions in {} blocks. While harmless, it's inconsistent with typical Kotlin style where single-expression branches don't need braces. Minor nit — not blocking.

backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/dataImport/SingleStepImportBranchTestData.kt (1)

7-7: germanLanguage appears unused.

This member is declared but none of the tests in SingleStepImportBranchingTest reference it. If it's not needed, consider removing it to keep the test data minimal.

#!/bin/bash
# Verify if germanLanguage is referenced anywhere
rg -n 'germanLanguage' --type=kt
ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt (1)

27-28: newJson resource is declared but never used in any test.

Consider removing it to avoid confusion.

Comment on lines +35 to +41
@BeforeEach
fun setup() {
testData = SingleStepImportBranchTestData()
testDataService.saveTestData(testData.root)
userAccount = testData.user
projectSupplier = { testData.project }
}

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the ProjectAuthControllerTest base class and check for cleanup methods
fd 'ProjectAuthControllerTest' --type f -e kt

Repository: tolgee/tolgee-platform

Length of output: 136


🏁 Script executed:

# Search for `@AfterEach` and cleanup methods in the base class area
rg -n '@AfterEach|fun tearDown|fun cleanup' --type=kt -C5 | head -100

Repository: tolgee/tolgee-platform

Length of output: 92


🏁 Script executed:

# Check how enabledFeaturesProvider.forceEnabled is used in tests
rg -n 'forceEnabled|enabledFeaturesProvider' --type=kt -C3 | head -150

Repository: tolgee/tolgee-platform

Length of output: 92


🏁 Script executed:

# Look at the full SingleStepImportBranchingTest file to understand its structure
fd 'SingleStepImportBranchingTest' --type f -e kt -exec cat -n {} \;

Repository: tolgee/tolgee-platform

Length of output: 296


🏁 Script executed:

# Read the ProjectAuthControllerTest base class
cat -n backend/testing/src/main/kotlin/io/tolgee/ProjectAuthControllerTest.kt

Repository: tolgee/tolgee-platform

Length of output: 4396


🏁 Script executed:

# Search for `@AfterEach` and forceEnabled with correct rg syntax
rg '@AfterEach|tearDown|cleanup' -A 5 --type-list | grep -i kotlin

Repository: tolgee/tolgee-platform

Length of output: 455


🏁 Script executed:

# Read the SingleStepImportBranchingTest file
cat -n ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt | head -100

Repository: tolgee/tolgee-platform

Length of output: 4058


🏁 Script executed:

# Search for forceEnabled usage
rg 'forceEnabled' -C 3 | head -100

Repository: tolgee/tolgee-platform

Length of output: 11342


🏁 Script executed:

# Get complete SingleStepImportBranchingTest file
cat ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt | wc -l

Repository: tolgee/tolgee-platform

Length of output: 69


🏁 Script executed:

# Get the full file content
tail -n +100 ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt

Repository: tolgee/tolgee-platform

Length of output: 1152


🏁 Script executed:

# Check the AuthorizedControllerTest parent class
find . -name "AuthorizedControllerTest.kt" -type f

Repository: tolgee/tolgee-platform

Length of output: 145


🏁 Script executed:

# Check AuthorizedControllerTest for cleanup methods
cat -n ./backend/testing/src/main/kotlin/io/tolgee/testing/AuthorizedControllerTest.kt | head -150

Repository: tolgee/tolgee-platform

Length of output: 5093


🏁 Script executed:

# Check the entire file length first
wc -l ./backend/testing/src/main/kotlin/io/tolgee/testing/AuthorizedControllerTest.kt

Repository: tolgee/tolgee-platform

Length of output: 149


🏁 Script executed:

# Check AbstractControllerTest to see if it has testDataService cleanup
fd 'AbstractControllerTest.kt' --type f

Repository: tolgee/tolgee-platform

Length of output: 141


🏁 Script executed:

# Check if there's a testDataService cleanup pattern used elsewhere
rg 'testDataService.cleanTestData' -A 2 -B 2 | head -50

Repository: tolgee/tolgee-platform

Length of output: 5395


🏁 Script executed:

# Verify the pattern in AbstractControllerTest
cat -n backend/testing/src/main/kotlin/io/tolgee/testing/AbstractControllerTest.kt | grep -A 5 -B 5 'testDataService\|@AfterEach'

Repository: tolgee/tolgee-platform

Length of output: 48


Add @AfterEach cleanup method to reset test state.

The test sets enabledFeaturesProvider.forceEnabled and creates test data via testDataService.saveTestData() but never cleans up. This causes state leakage across test runs. Following the established pattern in similar tests (e.g., GlossaryTermControllerTest, SsoProviderControllerTest), add an @AfterEach method that calls testDataService.cleanTestData(testData.root) and resets enabledFeaturesProvider.forceEnabled = null.

🤖 Prompt for AI Agents
In
`@ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/branching/SingleStepImportBranchingTest.kt`
around lines 35 - 41, Add an `@AfterEach` teardown to mirror the setup: implement
a method (annotated with `@AfterEach`) that calls
testDataService.cleanTestData(testData.root) and resets
enabledFeaturesProvider.forceEnabled = null to avoid test state leakage; place
it alongside the existing setup() in SingleStepImportBranchingTest so it runs
after each test and uses the same testData instance created in setup().

@dkrizan
dkrizan requested a review from bdshadow February 16, 2026 19:44
@bdshadow
bdshadow merged commit a4e87e7 into main Feb 17, 2026
41 checks passed
@bdshadow
bdshadow deleted the dkrizan/branching-single-step-import branch February 17, 2026 07:57
TolgeeMachine added a commit that referenced this pull request Feb 17, 2026
# [3.158.0](v3.157.0...v3.158.0) (2026-02-17)

### Features

* add branching support to single-step import ([#3471](#3471)) ([a4e87e7](a4e87e7))
@coderabbitai coderabbitai Bot mentioned this pull request Mar 2, 2026
6 tasks
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