added jpms-check plugin
This commit is contained in:
142
dependency-export/README.md
Normal file
142
dependency-export/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
## Overview
|
||||
This plugin will add 2 new tasks to your gradle projects
|
||||
|
||||
### The *exportDependencies* task
|
||||
The `exportDependencies` task will simply create a `.dot` file that contains your project's dependency graph,
|
||||
this task does not depend on anything and will succeed even if you don't have
|
||||
[Graphviz](https://www.graphviz.org) installed.
|
||||
|
||||
### The *renderDependencies* task
|
||||
This task will invoke the `exportDependencies` task and then call Graphviz to create an visual
|
||||
representation of your dependency graph. Since this task invokes `Graphviz` directly,
|
||||
having it installed and available in your `PATH` is a requirement.
|
||||
|
||||
## Install the plugin
|
||||
|
||||
Checkout this project and in the root folder run
|
||||
```bash
|
||||
./gradlew publishToMavenLocal
|
||||
```
|
||||
to install it to your local machine's Maven repository.
|
||||
|
||||
## Add the plugin to your project
|
||||
|
||||
Add this plugin to you project simply adding it to your projects `build.gradle`
|
||||
```groovy
|
||||
plugins {
|
||||
id "net.woggioni.plugins.dependency-export" version "0.1"
|
||||
}
|
||||
```
|
||||
|
||||
or to your `build.gradle.kts` if you prefer the Gradle Kotlin DSL
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
id("net.woggioni.plugins.dependency-export") version "0.1"
|
||||
}
|
||||
```
|
||||
|
||||
You can also enable it globally on your machine just create a `~/.gradle/init.gradle` file with this content
|
||||
|
||||
```groovy
|
||||
initscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath "net.woggioni.plugins:dependency-export:0.1"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: net.woggioni.plugins.DependencyExportPlugin
|
||||
}
|
||||
```
|
||||
|
||||
this means that the plugin will be automatically enabled for all your Gradle projects,
|
||||
note that it doesn't alter the build process in any way except for creating the
|
||||
`renderDependency` and `exportDependencies` tasks, so it's relatively safe to do so.
|
||||
|
||||
If you need more information, the `sample` folder contains a basic Gradle project using the plugin,
|
||||
using both Groovy and Kotlin DSL.
|
||||
|
||||
## Configure the plugin
|
||||
|
||||
This is the default configuration for both tasks using Groovy DSL
|
||||
|
||||
```groovy
|
||||
exportDependencies {
|
||||
configurationName = 'default'
|
||||
outputFile = 'dependencies.dot'
|
||||
}
|
||||
|
||||
renderDependencies {
|
||||
format = 'xlib'
|
||||
outputFile = 'renderedDependencies'
|
||||
graphvizExecutable = 'graphviz'
|
||||
}
|
||||
```
|
||||
|
||||
and using Kotlin DSL
|
||||
|
||||
```kotlin
|
||||
import net.woggioni.plugins.ExportDependenciesPluginExtension
|
||||
import net.woggioni.plugins.RenderDependenciesPluginExtension
|
||||
|
||||
configure<ExportDependenciesPluginExtension> {
|
||||
configurationName = "default"
|
||||
outputFile = "dependencies.dot"
|
||||
}
|
||||
|
||||
configure<RenderDependenciesPluginExtension> {
|
||||
format = "xlib"
|
||||
outputFile = "renderedDependencies"
|
||||
graphvizExecutable = "graphviz"
|
||||
}
|
||||
```
|
||||
|
||||
any configuration parameter can be overridden in your `build.gradle` (or `build.gradle.kts`) file
|
||||
or using its correspondent Gradle's [project properties](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties).
|
||||
For example to override the output format of the `renderDependencies` task from the CLI:
|
||||
|
||||
```bash
|
||||
gradle -PrenderDependencies.format=svg renderDependencies
|
||||
```
|
||||
|
||||
### Parameter description
|
||||
|
||||
- `exportDependencies.configurationName` will select the Gradle's configuration
|
||||
(that word you put in the `dependencies` section of your build before `groupId:artifactId:versionId` tuple)
|
||||
that will be represented in the graph
|
||||
- `exportDependencies.outputFile` will specify the location of the generated `.dot` file
|
||||
(note that if a relative path is provided, it will be interpreted as relative to the project's build directory)
|
||||
- `renderDependencies.format` will specify the format of the file generated by Graphviz.
|
||||
The default output format is `xlib` which, on a linux machine with a GUI, will open
|
||||
a window with an interactive (with zoom and pan) view of your dependencies (this is a special format that
|
||||
will not output any file). Otherwise you can choose between any other output format supported by Graphviz,
|
||||
refer to [its official documentation](https://graphviz.gitlab.io/_pages/doc/info/output.html) for more details.
|
||||
- `renderDependencies.outputFile` will specify the location of the generated file (note that if a
|
||||
relative path is provided, it will be interpreted as relative to the project's build directory)
|
||||
- `renderDependencies.graphvizExecutable` will set the executable that will be launched to invoke
|
||||
Graphviz so that, if you have it installed in an exotic location outside of your `PATH` or, for
|
||||
any reason, you renamed it in some way, you can configure it here.
|
||||
|
||||
## And finally use it!
|
||||
|
||||
Just run
|
||||
|
||||
```bash
|
||||
gradle exportDependencies
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
gradle renderDependencies
|
||||
```
|
||||
|
||||
and enjoy the mess of your horrible dependency thornbush.
|
||||
Now ask yourself if you really need that neural network framework for
|
||||
[your FizzBuzz project](https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition).
|
21
dependency-export/build.gradle.kts
Normal file
21
dependency-export/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
`maven-publish`
|
||||
id("org.jetbrains.kotlin.jvm")
|
||||
id("com.gradle.plugin-publish")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Align versions of all Kotlin components
|
||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||
|
||||
// Use the Kotlin JDK 8 standard library.
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
val dependencyExportPlugin by plugins.creating {
|
||||
id = "net.woggioni.plugins.dependency-export"
|
||||
implementationClass = "net.woggioni.plugins.dependency.export.DependencyExportPlugin"
|
||||
}
|
||||
}
|
32
dependency-export/sample/groovy/build.gradle
Normal file
32
dependency-export/sample/groovy/build.gradle
Normal file
@@ -0,0 +1,32 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "net.woggioni.plugins:dependency-export:0.1"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.jvm" version "1.3.61"
|
||||
id "net.woggioni.plugins.dependency-export" version "0.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
|
||||
exportDependencies {
|
||||
configurationName = 'runtime'
|
||||
}
|
||||
|
||||
renderDependencies {
|
||||
format = "svg"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||
}
|
6
dependency-export/sample/groovy/settings.gradle
Normal file
6
dependency-export/sample/groovy/settings.gradle
Normal file
@@ -0,0 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
35
dependency-export/sample/kotlin/build.gradle.kts
Normal file
35
dependency-export/sample/kotlin/build.gradle.kts
Normal file
@@ -0,0 +1,35 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("net.woggioni.plugins:dependency-export:0.1")
|
||||
}
|
||||
}
|
||||
|
||||
import net.woggioni.plugins.ExportDependenciesPluginExtension
|
||||
import net.woggioni.plugins.RenderDependenciesPluginExtension
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.3.71"
|
||||
id("net.woggioni.plugins.dependency-export") version "0.1"
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||
}
|
||||
|
||||
configure<ExportDependenciesPluginExtension> {
|
||||
configurationName = "runtime"
|
||||
}
|
||||
|
||||
configure<RenderDependenciesPluginExtension> {
|
||||
format = "svg"
|
||||
}
|
6
dependency-export/sample/kotlin/settings.gradle.kts
Normal file
6
dependency-export/sample/kotlin/settings.gradle.kts
Normal file
@@ -0,0 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
@@ -0,0 +1,220 @@
|
||||
package net.woggioni.plugins.dependency.export
|
||||
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.artifacts.component.ComponentIdentifier
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.artifacts.result.UnresolvedDependencyResult
|
||||
import java.io.BufferedWriter
|
||||
import java.io.OutputStreamWriter
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
|
||||
open class ExportDependenciesPluginExtension(project: Project) {
|
||||
var configurationName: String = "default"
|
||||
var outputFile = project.buildDir.toPath().resolve("dependencies.dot")
|
||||
var showArtifacts = false
|
||||
}
|
||||
|
||||
open class RenderDependenciesPluginExtension(project: Project) {
|
||||
var format: String = "xlib"
|
||||
var outputFile = project.buildDir.toPath().resolve("renderedDependencies")
|
||||
var graphvizExecutable: String = "dot"
|
||||
}
|
||||
|
||||
private class Overrider(private val properties: Map<String, Any?>, private val prefix: String) {
|
||||
inline fun <reified T> identity(arg: T): T {
|
||||
return arg
|
||||
}
|
||||
|
||||
fun overrideProperty(property: KMutableProperty0<String>) {
|
||||
overrideProperty(property, ::identity)
|
||||
}
|
||||
|
||||
inline fun <reified V> overrideProperty(
|
||||
property: KMutableProperty0<V>,
|
||||
valueFactory: (String) -> V) {
|
||||
val propertyKey = prefix + "." + property.name
|
||||
val propertyValue = properties[propertyKey] as String?
|
||||
if (propertyValue != null) {
|
||||
property.set(valueFactory(propertyValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DependencyExporter {
|
||||
|
||||
private fun quote(s : String) = "\"" + s + "\""
|
||||
|
||||
fun exportDot(project: Project, ext: ExportDependenciesPluginExtension) {
|
||||
val overrider = Overrider(project.properties, "exportDependencies")
|
||||
overrider.overrideProperty(ext::configurationName)
|
||||
overrider.overrideProperty(ext::outputFile) { value -> Paths.get(value) }
|
||||
overrider.overrideProperty(ext::showArtifacts) { value -> value.toBoolean() }
|
||||
|
||||
var sequence = 0
|
||||
val map = HashMap<ResolvedComponentResult, Int>()
|
||||
|
||||
val requestedConfiguration = project.configurations.singleOrNull {
|
||||
it.name == ext.configurationName
|
||||
}?.takeIf { it.isCanBeResolved } ?: let {
|
||||
val resolvableConfigurations = "[" + project.configurations.asSequence()
|
||||
.filter { it.isCanBeResolved }
|
||||
.map { "'${it.name}'" }
|
||||
.joinToString(",") + "]"
|
||||
throw GradleException("Configuration '${ext.configurationName}' doesn't exist or cannot be resolved, " +
|
||||
"resolvable configurations in this project are " + resolvableConfigurations)
|
||||
}
|
||||
|
||||
val resolutionResult = requestedConfiguration.incoming.resolutionResult
|
||||
if (!ext.outputFile.isAbsolute) {
|
||||
ext.outputFile = project.buildDir.toPath().resolve(ext.outputFile)
|
||||
}
|
||||
Files.createDirectories(ext.outputFile.parent)
|
||||
BufferedWriter(
|
||||
OutputStreamWriter(
|
||||
Files.newOutputStream(ext.outputFile))).use { writer ->
|
||||
writer.write("digraph G {")
|
||||
writer.newLine()
|
||||
writer.write(" #rankdir=\"LR\";")
|
||||
writer.newLine()
|
||||
|
||||
val artifactMap = if(ext.showArtifacts) {
|
||||
requestedConfiguration.resolvedConfiguration.resolvedArtifacts.asSequence().map {
|
||||
it.id.componentIdentifier to it
|
||||
}.groupBy(
|
||||
Pair<ComponentIdentifier, ResolvedArtifact>::first,
|
||||
Pair<ComponentIdentifier, ResolvedArtifact>::second
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
for (component in resolutionResult.allComponents) {
|
||||
map.computeIfAbsent(component) {
|
||||
sequence++
|
||||
}
|
||||
val artifacts = artifactMap?.let { it[component.id] }
|
||||
val (shape, color) = when (component.id) {
|
||||
is ProjectComponentIdentifier -> (artifacts?.let { "none" } ?: "box") to "#88ff88"
|
||||
is ModuleComponentIdentifier -> (artifacts?.let { "none" } ?: "oval") to "#ffff88"
|
||||
else -> throw NotImplementedError("${component.id::class}")
|
||||
}
|
||||
|
||||
|
||||
val componentName = component.id.displayName
|
||||
val label = artifacts?.let {
|
||||
val rows = it.asSequence().map { resolvedArtifact ->
|
||||
val artifactDescription = sequenceOf(
|
||||
"type" to resolvedArtifact.type,
|
||||
"classifier" to resolvedArtifact.classifier,
|
||||
"extension" to resolvedArtifact.extension.takeIf {
|
||||
resolvedArtifact.extension != resolvedArtifact.type
|
||||
}
|
||||
).mapNotNull { pair ->
|
||||
when {
|
||||
pair.second == null || pair.second.isEmpty() -> null
|
||||
else -> "${pair.first}: ${pair.second}"
|
||||
}
|
||||
}.joinToString(", ")
|
||||
"<TR><TD BGCOLOR=\"lightgrey\">$artifactDescription</TD></TR>"
|
||||
}.joinToString()
|
||||
"""
|
||||
<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="2">
|
||||
<TR>
|
||||
<TD>${component.id.displayName}</TD>
|
||||
</TR>
|
||||
$rows
|
||||
</TABLE>>
|
||||
""".trimIndent()
|
||||
} ?: quote(componentName)
|
||||
|
||||
val attrs = sequenceOf(
|
||||
"label" to label,
|
||||
"shape" to quote(shape),
|
||||
"style" to quote("filled"),
|
||||
artifacts?.let { "margin" to quote(0.toString()) },
|
||||
"fillcolor" to quote(color)
|
||||
).mapNotNull { it }.toMap()
|
||||
writer.write(" node_${map[component]} [" +
|
||||
attrs.entries
|
||||
.asSequence()
|
||||
.map { "${it.key}=${it.value}" }.joinToString(", ") +
|
||||
"];")
|
||||
writer.newLine()
|
||||
}
|
||||
|
||||
for (component in resolutionResult.allComponents) {
|
||||
component.dependencies.map { dependency ->
|
||||
when (dependency) {
|
||||
is ResolvedDependencyResult -> dependency
|
||||
is UnresolvedDependencyResult -> {
|
||||
throw dependency.failure
|
||||
}
|
||||
else -> {
|
||||
throw NotImplementedError("${dependency::class}")
|
||||
}
|
||||
}
|
||||
}.map(ResolvedDependencyResult::getSelected).forEach { child ->
|
||||
writer.write(" node_${map[component]} -> node_${map[child]};")
|
||||
writer.newLine()
|
||||
}
|
||||
}
|
||||
writer.write("}")
|
||||
writer.newLine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DependencyRenderer {
|
||||
fun render(project: Project, ext: RenderDependenciesPluginExtension, sourceFile: Path) {
|
||||
val overrider = Overrider(project.properties, "renderDependencies")
|
||||
overrider.overrideProperty(ext::format)
|
||||
overrider.overrideProperty(ext::graphvizExecutable)
|
||||
overrider.overrideProperty(ext::outputFile) { value -> Paths.get(value) }
|
||||
|
||||
if (!ext.outputFile.isAbsolute) {
|
||||
ext.outputFile = project.buildDir.toPath().resolve(ext.outputFile)
|
||||
}
|
||||
val cmd: List<String> = listOf(
|
||||
ext.graphvizExecutable,
|
||||
"-T${ext.format}",
|
||||
"-o${ext.outputFile}",
|
||||
sourceFile.toString()
|
||||
|
||||
)
|
||||
val returnCode = ProcessBuilder(cmd).inheritIO().start().waitFor()
|
||||
if (returnCode != 0) {
|
||||
throw GradleException("Error invoking graphviz")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DependencyExportPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
val dependencyExportExtension = ExportDependenciesPluginExtension(project)
|
||||
project.extensions.add(ExportDependenciesPluginExtension::class.java, "exportDependencies", dependencyExportExtension)
|
||||
val exportDependenciesTask = project.tasks.register("exportDependencies") {
|
||||
it.doLast {
|
||||
DependencyExporter.exportDot(project, dependencyExportExtension)
|
||||
}
|
||||
}.get()
|
||||
|
||||
val renderDependenciesPluginExtension = RenderDependenciesPluginExtension(project)
|
||||
project.extensions.add(RenderDependenciesPluginExtension::class.java, "renderDependencies", renderDependenciesPluginExtension)
|
||||
project.tasks.register("renderDependencies") {
|
||||
it.dependsOn(exportDependenciesTask)
|
||||
it.doLast {
|
||||
DependencyRenderer.render(project, renderDependenciesPluginExtension, dependencyExportExtension.outputFile)
|
||||
}
|
||||
}.get()
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This Kotlin source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package net.woggioni.plugins.dependency.export
|
||||
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
class DependencyExportPluginTest {
|
||||
|
||||
@TempDir
|
||||
lateinit var testGradleHomeDir : Path
|
||||
|
||||
@TempDir
|
||||
lateinit var testProjectDir : Path
|
||||
lateinit var buildFile : Path
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
buildFile = testProjectDir.resolve("build.gradle.kts")
|
||||
}
|
||||
|
||||
fun getStandardGradleRunnerFor(taskName: String): GradleRunner {
|
||||
return GradleRunner.create()
|
||||
.withDebug(true)
|
||||
.withProjectDir(testProjectDir.toFile())
|
||||
.withArguments(taskName, "-s", "--info", "-g", testGradleHomeDir.toString())
|
||||
.withPluginClasspath()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKotlin() {
|
||||
installResource("build.gradle.kts", testProjectDir)
|
||||
installResource("settings.gradle.kts", testProjectDir)
|
||||
installResource("gradle.properties", testProjectDir)
|
||||
val runner = getStandardGradleRunnerFor("exportDependencies")
|
||||
runner.build()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGroovy() {
|
||||
installResource("build.gradle", testProjectDir)
|
||||
installResource("settings.gradle.kts", testProjectDir)
|
||||
installResource("gradle.properties", testProjectDir)
|
||||
val runner = getStandardGradleRunnerFor("exportDependencies")
|
||||
runner.build()
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package net.woggioni.plugins.dependency.export
|
||||
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun Any.installResource(resourceName: String, destination: Path) {
|
||||
val outputFile = run {
|
||||
val realDestination = if (Files.isSymbolicLink(destination)) {
|
||||
destination.toRealPath()
|
||||
} else {
|
||||
destination
|
||||
}
|
||||
when {
|
||||
!Files.exists(realDestination) -> {
|
||||
Files.createDirectories(realDestination.parent)
|
||||
realDestination
|
||||
}
|
||||
Files.isDirectory(realDestination) ->
|
||||
realDestination.resolve(resourceName.substring(1 + resourceName.lastIndexOf('/')))
|
||||
Files.isRegularFile(realDestination) -> realDestination
|
||||
else -> throw IllegalStateException("Path '${realDestination}' is neither a file nor a directory")
|
||||
}
|
||||
}
|
||||
(javaClass.getResourceAsStream(resourceName)
|
||||
?: javaClass.classLoader.getResourceAsStream(resourceName))?.use { inputStream ->
|
||||
Files.copy(inputStream, outputFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
} ?: throw FileNotFoundException(resourceName)
|
||||
}
|
2
dependency-export/src/test/resources/gradle.properties
Normal file
2
dependency-export/src/test/resources/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
org.gradle.jvmargs=-Xmx256m
|
||||
org.gradle.caching=false
|
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.jvm" version "1.3.61"
|
||||
id "net.woggioni.plugins.dependency-export"
|
||||
}
|
||||
|
||||
exportDependencies {
|
||||
configurationName = 'runtime'
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "1.3.71"
|
||||
id("net.woggioni.plugins.dependency-export")
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
runtime("org.hibernate:hibernate-core:5.4.13.Final")
|
||||
}
|
||||
|
Reference in New Issue
Block a user