Skip to content

Commit fb570b5

Browse files
committed
feat: handle branch in key/translation operations
1 parent e93cdaa commit fb570b5

File tree

17 files changed

+209
-19
lines changed

17 files changed

+209
-19
lines changed

backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/translation/TranslationsController.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ When null, resulting file will be a flat key-value object.
160160
)
161161
@RequestParam(value = "filterTag", required = false)
162162
filterTag: List<String>? = null,
163+
@Parameter(description = "Branch name to return translations from")
164+
branch: String? = null,
163165
request: WebRequest,
164166
): ResponseEntity<Map<String, Any>>? {
165167
val lastModified: Long = projectTranslationLastModifiedManager.getLastModified(projectHolder.project.id)
@@ -176,6 +178,7 @@ When null, resulting file will be a flat key-value object.
176178
translationService.getTranslations(
177179
languageTags = permittedTags,
178180
namespace = ns,
181+
branch = branch,
179182
projectId = projectHolder.project.id,
180183
structureDelimiter = request.getStructureDelimiter(),
181184
filterTag = filterTag,

backend/api/src/main/kotlin/io/tolgee/controllers/ExportController.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class ExportController(
6464
translationService.getTranslations(
6565
allLanguages.map { it.tag }.toSet(),
6666
null,
67+
null,
6768
projectHolder.project.id,
6869
'.',
6970
)

backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerViewTest.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,50 @@ class TranslationsControllerViewTest : ProjectAuthControllerTest("/v2/projects/"
105105
}
106106
}
107107

108+
@Test
109+
@ProjectJWTAuthTestMethod
110+
fun `return translations from non-branched keys`() {
111+
testData.generateBranchedData(10)
112+
testDataService.saveTestData(testData.root)
113+
userAccount = testData.user
114+
performProjectAuthGet("/translations?sort=id").andPrettyPrint.andIsOk.andAssertThatJson {
115+
// 2 keys from the default branch, 10 keys from the feature branch should be filtered out
116+
node("_embedded.keys").isArray.hasSize(2)
117+
}
118+
}
119+
120+
@Test
121+
@ProjectJWTAuthTestMethod
122+
fun `return translations from default branch only`() {
123+
testData.generateBranchedData(5, "main", true)
124+
testData.generateBranchedData(10)
125+
testDataService.saveTestData(testData.root)
126+
userAccount = testData.user
127+
performProjectAuthGet("/translations?sort=id").andPrettyPrint.andIsOk.andAssertThatJson {
128+
// 2 non-branched keys + 5 keys from the default branch, 10 keys from the feature branch should be filtered out
129+
node("_embedded.keys").isArray.hasSize(7)
130+
}
131+
}
132+
133+
@Test
134+
@ProjectJWTAuthTestMethod
135+
fun `return translations from featured branch only`() {
136+
testData.generateBranchedData(10)
137+
testDataService.saveTestData(testData.root)
138+
userAccount = testData.user
139+
performProjectAuthGet("/translations?sort=id&branch=feature-branch").andPrettyPrint.andIsOk.andAssertThatJson {
140+
// 10 keys from the feature branch should be returned
141+
node("_embedded.keys").isArray.hasSize(10)
142+
node("_embedded.keys[0].keyName").isEqualTo("key from branch feature-branch 1")
143+
node("_embedded.keys[0].translations.en") {
144+
node("text").isEqualTo("I am key 1's english translation from branch feature-branch.")
145+
}
146+
node("_embedded.keys[1].translations.de") {
147+
node("text").isEqualTo("I am key 2's german translation from branch feature-branch.")
148+
}
149+
}
150+
}
151+
108152
@Test
109153
@ProjectJWTAuthTestMethod
110154
fun `returns correct comment counts`() {

backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2KeyController/KeyControllerTest.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach
2323
import org.junit.jupiter.api.Test
2424
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
2525
import org.springframework.boot.test.context.SpringBootTest
26+
import java.math.BigDecimal
2627

2728
@SpringBootTest
2829
@AutoConfigureMockMvc
@@ -43,6 +44,7 @@ class KeyControllerTest : ProjectAuthControllerTest("/v2/projects/") {
4344
@Test
4445
fun `returns all keys`() {
4546
testData.addNKeys(120)
47+
testData.addNBranchedKeys(10)
4648
saveTestDataAndPrepare()
4749
performProjectAuthGet("keys")
4850
.andIsOk.andAssertThatJson {
@@ -53,6 +55,7 @@ class KeyControllerTest : ProjectAuthControllerTest("/v2/projects/") {
5355
node("[2].namespace").isEqualTo("null")
5456
node("[1].description").isEqualTo("description")
5557
}
58+
node("page.totalElements").isNumber.isEqualTo(BigDecimal(123))
5659
}
5760
performProjectAuthGet("keys?page=1")
5861
.andIsOk.andAssertThatJson {

backend/app/src/test/kotlin/io/tolgee/service/TranslationServiceTest.kt

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ class TranslationServiceTest : AbstractSpringTest() {
1818
val id = dbPopulator.populate().project.id
1919
val data =
2020
translationService.getTranslations(
21-
languageTags = HashSet(Arrays.asList("en", "de")),
21+
languageTags = HashSet(listOf("en", "de")),
2222
namespace = null,
23+
branch = null,
2324
projectId = id,
2425
structureDelimiter = '.',
2526
)
@@ -35,8 +36,9 @@ class TranslationServiceTest : AbstractSpringTest() {
3536

3637
val viewData =
3738
translationService.getTranslations(
38-
languageTags = HashSet(Arrays.asList("en", "de")),
39+
languageTags = HashSet(listOf("en", "de")),
3940
namespace = null,
41+
branch = null,
4042
projectId = project.id,
4143
structureDelimiter = '.',
4244
)
@@ -78,4 +80,53 @@ class TranslationServiceTest : AbstractSpringTest() {
7880
assertThat(translation.auto).isFalse
7981
assertThat(translation.mtProvider).isNull()
8082
}
83+
84+
@Test
85+
fun `returns translations for default branch`() {
86+
val testData = TranslationsTestData()
87+
testData.generateBranchedData(10)
88+
testDataService.saveTestData(testData.root)
89+
val translations = translationService.getTranslations(
90+
languageTags = HashSet(listOf("en", "de")),
91+
namespace = null,
92+
branch = null,
93+
projectId = testData.project.id,
94+
structureDelimiter = '.',
95+
)
96+
assertThat(translations).hasSize(2)
97+
assertThat(translations["en"] as LinkedHashMap<*, *>).hasSize(1)
98+
}
99+
100+
@Test
101+
@Transactional
102+
fun `returns translations for feature branch`() {
103+
val testData = TranslationsTestData()
104+
testData.generateBranchedData(10)
105+
testDataService.saveTestData(testData.root)
106+
val translations = translationService.getTranslations(
107+
languageTags = HashSet(listOf("en", "de")),
108+
namespace = null,
109+
branch = "feature-branch",
110+
projectId = testData.project.id,
111+
structureDelimiter = '.',
112+
)
113+
assertThat(translations).hasSize(2)
114+
assertThat(translations["en"] as LinkedHashMap<*, *>).hasSize(10)
115+
}
116+
117+
@Test
118+
@Transactional
119+
fun `returns empty translations for invalid branch name`() {
120+
val testData = TranslationsTestData()
121+
testData.generateBranchedData(5)
122+
testDataService.saveTestData(testData.root)
123+
val translations = translationService.getTranslations(
124+
languageTags = HashSet(listOf("en", "de")),
125+
namespace = null,
126+
branch = "invalid-branch",
127+
projectId = testData.project.id,
128+
structureDelimiter = '.',
129+
)
130+
assertThat(translations).hasSize(0)
131+
}
81132
}

backend/data/src/main/kotlin/io/tolgee/constants/Message.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ enum class Message {
312312
BRANCH_NOT_FOUND,
313313
CANNOT_DELETE_DEFAULT_BRANCH,
314314
BRANCH_ALREADY_EXISTS,
315+
ORIGIN_BRANCH_NOT_FOUND,
315316
;
316317

317318
val code: String

backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/KeysTestData.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,22 @@ class KeysTestData {
127127
}
128128
}
129129

130+
fun addNBranchedKeys(n: Int, branchName: String = "feature") {
131+
projectBuilder.apply {
132+
addBranch {
133+
name = branchName
134+
project = projectBuilder.self
135+
}.build {
136+
(1..n).forEach {
137+
addKey {
138+
name = "branch_key_$it"
139+
this.branch = self
140+
}
141+
}
142+
}
143+
}
144+
}
145+
130146
fun addThirdKey(): Key {
131147
return projectBuilder.addKey("third_key").self
132148
}

backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/TranslationsTestData.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,32 @@ class TranslationsTestData {
248248
}
249249
}
250250

251+
fun generateBranchedData(count: Long, branchName: String = "feature-branch", isBranchDefault: Boolean = false) {
252+
root.data.projects[0].apply {
253+
addBranch {
254+
name = branchName
255+
project = this@apply.self
256+
isDefault = isBranchDefault
257+
}.build {
258+
(1..count).forEach {
259+
addKey {
260+
name = "key from branch $branchName $it"
261+
branch = this@build.self
262+
}.build {
263+
addTranslation {
264+
language = germanLanguage
265+
text = "I am key $it's german translation from branch $branchName."
266+
}
267+
addTranslation {
268+
language = englishLanguage
269+
text = "I am key $it's english translation from branch $branchName."
270+
}
271+
}
272+
}
273+
}
274+
}
275+
}
276+
251277
fun addFewKeysWithTags() {
252278
root.data.projects[0].apply {
253279
addKey {

backend/data/src/main/kotlin/io/tolgee/dtos/request/translation/TranslationFilters.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,9 @@ To filter default namespace, set to empty string.
157157
description = "Filter keys with no suggestions in lang",
158158
)
159159
var filterHasNoSuggestionsInLang: List<String>? = null
160+
161+
@field:Parameter(
162+
description = "Selects only keys from specified branch",
163+
)
164+
var branch: String? = null
160165
}

backend/data/src/main/kotlin/io/tolgee/repository/KeyRepository.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ interface KeyRepository : JpaRepository<Key, Long> {
139139
""",
140140
countQuery = """
141141
select count(k) from Key k
142-
where k.project.id = :projectId
142+
left join k.branch b
143+
where k.project.id = :projectId and (k.branch.id is null or b.isDefault)
143144
""",
144145
)
145146
fun getAllByProjectId(

0 commit comments

Comments
 (0)