Skip to content

Commit

Permalink
Add support for configuration (#27)
Browse files Browse the repository at this point in the history
* add configuration file

* CR changes

* display output

* CR v2

Co-authored-by: azdrojowa123 <azdrojowa@gmail.com>
  • Loading branch information
azdrojowa123 and azdrojowa123 authored Jan 16, 2023
1 parent f7ad4ce commit c83cea0
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 0 deletions.
4 changes: 4 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ maven_install(
"org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.0",
"io.get-coursier:interface:1.0.11",
"commons-io:commons-io:2.11.0",
"com.fasterxml.jackson.module:jackson-module-kotlin:2.11.2",
"com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.1",
"com.networknt:json-schema-validator:1.0.76",
"org.slf4j:slf4j-nop:2.0.6",
"org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.5",
"org.kohsuke:github-api:1.313",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ kt_jvm_library(
visibility = ["//visibility:public"],
deps = [
"//common",
"//config",
"//core",
"//github",
"//maven",
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/kotlin/org/virtuslab/bazelsteward/app/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.virtuslab.bazelsteward.common.FileUpdateSearch
import org.virtuslab.bazelsteward.common.GitClient
import org.virtuslab.bazelsteward.common.GitOperations
import org.virtuslab.bazelsteward.common.UpdateLogic
import org.virtuslab.bazelsteward.config.BazelStewardConfiguration
import org.virtuslab.bazelsteward.core.Config
import org.virtuslab.bazelsteward.core.Environment
import org.virtuslab.bazelsteward.core.GitHostClient
Expand Down Expand Up @@ -44,6 +45,7 @@ data class Context(
}
val config = Config(repoPath, pushToRemote, baseBranch)

val bsc = runBlocking { BazelStewardConfiguration(repoPath).get() } // will be used later
val bfs = BazelFileSearch(config)
val mde = MavenDataExtractor(config)
val mr = MavenRepository()
Expand Down
5 changes: 5 additions & 0 deletions config/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
alias(
name = "config",
actual = "//config/src/main:config",
visibility = ["//visibility:public"],
)
20 changes: 20 additions & 0 deletions config/src/main/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
kt_jvm_library(
name = "config",
srcs = glob(["kotlin/**/*.kt"]),
resources = glob(
["resources/**"],
),
visibility = ["//visibility:public"],
deps = [
"//maven",
"@maven//:com_fasterxml_jackson_dataformat_jackson_dataformat_yaml",
"@maven//:com_fasterxml_jackson_module_jackson_module_kotlin",
"@maven//:com_networknt_json_schema_validator",
"@maven//:io_arrow_kt_arrow_core",
"@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core",
"@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_jdk8",
"@maven//:org_slf4j_slf4j_nop",
],
)

lint(srcs = glob(["**/*.kt"]))
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.virtuslab.bazelsteward.config

import com.fasterxml.jackson.annotation.JsonSetter
import com.fasterxml.jackson.annotation.Nulls
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.networknt.schema.JsonSchemaFactory
import com.networknt.schema.SpecVersion
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.virtuslab.bazelsteward.maven.MavenLibraryId
import java.nio.file.Path
import kotlin.io.path.exists

data class Configuration(
@JsonSetter(nulls = Nulls.AS_EMPTY)
val maven: MavenConfig = MavenConfig()
)

data class MavenConfig(
@JsonSetter(nulls = Nulls.AS_EMPTY)
val ruledDependencies: List<MavenDependency> = emptyList()
)

data class MavenDependency(
val id: MavenLibraryId,
val versioning: String
)

class BazelStewardConfiguration(repoRoot: Path) {

private val configFilePath = repoRoot.resolve(".bazel-steward.yaml")

suspend fun get(): Configuration {

return withContext(Dispatchers.IO) {
val schemaContent = javaClass.classLoader.getResource("bazel-steward-schema.json")?.readText()
?: throw Exception("Could not find schema to validate configuration file")
val schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909).getSchema(schemaContent)

runCatching {
if (!configFilePath.exists()) return@withContext Configuration()
val configContent = configFilePath.toFile()
.readLines()
.filterNot { it.startsWith("#") }
.joinToString("\n")
.ifEmpty { return@withContext Configuration() }
val yamlReader = ObjectMapper(YAMLFactory())
yamlReader.registerModule(KotlinModule())
val validationResult = schema.validate(yamlReader.readTree(configContent))
if (validationResult.isNotEmpty()) {
throw Exception(validationResult.joinToString(System.lineSeparator()) { it.message.removePrefix("$.") })
} else {
yamlReader.readValue(configContent, Configuration::class.java)
}
}.getOrElse {
println("Could not parse $configFilePath file!")
throw it
}
}
}
}
35 changes: 35 additions & 0 deletions config/src/main/resources/bazel-steward-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"type": "object",
"properties": {
"maven": {
"properties": {
"ruledDependencies": {
"type": ["array", "null"],
"items": {
"type": "object",
"properties": {
"id": {
"type": "object",
"properties": {
"group": {
"type": "string"
},
"artifact": {
"type": "string"
}
},
"required": ["group", "artifact"]
},
"versioning": {
"type": "string",
"anyOf": [{"enum": ["loose", "semver"]}, {"pattern": "^regex:"}]
}
},
"required": ["id", "versioning"]
}
}
},
"required": ["ruledDependencies"]
}
}
}
15 changes: 15 additions & 0 deletions config/src/test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
kt_junit5_test(
name = "config",
size = "small",
srcs = glob(["kotlin/**/*.kt"]),
resources = glob(
["resources/**"],
),
test_package = "org.virtuslab.bazelsteward.config",
deps = [
"//config/src/main:config",
"@maven//:commons_io_commons_io",
],
)

lint(srcs = glob(["**/*.kt"]))
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.virtuslab.bazelsteward.config

import io.kotest.common.runBlocking
import org.apache.commons.io.FileUtils
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import org.virtuslab.bazelsteward.maven.MavenLibraryId
import java.io.File

class BazelStewardConfigurationTest {

@Test
fun `should throw an exception when maven object in config file is not correct`(@TempDir tempDir: File) {
copyConfigFileToTempLocation(tempDir, ".bazel-steward-fail.yaml")
Assertions.assertThatThrownBy { runBlocking { BazelStewardConfiguration(tempDir.toPath()).get() } }
.hasMessage(
listOf(
"maven.ruledDependencies[0].id.group: is missing but it is required",
"maven.ruledDependencies[0].id.artifact: is missing but it is required",
"maven.ruledDependencies[1].versioning: does not have a value in the enumeration [loose, semver]",
"maven.ruledDependencies[1].versioning: does not match the regex pattern ^regex:",
"maven.ruledDependencies[2].id.group: integer found, string expected"
).joinToString(System.lineSeparator())
)
}

@Test
fun `should create default configuration when config file is not declared`(@TempDir tempDir: File) {
val configuration = runBlocking { BazelStewardConfiguration(tempDir.toPath()).get() }
Assertions.assertThat(configuration).isEqualTo(Configuration())
}

@Test
fun `should create configuration when config file is correct`(@TempDir tempDir: File) {
copyConfigFileToTempLocation(tempDir, ".bazel-steward-correct.yaml")
val configuration = runBlocking { BazelStewardConfiguration(tempDir.toPath()).get() }
val expectedConfiguration = Configuration(
MavenConfig(
listOf(
MavenDependency(MavenLibraryId("commons-io", "commons-io"), "loose"),
MavenDependency(MavenLibraryId("io.get-coursier", "interface"), "semver"),
MavenDependency(MavenLibraryId("org.jetbrains.kotlinx", "kotlinx-coroutines-jdk8"), "regex:(?<major>\\d+)")
)
)
)
Assertions.assertThat(configuration).isEqualTo(expectedConfiguration)
}

private fun copyConfigFileToTempLocation(tempDir: File, configFileName: String) {
FileUtils.copyURLToFile(
javaClass.classLoader.getResource(configFileName),
File(tempDir, ".bazel-steward.yaml")
)
}
}
17 changes: 17 additions & 0 deletions config/src/test/resources/.bazel-steward-correct.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
maven:
ruledDependencies:
-
id:
group: "commons-io"
artifact: "commons-io"
versioning: "loose"
-
id:
group: "io.get-coursier"
artifact: "interface"
versioning: "semver"
-
id:
group: "org.jetbrains.kotlinx"
artifact: "kotlinx-coroutines-jdk8"
versioning: "regex:(?<major>\\d+)"
17 changes: 17 additions & 0 deletions config/src/test/resources/.bazel-steward-fail.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
maven:
ruledDependencies:
-
id:
grouop: "commons-io"
artifactt: "commons-io"
versioning: "loose"
-
id:
group: "io.get-coursier"
artifact: "interface"
versioning: "semverr"
-
id:
group: 2
artifact: "kotlinx-coroutines-jdk8"
versioning: "regex:(?<major>\\d+)(?<minor>\\.\\d+)?(?<patch>\\.\\d+)?$"

0 comments on commit c83cea0

Please sign in to comment.