Compare commits
4 Commits
d84770970d
...
8bcc50ea1b
| Author | SHA1 | Date | |
|---|---|---|---|
| 8bcc50ea1b | |||
| d063ba1c25 | |||
| 68fdac4d64 | |||
| aa585358be |
@ -16,6 +16,11 @@ display = "Java Version"
|
||||
default = "1.4.10"
|
||||
display = "Kotlin Version"
|
||||
|
||||
[features]
|
||||
|
||||
[features.ktlint]
|
||||
default = true
|
||||
|
||||
[versions]
|
||||
http4k = "3.265.0"
|
||||
pebble = "3.1.4"
|
||||
|
||||
50
pom.xml
50
pom.xml
@ -64,6 +64,12 @@
|
||||
<version>5.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
@ -150,6 +156,50 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>ktlint</id>
|
||||
<phase>verify</phase>
|
||||
<configuration>
|
||||
<target name="ktlint">
|
||||
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
|
||||
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
|
||||
<arg value="src/**/*.kt"/>
|
||||
</java>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>ktlint-format</id>
|
||||
<configuration>
|
||||
<target name="ktlint">
|
||||
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
|
||||
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
|
||||
<arg value="-F"/>
|
||||
<arg value="src/**/*.kt"/>
|
||||
</java>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pinterest</groupId>
|
||||
<artifactId>ktlint</artifactId>
|
||||
<version>0.39.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@ -24,12 +24,15 @@ data class Repository(val name: String, val url: String)
|
||||
|
||||
data class Input(val name: String, val display: String, val value: String? = null)
|
||||
|
||||
data class Feature(val name: String, val value: Boolean = false)
|
||||
|
||||
data class Project(
|
||||
val name: String,
|
||||
val basePackage: String,
|
||||
val inputs: List<Input>,
|
||||
val features: List<Feature>,
|
||||
val dependencies: List<Dependency>,
|
||||
val repositories: Collection<Repository>,
|
||||
val repositories: Set<Repository>,
|
||||
)
|
||||
|
||||
data class Version(val name: String, val value: String)
|
||||
|
||||
@ -7,6 +7,7 @@ import com.electronwill.nightconfig.core.Config as NightConfig
|
||||
data class StarterConfig(
|
||||
val dependencies: List<Dependency>,
|
||||
val inputs: List<Input>,
|
||||
val features: List<Feature>,
|
||||
)
|
||||
|
||||
class Config(private val cfg: NightConfig) {
|
||||
@ -54,6 +55,11 @@ class Config(private val cfg: NightConfig) {
|
||||
Input(name, values["display"], values["default"])
|
||||
}
|
||||
|
||||
return StarterConfig(dependencies, inputs)
|
||||
val features = cfg.configMap("features")
|
||||
.map { (name, values) ->
|
||||
Feature(name, values["default"] ?: false)
|
||||
}
|
||||
|
||||
return StarterConfig(dependencies, inputs, features)
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import org.koin.dsl.onClose
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import starter.ProjectZip
|
||||
import starter.config.Config
|
||||
import starter.views.Views
|
||||
|
||||
val mainModule = module {
|
||||
|
||||
@ -1,57 +1,23 @@
|
||||
package starter.modules
|
||||
|
||||
import com.mitchellbosecke.pebble.extension.escaper.SafeString
|
||||
import com.mitchellbosecke.pebble.template.EvaluationContext
|
||||
import com.mitchellbosecke.pebble.template.PebbleTemplate
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
import starter.Dependency
|
||||
import starter.pebble.DepAsXmlPebbleFunction
|
||||
import starter.pebble.HasFeatureFilter
|
||||
import starter.utils.PebbleEngineBuilder
|
||||
import starter.utils.PebbleEngineBuilder.CacheType.ConcurrentMap
|
||||
import starter.utils.PebbleFilter
|
||||
import starter.utils.PebbleFunction
|
||||
|
||||
class DepAsXmlPebbleFunction : PebbleFunction {
|
||||
override val name = "depAsXml"
|
||||
override fun getArgumentNames() = listOf("dependency")
|
||||
override fun execute(args: Map<String, Any>, self: PebbleTemplate, context: EvaluationContext, lineNumber: Int): Any {
|
||||
val dep = args["dependency"] as Dependency
|
||||
|
||||
fun startTag(name: String): String {
|
||||
@Language("html") @Suppress("UnnecessaryVariable")
|
||||
val result = """<span class="text-gray-700"><</span><span class="text-red-700">$name</span><span class="text-gray-700">></span>"""
|
||||
return result
|
||||
}
|
||||
|
||||
fun endTag(name: String): String {
|
||||
@Language("html") @Suppress("UnnecessaryVariable")
|
||||
val result = """<span class="text-gray-700"></</span><span class="text-red-700">$name</span><span class="text-gray-700">></span>"""
|
||||
return result
|
||||
}
|
||||
|
||||
fun tag(name: String, content: String): String {
|
||||
return """${startTag(name)}$content${endTag(name)}"""
|
||||
}
|
||||
|
||||
val result = """
|
||||
|${startTag("dependency")}
|
||||
| ${tag("groupId", dep.groupId)}
|
||||
| ${tag("artifactId", dep.artifactId)}
|
||||
| ${tag("version", dep.version.value)}
|
||||
|${endTag("dependency")}
|
||||
""".trimMargin()
|
||||
|
||||
return SafeString(result)
|
||||
}
|
||||
}
|
||||
|
||||
val pebbleModule = module {
|
||||
single { DepAsXmlPebbleFunction() } bind PebbleFunction::class
|
||||
single { HasFeatureFilter() } bind PebbleFilter::class
|
||||
|
||||
single {
|
||||
PebbleEngineBuilder {
|
||||
cache = ConcurrentMap
|
||||
functions(getAll())
|
||||
filters(getAll())
|
||||
classPath { suffix = ".twig" }
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,15 +11,19 @@ import starter.routes.IndexRouteSupplier
|
||||
import starter.routes.RouteSupplier
|
||||
import starter.routes.ZipRouteSupplier
|
||||
import starter.routes.toRouter
|
||||
import starter.utils.ProjectExtractor
|
||||
import starter.utils.ProjectExtractorImpl
|
||||
|
||||
val routesModule = module {
|
||||
single { IndexRouteSupplier(get()) } bind RouteSupplier::class
|
||||
single { ZipRouteSupplier(get(), get()) } bind RouteSupplier::class
|
||||
single<ProjectExtractor> { ProjectExtractorImpl(get()) }
|
||||
single {
|
||||
ServerFilters.CatchAll().then(
|
||||
routes(
|
||||
static(ResourceLoader.Classpath("/assets")),
|
||||
getAll<RouteSupplier>().toRouter()
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,4 +10,5 @@ val templateModule = module {
|
||||
single { LogbackTemplate(get()) } bind Template::class
|
||||
single { GitignoreTemplate(get()) } bind Template::class
|
||||
single { JunitTemplate(get()) } bind Template::class
|
||||
single { EditorConfigTemplate(get()) } bind Template::class
|
||||
}
|
||||
|
||||
51
src/main/kotlin/starter/pebble/DepAsXmlPebbleFunction.kt
Normal file
51
src/main/kotlin/starter/pebble/DepAsXmlPebbleFunction.kt
Normal file
@ -0,0 +1,51 @@
|
||||
package starter.pebble
|
||||
|
||||
import com.mitchellbosecke.pebble.extension.escaper.SafeString
|
||||
import com.mitchellbosecke.pebble.template.EvaluationContext
|
||||
import com.mitchellbosecke.pebble.template.PebbleTemplate
|
||||
import org.intellij.lang.annotations.Language
|
||||
import starter.Dependency
|
||||
import starter.utils.PebbleFunction
|
||||
|
||||
// We need a custom function since pebble inserts whitespace everywhere
|
||||
class DepAsXmlPebbleFunction : PebbleFunction {
|
||||
override val name = "depAsXml"
|
||||
override fun getArgumentNames() = listOf("dependency")
|
||||
|
||||
override fun execute(
|
||||
args: Map<String, Any>,
|
||||
self: PebbleTemplate,
|
||||
context: EvaluationContext,
|
||||
lineNumber: Int,
|
||||
): SafeString {
|
||||
val dep = args["dependency"] as Dependency
|
||||
|
||||
fun tagName(name: String) = """<span class="text-red-700">$name</span>"""
|
||||
|
||||
fun startTag(name: String): String {
|
||||
@Language("html") @Suppress("UnnecessaryVariable")
|
||||
val result = """<span class="text-gray-700"><</span>""" +
|
||||
"""${tagName(name)}<span class="text-gray-700">></span>"""
|
||||
return result
|
||||
}
|
||||
|
||||
fun endTag(name: String): String {
|
||||
@Language("html") @Suppress("UnnecessaryVariable")
|
||||
val result = """<span class="text-gray-700"></</span>""" +
|
||||
"""${tagName(name)}<span class="text-gray-700">></span>"""
|
||||
return result
|
||||
}
|
||||
|
||||
fun tag(name: String, content: String) = """${startTag(name)}$content${endTag(name)}"""
|
||||
|
||||
val result = """
|
||||
|${startTag("dependency")}
|
||||
| ${tag("groupId", dep.groupId)}
|
||||
| ${tag("artifactId", dep.artifactId)}
|
||||
| ${tag("version", dep.version.value)}
|
||||
|${endTag("dependency")}
|
||||
""".trimMargin()
|
||||
|
||||
return SafeString(result)
|
||||
}
|
||||
}
|
||||
27
src/main/kotlin/starter/pebble/HasFeatureFilter.kt
Normal file
27
src/main/kotlin/starter/pebble/HasFeatureFilter.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package starter.pebble
|
||||
|
||||
import com.mitchellbosecke.pebble.template.EvaluationContext
|
||||
import com.mitchellbosecke.pebble.template.PebbleTemplate
|
||||
import starter.Feature
|
||||
import starter.utils.PebbleFilter
|
||||
|
||||
class HasFeatureFilter : PebbleFilter {
|
||||
override val name = "hasFeature"
|
||||
|
||||
override fun getArgumentNames() = listOf("name")
|
||||
|
||||
override fun apply(
|
||||
input: Any,
|
||||
args: MutableMap<String, Any>,
|
||||
self: PebbleTemplate,
|
||||
context: EvaluationContext,
|
||||
lineNumber: Int,
|
||||
): Boolean {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val features = input as List<Feature>
|
||||
|
||||
val name = args["name"] as String
|
||||
|
||||
return features.any { it.name == name }
|
||||
}
|
||||
}
|
||||
@ -1,54 +1,35 @@
|
||||
package starter.routes
|
||||
|
||||
import org.http4k.core.Method
|
||||
import org.http4k.core.Request
|
||||
import org.http4k.core.Response
|
||||
import org.http4k.core.body.form
|
||||
import org.http4k.core.body.formAsMap
|
||||
import org.http4k.core.with
|
||||
import org.http4k.routing.bind
|
||||
import starter.Project
|
||||
import starter.ProjectZip
|
||||
import starter.config.StarterConfig
|
||||
import starter.extensions.attachment
|
||||
import starter.extensions.badRequest
|
||||
import starter.extensions.ok
|
||||
import starter.utils.ProjectExtractor
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
class ZipRouteSupplier(
|
||||
private val conf: StarterConfig,
|
||||
private val projectZip: ProjectZip,
|
||||
private val projectExtractor: ProjectExtractor,
|
||||
private val projectZip: ProjectZip,
|
||||
) : RouteSupplier {
|
||||
|
||||
override fun get() = "/" bind Method.POST to { req ->
|
||||
private fun handle(req: Request): Response {
|
||||
val project = projectExtractor(req) ?: return Response.badRequest()
|
||||
|
||||
val deps = conf.dependencies.filter {
|
||||
req.form(it.name) != null
|
||||
}
|
||||
val outputStream = projectZip.createZip(project)
|
||||
|
||||
val inputKeys = conf.inputs.map { it.name }
|
||||
val inputs = req.formAsMap()
|
||||
.filter { it.key in inputKeys }
|
||||
.map { (name, value) ->
|
||||
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
||||
}
|
||||
|
||||
val projectName = inputs.find { it.name == "name" }!!.value!!
|
||||
val basePackage = inputs.find { it.name == "basePackage" }!!.value!!
|
||||
|
||||
if (basePackage.contains("/") || basePackage.contains("..")) {
|
||||
Response.badRequest()
|
||||
} else {
|
||||
val repositories = deps.mapNotNull { it.repository }.toSet()
|
||||
val project = Project(projectName, basePackage, inputs, deps, repositories)
|
||||
val outputStream = projectZip.createZip(project)
|
||||
|
||||
Response.ok().with(
|
||||
attachment(
|
||||
value = ByteArrayInputStream(outputStream.toByteArray()),
|
||||
name = "$projectName.zip",
|
||||
contentType = "application/zip"
|
||||
)
|
||||
return Response.ok().with(
|
||||
attachment(
|
||||
value = ByteArrayInputStream(outputStream.toByteArray()),
|
||||
name = "${project.name}.zip",
|
||||
contentType = "application/zip"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun get() = "/" bind Method.POST to ::handle
|
||||
}
|
||||
|
||||
15
src/main/kotlin/starter/templates/EditorConfigTemplate.kt
Normal file
15
src/main/kotlin/starter/templates/EditorConfigTemplate.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package starter.templates
|
||||
|
||||
import com.mitchellbosecke.pebble.PebbleEngine
|
||||
import starter.Project
|
||||
import starter.utils.render
|
||||
|
||||
class EditorConfigTemplate(private val engine: PebbleEngine) : Template {
|
||||
override fun path(project: Project) =
|
||||
".editorconfig"
|
||||
|
||||
override fun enabled(project: Project) = project.features.any { it.name == "ktlint" }
|
||||
|
||||
override fun render(project: Project) =
|
||||
engine.render("starter/editorconfig/index")
|
||||
}
|
||||
@ -2,7 +2,6 @@ package starter.templates
|
||||
|
||||
import com.mitchellbosecke.pebble.PebbleEngine
|
||||
import starter.Project
|
||||
import starter.utils.prettyPrintXml
|
||||
import starter.utils.render
|
||||
|
||||
class JunitTemplate(private val engine: PebbleEngine) : Template {
|
||||
|
||||
@ -6,7 +6,7 @@ import starter.utils.render
|
||||
|
||||
class MainTemplate(private val engine: PebbleEngine) : Template {
|
||||
override fun path(project: Project) =
|
||||
"src/main/kotlin/" + project.basePackage.replace('.', '/') + "/" + project.name.toLowerCase().capitalize() + ".kt"
|
||||
"src/main/kotlin/" + project.name.toLowerCase().capitalize() + ".kt"
|
||||
|
||||
override fun render(project: Project) =
|
||||
engine.render("starter/main/index", mapOf("basePackage" to project.basePackage))
|
||||
|
||||
@ -2,7 +2,6 @@ package starter.templates
|
||||
|
||||
import com.mitchellbosecke.pebble.PebbleEngine
|
||||
import starter.Project
|
||||
import starter.Version
|
||||
import starter.utils.prettyPrintXml
|
||||
import starter.utils.render
|
||||
|
||||
@ -14,6 +13,7 @@ class PomTemplate(private val engine: PebbleEngine) : Template {
|
||||
"dependencies" to project.dependencies.sortedBy { it.scope },
|
||||
"repositories" to project.repositories,
|
||||
"kotlinxSerialization" to project.dependencies.any { it.name == "kotlinx-serialization" },
|
||||
"features" to project.features,
|
||||
"versions" to project.dependencies.map { it.version }.toSet()
|
||||
)
|
||||
|
||||
|
||||
@ -64,16 +64,20 @@ class PebbleEngineBuilder {
|
||||
PebbleEngine.Builder()
|
||||
.loader(builder.loader)
|
||||
.cacheActive(builder.cache != CacheType.None)
|
||||
.templateCache(when (builder.cache) {
|
||||
CacheType.None -> NoOpTemplateCache()
|
||||
CacheType.Caffeine -> CaffeineTemplateCache()
|
||||
CacheType.ConcurrentMap -> ConcurrentMapTemplateCache()
|
||||
})
|
||||
.tagCache(when (builder.cache) {
|
||||
CacheType.None -> NoOpTagCache()
|
||||
CacheType.Caffeine -> CaffeineTagCache()
|
||||
CacheType.ConcurrentMap -> ConcurrentMapTagCache()
|
||||
})
|
||||
.templateCache(
|
||||
when (builder.cache) {
|
||||
CacheType.None -> NoOpTemplateCache()
|
||||
CacheType.Caffeine -> CaffeineTemplateCache()
|
||||
CacheType.ConcurrentMap -> ConcurrentMapTemplateCache()
|
||||
}
|
||||
)
|
||||
.tagCache(
|
||||
when (builder.cache) {
|
||||
CacheType.None -> NoOpTagCache()
|
||||
CacheType.Caffeine -> CaffeineTagCache()
|
||||
CacheType.ConcurrentMap -> ConcurrentMapTagCache()
|
||||
}
|
||||
)
|
||||
.extension(object : AbstractExtension() {
|
||||
override fun getFunctions(): Map<String, Function>? =
|
||||
builder.functions.associateBy { it.name }.ifEmpty { null }
|
||||
|
||||
44
src/main/kotlin/starter/utils/ProjectExtractor.kt
Normal file
44
src/main/kotlin/starter/utils/ProjectExtractor.kt
Normal file
@ -0,0 +1,44 @@
|
||||
package starter.utils
|
||||
|
||||
import org.http4k.core.Request
|
||||
import org.http4k.core.body.form
|
||||
import org.http4k.core.body.formAsMap
|
||||
import starter.Project
|
||||
import starter.config.StarterConfig
|
||||
|
||||
interface ProjectExtractor {
|
||||
operator fun invoke(request: Request): Project?
|
||||
}
|
||||
|
||||
class ProjectExtractorImpl(private val conf: StarterConfig) : ProjectExtractor {
|
||||
override fun invoke(request: Request): Project? {
|
||||
val deps = conf.dependencies.filter {
|
||||
request.form(it.name) != null
|
||||
}
|
||||
|
||||
val formMap = request.formAsMap()
|
||||
|
||||
val inputKeys = conf.inputs.map { it.name }
|
||||
val inputs = formMap
|
||||
.filter { it.key in inputKeys }
|
||||
.map { (name, value) ->
|
||||
conf.inputs.find { it.name == name }!!.copy(value = value.first())
|
||||
}
|
||||
|
||||
val features = formMap
|
||||
.filter { it.key in conf.features.map { it.name } }
|
||||
.map { (name, _) ->
|
||||
conf.features.find { it.name == name }!!.copy(value = true)
|
||||
}
|
||||
|
||||
val projectName = inputs.find { it.name == "name" }?.value ?: return null
|
||||
val basePackage = inputs.find { it.name == "basePackage" }?.value ?: return null
|
||||
|
||||
return if (basePackage.contains("/") || basePackage.contains("..")) {
|
||||
null
|
||||
} else {
|
||||
val repositories = deps.mapNotNull { it.repository }.toSet()
|
||||
Project(projectName, basePackage, inputs, features, deps, repositories)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,8 @@ import starter.utils.render
|
||||
class Views(private val engine: PebbleEngine, config: StarterConfig) {
|
||||
private val args = mapOf(
|
||||
"dependencies" to config.dependencies.groupBy { it.category }.toSortedMap(),
|
||||
"inputs" to config.inputs
|
||||
"inputs" to config.inputs,
|
||||
"features" to config.features,
|
||||
)
|
||||
|
||||
fun index() = engine.render("views/index", args)
|
||||
|
||||
18
src/main/resources/starter/editorconfig/index.twig
Normal file
18
src/main/resources/starter/editorconfig/index.twig
Normal file
@ -0,0 +1,18 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{kt, kts}]
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
continuation_indent_size=4
|
||||
max_line_length = 120
|
||||
disabled_rules = no-wildcard-imports
|
||||
kotlin_imports_layout = idea
|
||||
@ -10,5 +10,7 @@
|
||||
|
||||
{% include "starter/pom/plugins/@shade" %}
|
||||
|
||||
{% include "starter/pom/plugins/@ktlint" %}
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</build>
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
<properties>
|
||||
<java.version>{{ javaVersion }}</java.version>
|
||||
<kotlin.version>{{ kotlinVersion }}</kotlin.version>
|
||||
<kotlin.code.style>official</kotlin.code.style>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
46
src/main/resources/starter/pom/plugins/@ktlint.twig
Normal file
46
src/main/resources/starter/pom/plugins/@ktlint.twig
Normal file
@ -0,0 +1,46 @@
|
||||
{% if features | hasFeature("ktlint") %}
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>ktlint</id>
|
||||
<phase>verify</phase>
|
||||
<configuration>
|
||||
<target name="ktlint">
|
||||
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
|
||||
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
|
||||
<arg value="src/**/*.kt"/>
|
||||
</java>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>ktlint-format</id>
|
||||
<configuration>
|
||||
<target name="ktlint">
|
||||
<java taskname="ktlint" dir="${basedir}" fork="true" failonerror="true"
|
||||
classname="com.pinterest.ktlint.Main" classpathref="maven.plugin.classpath">
|
||||
<arg value="-F"/>
|
||||
<arg value="src/**/*.kt"/>
|
||||
</java>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pinterest</groupId>
|
||||
<artifactId>ktlint</artifactId>
|
||||
<version>0.39.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
{% endif %}
|
||||
@ -10,6 +10,19 @@
|
||||
{% endfor %}
|
||||
|
||||
<div class="mt-4">
|
||||
<section>
|
||||
<h2 class="category">Features</h2>
|
||||
<ul>
|
||||
{% for feature in features %}
|
||||
<label class="m-2">
|
||||
<input name="{{ feature.name }}"
|
||||
type="checkbox"{% if feature.value %} checked{% endif %}>
|
||||
<span>{{ feature.name }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{% for category in dependencies %}
|
||||
<section>
|
||||
<h2 class="category">{{ category.key }}</h2>
|
||||
|
||||
46
src/test/kotlin/starter/TestProject.kt
Normal file
46
src/test/kotlin/starter/TestProject.kt
Normal file
@ -0,0 +1,46 @@
|
||||
package starter
|
||||
|
||||
import starter.config.StarterConfig
|
||||
|
||||
val testConfig = StarterConfig(
|
||||
dependencies = listOf(
|
||||
Dependency(
|
||||
name = "h2",
|
||||
groupId = "com.h2database",
|
||||
artifactId = "h2",
|
||||
version = Version("h2", "1.4.200"),
|
||||
default = false,
|
||||
category = Category.Database,
|
||||
scope = Scope.Compile,
|
||||
logger = null,
|
||||
repository = null,
|
||||
),
|
||||
Dependency(
|
||||
name = "assertj",
|
||||
groupId = "org.assertj",
|
||||
artifactId = "assertj-core",
|
||||
version = Version("assertj", "3.17.2"),
|
||||
default = true,
|
||||
category = Category.Test,
|
||||
scope = Scope.Test,
|
||||
logger = null,
|
||||
repository = null,
|
||||
),
|
||||
Dependency(
|
||||
name = "koin",
|
||||
groupId = "org.koin",
|
||||
artifactId = "koin-core",
|
||||
version = Version("koin", "2.1.6"),
|
||||
default = true,
|
||||
category = Category.Injection,
|
||||
scope = Scope.Compile,
|
||||
logger = null,
|
||||
repository = Repository("jcenter", "https://jcenter.bintray.com"),
|
||||
),
|
||||
),
|
||||
inputs = listOf(
|
||||
Input(name = "name", display = "name", value = "example"),
|
||||
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||
),
|
||||
features = listOf(Feature("ktlint", true))
|
||||
)
|
||||
@ -30,6 +30,7 @@ internal class PomTemplateTest {
|
||||
name = "Test",
|
||||
basePackage = "org.test",
|
||||
inputs = conf.inputs,
|
||||
features = emptyList(),
|
||||
dependencies = conf.dependencies,
|
||||
repositories = conf.dependencies.mapNotNull { it.repository }.toSet()
|
||||
)
|
||||
@ -72,7 +73,6 @@ internal class PomTemplateTest {
|
||||
.associate { it.nodeName to it.firstChild.nodeValue }
|
||||
|
||||
Triple(map["groupId"]!!, map["artifactId"]!!, map["version"] ?: "")
|
||||
|
||||
}.filterNot { it.second == "kotlin-stdlib-jdk8" }
|
||||
|
||||
println(deps.joinToString("\n"))
|
||||
@ -116,6 +116,5 @@ internal class PomTemplateTest {
|
||||
val kotlinxPluginDep = "$kotlinMavenPlugin/dependencies/dependency/artifactId"
|
||||
assertThat(xml.extract(kotlinxPluginDep))
|
||||
.isEqualTo("kotlin-maven-serialization")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
109
src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt
Normal file
109
src/test/kotlin/starter/utils/ProjectExtractorImplTest.kt
Normal file
@ -0,0 +1,109 @@
|
||||
package starter.utils
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.http4k.core.Method
|
||||
import org.http4k.core.Request
|
||||
import org.http4k.core.body.Form
|
||||
import org.http4k.core.body.toBody
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import org.koin.dsl.koinApplication
|
||||
import org.koin.dsl.module
|
||||
import starter.Feature
|
||||
import starter.Input
|
||||
import starter.Project
|
||||
import starter.modules.routesModule
|
||||
import starter.testConfig
|
||||
import java.util.stream.Stream
|
||||
|
||||
internal class ProjectExtractorImplTest {
|
||||
|
||||
private val fakeModule = module {
|
||||
single { testConfig }
|
||||
}
|
||||
|
||||
private val koin = koinApplication {
|
||||
modules(routesModule, fakeModule)
|
||||
}.koin
|
||||
|
||||
private val projectExtractor = koin.get<ProjectExtractor>()
|
||||
|
||||
@Suppress("unused")
|
||||
fun invalidProjectsSource(): Stream<Form> = Stream.of(
|
||||
emptyList(),
|
||||
listOf(
|
||||
"basePackage" to "org.example",
|
||||
),
|
||||
listOf(
|
||||
"basePackage" to "org.example/a",
|
||||
"name" to "test"
|
||||
),
|
||||
)
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("invalidProjectsSource")
|
||||
fun invalidProjects(form: Form) {
|
||||
val request = Request(Method.POST, "")
|
||||
.body(form.toBody())
|
||||
|
||||
val project = projectExtractor(request)
|
||||
|
||||
assertThat(project).isNull()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun validProjectsSource(): Stream<Pair<Form, Project>> = Stream.of(
|
||||
listOf(
|
||||
"name" to "Test",
|
||||
"basePackage" to "org.example",
|
||||
"ktlint" to "",
|
||||
) to Project(
|
||||
name = "Test",
|
||||
basePackage = "org.example",
|
||||
inputs = listOf(
|
||||
Input(name = "name", display = "name", value = "Test"),
|
||||
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||
),
|
||||
features = listOf(
|
||||
Feature(name = "ktlint", value = true)
|
||||
),
|
||||
dependencies = listOf(),
|
||||
repositories = setOf(),
|
||||
),
|
||||
listOf(
|
||||
"name" to "Test",
|
||||
"basePackage" to "org.example",
|
||||
"ktlint" to "",
|
||||
"koin" to "",
|
||||
) to Project(
|
||||
name = "Test",
|
||||
basePackage = "org.example",
|
||||
inputs = listOf(
|
||||
Input(name = "name", display = "name", value = "Test"),
|
||||
Input(name = "basePackage", display = "Base package", value = "org.example"),
|
||||
),
|
||||
features = listOf(
|
||||
Feature(name = "ktlint", value = true)
|
||||
),
|
||||
dependencies = listOf(
|
||||
testConfig.dependencies.find { it.name == "koin" }!!
|
||||
),
|
||||
repositories = setOf(
|
||||
testConfig.dependencies.find { it.name == "koin" }!!.repository!!
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("validProjectsSource")
|
||||
fun validProjects(pair: Pair<Form, Project>) {
|
||||
val (form, expected) = pair
|
||||
|
||||
val request = Request(Method.POST, "")
|
||||
.body(form.toBody())
|
||||
|
||||
val project = projectExtractor(request)
|
||||
|
||||
assertThat(project).isEqualTo(expected)
|
||||
}
|
||||
}
|
||||
4
src/test/resources/junit-platform.properties
Normal file
4
src/test/resources/junit-platform.properties
Normal file
@ -0,0 +1,4 @@
|
||||
junit.jupiter.testinstance.lifecycle.default=per_class
|
||||
junit.jupiter.execution.parallel.enabled=true
|
||||
junit.jupiter.execution.parallel.mode.default=same_thread
|
||||
junit.jupiter.execution.parallel.mode.classes.default=concurrent
|
||||
Loading…
x
Reference in New Issue
Block a user