Skip to content

Commit 134d492

Browse files
authored
Merge pull request #999 from modelix/feat/bulk-sync-exclude-modules
MODELIX-851 Add option to exclude modules by name in bulk-sync plugin
2 parents 71db0f9 + 39c1dfa commit 134d492

File tree

13 files changed

+412
-21
lines changed

13 files changed

+412
-21
lines changed

bulk-model-sync-gradle/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies {
1313
implementation(libs.ktor.client.cio)
1414
testImplementation(libs.kotest.assertions.coreJvm)
1515
testImplementation(kotlin("test"))
16+
testImplementation(gradleTestKit())
1617
}
1718

1819
gradlePlugin {
@@ -36,5 +37,6 @@ tasks.named("processResources") {
3637
}
3738

3839
tasks.test {
40+
setEnvironment("MODELIX_CORE_PATH" to rootDir.absolutePath)
3941
useJUnitPlatform()
4042
}

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/ModelSyncGradlePlugin.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ class ModelSyncGradlePlugin : Plugin<Project> {
131131
it.outputDir.set(jsonDir)
132132
it.includedModules.set(syncDirection.includedModules)
133133
it.includedModulePrefixes.set(syncDirection.includedModulePrefixes)
134+
it.excludedModules.set(syncDirection.excludedModules)
135+
it.excludedModulePrefixes.set(syncDirection.excludedModulePrefixes)
134136
it.requestTimeoutSeconds.set(serverSource.requestTimeoutSeconds)
135137
}
136138
return exportFromModelServer
@@ -167,6 +169,8 @@ class ModelSyncGradlePlugin : Plugin<Project> {
167169
it.branchName.set(serverTarget.branchName)
168170
it.includedModules.set(syncDirection.includedModules)
169171
it.includedModulePrefixes.set(syncDirection.includedModulePrefixes)
172+
it.excludedModules.set(syncDirection.excludedModules)
173+
it.excludedModulePrefixes.set(syncDirection.excludedModulePrefixes)
170174
it.continueOnError.set(syncDirection.continueOnError)
171175
it.requestTimeoutSeconds.set(serverTarget.requestTimeoutSeconds)
172176
it.metaProperties.set(serverTarget.metaProperties)

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/MpsRunnerConfiguration.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ internal fun buildMpsRunConfigurationForLocalSources(
3737
",",
3838
)
3939
}",
40+
"-Dmodelix.mps.model.sync.bulk.output.modules.excluded=${syncDirection.excludedModules.joinToString(",")}",
41+
"-Dmodelix.mps.model.sync.bulk.output.modules.prefixes.excluded=${
42+
syncDirection.excludedModulePrefixes.joinToString(
43+
",",
44+
)
45+
}",
4046
"-Dmodelix.mps.model.sync.bulk.repo.path=${localSource.repositoryDir?.absolutePath}",
4147
"-Xmx${localSource.mpsHeapSize}",
4248
localSource.mpsDebugPort?.let { "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=$it" },
@@ -68,10 +74,19 @@ internal fun buildMpsRunConfigurationForLocalTarget(
6874
plugins = createPluginConfig(localTarget.mpsPlugins),
6975
jvmArgs = buildList {
7076
add("-Dmodelix.mps.model.sync.bulk.input.path=${jsonDir.absolutePath}")
71-
val includeModuleValue = syncDirection.includedModules.joinToString(",")
72-
add("-Dmodelix.mps.model.sync.bulk.input.modules=$includeModuleValue")
73-
val includeModulePrefixesValue = syncDirection.includedModulePrefixes.joinToString(",")
74-
add("-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=$includeModulePrefixesValue")
77+
78+
val includedModulesValue = syncDirection.includedModules.joinToString(",")
79+
add("-Dmodelix.mps.model.sync.bulk.input.modules=$includedModulesValue")
80+
81+
val includedModulePrefixesValue = syncDirection.includedModulePrefixes.joinToString(",")
82+
add("-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=$includedModulePrefixesValue")
83+
84+
val excludedModulesValue = syncDirection.excludedModules.joinToString(",")
85+
add("-Dmodelix.mps.model.sync.bulk.input.modules.excluded=$excludedModulesValue")
86+
87+
val excludedModulePrefixesValue = syncDirection.excludedModulePrefixes.joinToString(",")
88+
add("-Dmodelix.mps.model.sync.bulk.input.modules.prefixes.excluded=$excludedModulePrefixesValue")
89+
7590
add("-Dmodelix.mps.model.sync.bulk.repo.path=${repositoryDir.absolutePath}")
7691
add("-Dmodelix.mps.model.sync.bulk.input.continueOnError=${syncDirection.continueOnError}")
7792
add("-Xmx${localTarget.mpsHeapSize}")

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/config/ModelSyncGradleSettings.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ data class SyncDirection(
4242
internal var target: SyncEndpoint? = null,
4343
internal val includedModules: Set<String> = mutableSetOf(),
4444
internal val includedModulePrefixes: Set<String> = mutableSetOf(),
45+
internal val excludedModules: Set<String> = mutableSetOf(),
46+
internal val excludedModulePrefixes: Set<String> = mutableSetOf(),
4547
internal var continueOnError: Boolean = false,
4648
) {
4749
fun fromModelServer(action: Action<ServerSource>) {
@@ -76,6 +78,14 @@ data class SyncDirection(
7678
(includedModulePrefixes as MutableSet).add(prefix)
7779
}
7880

81+
fun excludeModule(module: String) {
82+
(excludedModules as MutableSet).add(module)
83+
}
84+
85+
fun excludeModulesByPrefix(prefix: String) {
86+
(excludedModulePrefixes as MutableSet).add(prefix)
87+
}
88+
7989
@Deprecated("Registering languages is not necessary. This call can be safely removed.", ReplaceWith(""))
8090
@DeprecationInfo(since = "2024-01-08")
8191
fun registerLanguage(language: ILanguage) {}

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/tasks/ExportFromModelServer.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ abstract class ExportFromModelServer : DefaultTask() {
5858
@get:Input
5959
abstract val includedModulePrefixes: SetProperty<String>
6060

61+
@get:Input
62+
abstract val excludedModules: SetProperty<String>
63+
64+
@get:Input
65+
abstract val excludedModulePrefixes: SetProperty<String>
66+
6167
@get:Input
6268
abstract val requestTimeoutSeconds: Property<Int>
6369

@@ -101,7 +107,13 @@ abstract class ExportFromModelServer : DefaultTask() {
101107
return root.allChildren.filter {
102108
val isModule = it.concept?.getUID() == BuiltinLanguages.MPSRepositoryConcepts.Module.getUID()
103109
val moduleName = it.getPropertyValue(nameRole) ?: return@filter false
104-
val isIncluded = isModuleIncluded(moduleName, includedModules.get(), includedModulePrefixes.get())
110+
val isIncluded = isModuleIncluded(
111+
moduleName,
112+
includedModules.get(),
113+
includedModulePrefixes.get(),
114+
excludedModules.get(),
115+
excludedModulePrefixes.get(),
116+
)
105117

106118
isModule && isIncluded
107119
}

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/tasks/ImportIntoModelServer.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ abstract class ImportIntoModelServer : DefaultTask() {
6161
@get:Input
6262
abstract val includedModulePrefixes: SetProperty<String>
6363

64+
@get:Input
65+
abstract val excludedModules: SetProperty<String>
66+
67+
@get:Input
68+
abstract val excludedModulePrefixes: SetProperty<String>
69+
6470
@get:Input
6571
abstract val continueOnError: Property<Boolean>
6672

@@ -77,7 +83,13 @@ abstract class ImportIntoModelServer : DefaultTask() {
7783

7884
val branchRef = ModelFacade.createBranchReference(repoId, branchName.get())
7985
val files = inputDir.listFiles()?.filter {
80-
it.extension == "json" && isModuleIncluded(it.nameWithoutExtension, includedModules.get(), includedModulePrefixes.get())
86+
it.extension == "json" && isModuleIncluded(
87+
it.nameWithoutExtension,
88+
includedModules.get(),
89+
includedModulePrefixes.get(),
90+
excludedModules.get(),
91+
excludedModulePrefixes.get(),
92+
)
8193
}
8294
if (files.isNullOrEmpty()) error("no json files found for included modules")
8395

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.sync.bulk.gradle
18+
19+
import io.kotest.matchers.file.shouldContainFile
20+
import io.kotest.matchers.file.shouldContainNFiles
21+
import org.gradle.testkit.runner.GradleRunner
22+
import org.junit.jupiter.api.io.CleanupMode
23+
import org.junit.jupiter.api.io.TempDir
24+
import java.io.File
25+
import kotlin.test.BeforeTest
26+
import kotlin.test.Test
27+
28+
class ExportFunctionalTest {
29+
30+
private val corePath: String = System.getenv("MODELIX_CORE_PATH")
31+
32+
@TempDir(cleanup = CleanupMode.ON_SUCCESS)
33+
private lateinit var projectDir: File
34+
private val gradle by lazy { GradleRunner.create().withProjectDir(projectDir) }
35+
36+
@BeforeTest
37+
fun setup() {
38+
writeSettingsFile()
39+
}
40+
41+
private fun writeSettingsFile() {
42+
// language=kotlin
43+
val settingsFileContent = """
44+
pluginManagement {
45+
includeBuild("$corePath")
46+
includeBuild("$corePath/build-logic")
47+
}
48+
plugins {
49+
id("modelix-repositories")
50+
}
51+
includeBuild("$corePath")
52+
53+
""".trimIndent()
54+
55+
projectDir.resolve("settings.gradle.kts").writeText(settingsFileContent)
56+
}
57+
58+
private fun writeBuildScript(testCode: String) {
59+
// language=kotlin
60+
val commonBuildScript = """
61+
plugins {
62+
id("modelix-kotlin-jvm")
63+
id("org.modelix.bulk-model-sync")
64+
}
65+
mpsBuild {
66+
mpsVersion("2021.2.5")
67+
}
68+
""".trimIndent()
69+
70+
projectDir.resolve("build.gradle.kts").writeText("$commonBuildScript\n\n$testCode")
71+
}
72+
73+
@Test
74+
fun `module exclusion works`() {
75+
val expectedModule = "jetbrains.mps.baseLanguage.builders"
76+
77+
// language=kotlin
78+
writeBuildScript(
79+
"""
80+
modelSync {
81+
direction("push") {
82+
val module = "jetbrains.mps.baseLanguage.classifiers"
83+
val prefix = "jetbrains.mps.baseLanguage.regexp"
84+
includeModule("$expectedModule")
85+
includeModule(module)
86+
excludeModule(module)
87+
includeModulesByPrefix(prefix)
88+
excludeModulesByPrefix(prefix)
89+
fromLocal {
90+
repositoryDir = File("${projectDir.path}")
91+
}
92+
toModelServer {
93+
url = "localhost"
94+
repositoryId = "abc"
95+
branchName = "master"
96+
}
97+
}
98+
}
99+
""".trimIndent(),
100+
)
101+
gradle.withArguments("pushExportFromMPS").build()
102+
103+
val jsonDir = gradle.projectDir.resolve("build/model-sync/push")
104+
jsonDir shouldContainNFiles 1
105+
jsonDir shouldContainFile "$expectedModule.json"
106+
}
107+
}

bulk-model-sync-gradle/src/test/kotlin/org/modelix/model/sync/bulk/gradle/MpsRunnerConfigurationTest.kt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package org.modelix.model.sync.bulk.gradle
22

3+
import io.kotest.matchers.collections.shouldContainAll
34
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
5+
import org.modelix.model.sync.bulk.gradle.config.LocalSource
46
import org.modelix.model.sync.bulk.gradle.config.LocalTarget
57
import org.modelix.model.sync.bulk.gradle.config.ServerSource
8+
import org.modelix.model.sync.bulk.gradle.config.ServerTarget
69
import org.modelix.model.sync.bulk.gradle.config.SyncDirection
710
import java.io.File
811
import kotlin.test.Test
@@ -29,6 +32,8 @@ class MpsRunnerConfigurationTest {
2932
"-Dmodelix.mps.model.sync.bulk.input.path=/jsonDir",
3033
"-Dmodelix.mps.model.sync.bulk.input.modules=",
3134
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=",
35+
"-Dmodelix.mps.model.sync.bulk.input.modules.excluded=",
36+
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes.excluded=",
3237
"-Dmodelix.mps.model.sync.bulk.repo.path=/repositoryDir",
3338
"-Dmodelix.mps.model.sync.bulk.input.continueOnError=false",
3439
"-Xmx2g",
@@ -55,6 +60,8 @@ class MpsRunnerConfigurationTest {
5560
"-Dmodelix.mps.model.sync.bulk.input.path=/jsonDir",
5661
"-Dmodelix.mps.model.sync.bulk.input.modules=",
5762
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=",
63+
"-Dmodelix.mps.model.sync.bulk.input.modules.excluded=",
64+
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes.excluded=",
5865
"-Dmodelix.mps.model.sync.bulk.repo.path=/repositoryDir",
5966
"-Dmodelix.mps.model.sync.bulk.input.continueOnError=false",
6067
"-Xmx2g",
@@ -85,6 +92,8 @@ class MpsRunnerConfigurationTest {
8592
"-Dmodelix.mps.model.sync.bulk.input.path=/jsonDir",
8693
"-Dmodelix.mps.model.sync.bulk.input.modules=",
8794
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=",
95+
"-Dmodelix.mps.model.sync.bulk.input.modules.excluded=",
96+
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes.excluded=",
8897
"-Dmodelix.mps.model.sync.bulk.repo.path=/repositoryDir",
8998
"-Dmodelix.mps.model.sync.bulk.input.continueOnError=false",
9099
"-Xmx2g",
@@ -96,4 +105,77 @@ class MpsRunnerConfigurationTest {
96105

97106
jvmArgs shouldContainExactlyInAnyOrder expectedJvmArgs
98107
}
108+
109+
@Test
110+
fun `module inclusion and exclusion (local to server)`() {
111+
val serverTarget = ServerTarget(
112+
url = "someUrl",
113+
repositoryId = "someRepositoryId",
114+
branchName = "someBranch",
115+
)
116+
117+
val localSource = LocalSource(repositoryDir = File("/someDir"))
118+
119+
val includedModules = setOf("includedModuleA", "includedModuleB")
120+
val includedModulePrefixes = setOf("includedPrefixA", "includedPrefixB")
121+
val excludedModules = setOf("excludedModuleA", "excludedModuleB")
122+
val excludedModulePrefixes = setOf("excludedPrefixA", "excludedPrefixB")
123+
124+
val syncDirection = SyncDirection(
125+
name = "syncDirection",
126+
source = localSource,
127+
target = serverTarget,
128+
includedModules = includedModules,
129+
includedModulePrefixes = includedModulePrefixes,
130+
excludedModules = excludedModules,
131+
excludedModulePrefixes = excludedModulePrefixes,
132+
)
133+
134+
val expectedJvmArgs = setOf(
135+
"-Dmodelix.mps.model.sync.bulk.output.modules=${includedModules.joinToString(",")}",
136+
"-Dmodelix.mps.model.sync.bulk.output.modules.prefixes=${includedModulePrefixes.joinToString(",")}",
137+
"-Dmodelix.mps.model.sync.bulk.output.modules.excluded=${excludedModules.joinToString(",")}",
138+
"-Dmodelix.mps.model.sync.bulk.output.modules.prefixes.excluded=${excludedModulePrefixes.joinToString(",")}",
139+
)
140+
141+
val config = buildMpsRunConfigurationForLocalSources(syncDirection, classPathElements, jsonDir)
142+
143+
config.jvmArgs shouldContainAll expectedJvmArgs
144+
}
145+
146+
@Test
147+
fun `module inclusion and exclusion (server to local)`() {
148+
val serverSource = ServerSource(
149+
url = "someUrl",
150+
repositoryId = "someRepositoryId",
151+
branchName = "someBranch",
152+
)
153+
val localTarget = LocalTarget(repositoryDir = File("/someDir"))
154+
155+
val includedModules = setOf("includedModuleA", "includedModuleB")
156+
val includedModulePrefixes = setOf("includedPrefixA", "includedPrefixB")
157+
val excludedModules = setOf("excludedModuleA", "excludedModuleB")
158+
val excludedModulePrefixes = setOf("excludedPrefixA", "excludedPrefixB")
159+
160+
val syncDirection = SyncDirection(
161+
name = "syncDirection",
162+
source = serverSource,
163+
target = localTarget,
164+
includedModules = includedModules,
165+
includedModulePrefixes = includedModulePrefixes,
166+
excludedModules = excludedModules,
167+
excludedModulePrefixes = excludedModulePrefixes,
168+
)
169+
170+
val expectedJvmArgs = setOf(
171+
"-Dmodelix.mps.model.sync.bulk.input.modules=${includedModules.joinToString(",")}",
172+
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes=${includedModulePrefixes.joinToString(",")}",
173+
"-Dmodelix.mps.model.sync.bulk.input.modules.excluded=${excludedModules.joinToString(",")}",
174+
"-Dmodelix.mps.model.sync.bulk.input.modules.prefixes.excluded=${excludedModulePrefixes.joinToString(",")}",
175+
)
176+
177+
val config = buildMpsRunConfigurationForLocalTarget(syncDirection, classPathElements, jsonDir)
178+
179+
config.jvmArgs shouldContainAll expectedJvmArgs
180+
}
99181
}

0 commit comments

Comments
 (0)