扩展 codestart
本指南说明如何为扩展创建和配置 Quarkus Codestart。
描述
"扩展 Codestarts" 是我们为 Quarkus 扩展的“入门”代码生成系统命名的名称。它旨在提供个性化的 Quarkus 入门体验。Quarkus 扩展能够提供一个或多个定义良好的 codestarts,其中包含开始使用该特定扩展所需的/推荐的资源和代码。
在使用 Quarkus 工具时,扩展 codestarts 会被默认应用(如果选择的扩展包含任何 codestarts)。
-
code.quarkus.io(查找标有 [code] 的扩展)
-
Quarkus Maven 插件
mvn io.quarkus.platform:quarkus-maven-plugin:create
-
Quarkus CLI
quarkus create app
工作原理
在启动项目时,您会选择语言、构建工具、框架,然后添加 Dockerfile、CI、依赖项和代码。
Codestarts 在为项目生成做出贡献时的工作方式相同,它们分为两类:
“基础” Codestarts(您可以选择它们的组合)
-
project:项目骨架(例如 Quarkus 项目)
-
buildtool:构建工具(例如 Maven、Gradle、带 Kotlin DSL 的 Gradle)
-
language:编程语言(例如 Java、Kotlin、Scala)
-
config:配置类型(例如 yaml、properties)
额外 Codestarts(任意数量,添加到基础 Codestarts 之上)
-
tooling:可以添加到项目以改进项目的任何内容(例如 Dockerfiles、GitHub Actions 工作流)
-
code:任何 Quarkus 扩展都可以提供入门代码。用户可以决定是否激活它。
每个 codestart 由以下部分组成:
-
一个唯一的 codestart 名称,例如
my-codestart
-
一个用于 codestart 文件的目录,例如
my-codestart/
-
一个
codestart.yml
文件 -
可选地,一些遵循通用结构和命名约定的模板
Quarkus 扩展 Codestarts 位于何处
-
在 Quarkus 核心存储库中,所有扩展 codestarts 都位于同一个 模块 中。
-
Quarkus REST(前身为 RESTEasy Reactive)、RESTEasy 和 Spring Web 扩展 codestarts 是 基础 codestarts 的一部分。
-
对于其他扩展,codestart 通常会位于运行时模块中(在
pom.xml
中有特殊说明以生成单独的 codestart 伪件)。
基础 Codestarts
基础 Codestarts 包含用于创建项目、构建工具、语言、配置和工具文件的模板。
此外,Quarkus 还提供了以下初始化新扩展项目并使用 Codestart 的方法:
编写扩展 Codestart
以下是编写扩展 codestart 的分步指南。您也可以观看 Quarkus Insight #99 进行现场编码。
正如之前提到的,基础项目文件(pom.xml、Dockerfile 等)已经由 Quarkus 核心提供的基础 codestarts 生成。因此,我们可以只关注特定于扩展的入门代码。
让我们以 io.quarkiverse.aloha:quarkus-aloha
作为示例 GAV(不要寻找这个扩展,它不存在)。
代码
Codestart 是用于构建新项目的模板。
在本教程中,Codestart 项目是从 Quarkus 项目创建的,并添加了必要的模板。
因此,请前往 code.quarkus.io,使用 aloha 扩展和 org.acme
作为 Group(即 org.acme
包名占位符)创建一个新项目。准备一个很好的入门示例。它不应包含任何业务逻辑,而应包含一些可以编译并概述如何使用该扩展的存根数据/Hello World。目的是提供扩展最常见的起始点代码。
对代码满意了吗?让我们来创建一个 Codestart。
Codestart(Quarkiverse 或独立扩展)
在您的扩展中:
-
创建
runtime/src/main/codestarts/quarkus/aloha-codestart
目录。 -
将已生成项目的
src/main/java
移动到runtime/src/main/codestarts/quarkus/aloha-codestart/java/src/main/java
。 -
(可选)使用此约定移动配置:应用程序配置 application.yml。
-
在
runtime/src/main/codestarts/quarkus/aloha-codestart
中创建一个 codestart.yml 文件。name: aloha-codestart ref: aloha type: code tags: extension-codestart metadata: title: Aloha description: Start to code with the Aloha extension. related-guide-section: https://docs.quarkiverse.io/quarkus-aloha/dev/ path: /aloha # (optional) for web extensions providing HTTP resources
-
在
runtime/pom.xml
中添加 Maven 构建插件配置(以生成 codestart 伪件:/target/quarkus-aloha-VERSION-codestarts.jar
)。<plugin> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>generate-codestart-jar</id> <phase>generate-resources</phase> <goals> <goal>jar</goal> </goals> <configuration> <classesDirectory>${project.basedir}/src/main</classesDirectory> <includes> <include>codestarts/**</include> </includes> <classifier>codestarts</classifier> <skipIfEmpty>true</skipIfEmpty> </configuration> </execution> </executions> </plugin>
-
在扩展元数据
runtime/src/main/resources/META-INF/quarkus-extension.yaml
中添加 codestart 绑定。没有此项,当选择您的扩展时,您的 codestart 将不会被添加。name: ... description: ... metadata: ... codestart: name: "aloha" languages: - "java" artifact: "io.quarkiverse.aloha:quarkus-aloha:codestarts:jar:${project.version}"
-
在
base/README.tpl.qute.md
中添加 README README.md 部分模板。{#include readme-header /}
-
在扩展根目录(或仅
runtime
)中运行mvn clean install
。 -
现在我们可以通过创建使用我们扩展的项目来检查 codestart 是否有效(确保快照版本正确)。
quarkus create app aloha-app -x=io.quarkiverse.aloha:quarkus-aloha:999-SNAPSHOT ... applying codestarts... 📚 java 🔨 maven 📦 quarkus 📝 config-properties 🔧 dockerfiles 🔧 maven-wrapper 🚀 aloha-codestart <<<<<<<<<<<<<<<< ...
测试
-
将此依赖项添加到
integration-tests
。<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-devtools-testing</artifactId> <scope>test</scope> </dependency>
-
在
integration-tests
中创建一个AlohaCodestartTest
。public class AlohaCodestartTest { @RegisterExtension public static QuarkusCodestartTest codestartTest = QuarkusCodestartTest.builder() .languages(Language.JAVA) .setupStandaloneExtensionTest("io.quarkiverse.aloha:quarkus-aloha") .build(); @Test void testContent() throws Throwable { codestartTest.checkGeneratedSource("org.acme.AlohaResource"); } @Test void buildAllProjects() throws Throwable { codestartTest.buildAllProjects(); } }
更进一步
-
如果扩展提供了一些 Web 资源,请添加
base/src/main/resources/META-INF/resources/index.entry.qute.html
模板(index.html 和 Web 扩展 codestarts)。 -
添加另一种语言(建议提供 Java 和 Kotlin)。
-
您可以添加其他资源(在
./base
目录中,如果它们不特定于语言)。
Quarkus Core 中的扩展 Codestarts
-
所有 codestarts 都被分组在一个 特定的模块 中。
-
不需要额外的 Maven 配置。
-
扩展元数据 引用了包含所有核心 codestarts 的伪件。
-
测试也已 分组。您无需测试构建,因为有一个特定的分组 测试。例如:
public class ConfigYamlCodestartTest { @RegisterExtension public static QuarkusCodestartTest codestartTest = QuarkusCodestartTest.builder() .codestarts("config-yaml") .languages(JAVA, KOTLIN) .build(); @Test void testContent() throws Throwable { codestartTest.checkGeneratedSource("org.acme.GreetingConfig"); codestartTest.assertThatGeneratedFileMatchSnapshot(JAVA, "src/main/resources/application.yml"); } @Test @EnabledIfSystemProperty(named = "build-projects", matches = "true") void buildAllProjectsForLocalUse() throws Throwable { codestartTest.buildAllProjects(); } }
特定主题
org.acme
包名占位符
您必须在扩展 codestart 源中使用 org.acme
作为包名。在生成的项目中,将使用用户指定的包(或 Group)(并自动替换 org.acme
)。
包名将在所有源文件(.java、.kt、.scala)中自动替换。包目录也将自动调整。如果出于某种原因,其他类型的文件需要用户包名,那么您应该使用 Qute 模板 和 {project.package-name}
数据占位符(在 grpc proto 文件中查找示例)。
codestart.yml
# codestart unique name
name: resteasy-example
# codestart reference, use the extension id
ref: resteasy
# use 'code' (other types are for base codestarts)
type: code
# use 'extension-codestart'
tags: extension-codestart
# public metadata for this example (accessible as data in the templates e.g. {title})
metadata:
title: RESTEasy Jakarta REST example
description: Rest is easy peasy with this Hello World RESTEasy resource.
related-guide-section: https://quarkus.net.cn/guides/getting-started#the-jax-rs-resources
# (optional) use this in web extensions with a specific path (and also add the index page)
path: /some-path
目录结构
codestart.yml 是唯一必需的文件。 |
-
codestart.yml
必须位于 codestart 的根目录。 -
./base
包含所有将独立于所选语言进行处理的文件。 -
./[java/kotlin/scala]
包含所有仅在选择了相应语言时才会被处理的文件(覆盖基础文件)。
Codestart 中的动态配置键
gen-info.time = generation time (in milliseconds)
input.selected-extensions[].name|description|guide = list of selected extensions with info
input.selected-extensions-ga = Set of Strings containing the list of extensions groupId:artifactId, useful for dynamic codestarts depending on selected extensions
input.provided-code[].name|tags|title|description|related-guide: list of selected codestarts with info
Codestart 中的静态配置键
quarkus.platform.group-id = BOM groupId
quarkus.platform.artifact-id = BOM artifactId
quarkus.platform.version = BOM version
project.group-id = Project groupId
project.artifact-id = Project artifactId
project.version = Project version
project.name = Project name (if specified)
project.description = Project description (if specified)
project.package-name = Project package name
quarkus.maven-plugin.group-id = Quarkus Maven plugin groupId
quarkus.maven-plugin.artifact-id = Quarkus Maven plugin artifactId
quarkus.maven-plugin.version = Quarkus Maven plugin version
quarkus.gradle-plugin.id = Quarkus Gradle pluginId
quarkus.gradle-plugin.version = Quarkus Gradle plugin version
quarkus.version = Quarkus version
java.version = Java version
kotlin.version = Kotlin version
scala.version = Scala version
scala-maven-plugin.version = Scala Maven plugin version
maven-compiler-plugin.version = Maven compiler plugin version
maven-surefire-plugin.version = Maven Surefire plugin version
文件名命名约定
-
.tpl.qute
将使用 Qute 进行处理,并可以使用数据(.tpl.qute
将从输出文件名中删除)。 -
某些常见文件,例如
readme.md
、src/main/resources/application.yml
、src/main/resources/META-INF/resources/index.html
,是从为项目选择的 codestarts 中收集的片段生成的。 -
其他文件将被复制。
Qute 模板
Codestarts 可以使用 Qute 模板 MyClass.tpl.qute.java
进行动态渲染。
这些模板能够使用包含以下内容的数据:
-
用于生成 codestart 的
data
(以及公共metadata
)(在codestart.yml
中指定)。 -
用于生成项目的ョ所有 codestarts 的
shared-data
的合并。 -
用户输入。
-
一些动态生成的数据(例如
dependencies
和test-dependencies
)。
README.md
您可以在 base
目录中添加 README.md
或 README.tpl.qute.md
,它将被附加到其他 README 文件中。因此,只需添加与您的扩展 codestart 相关的信息。
base/README.tpl.qute.md
{#include readme-header /}
[Optionally, Here you may add information about how to use the example, settings, ...]
{#include readme-header /} 将使用位于 Quarkus 项目 codestart 中的模板,该模板显示来自 codestart.yml 元数据的标准信息。 |
应用程序配置 application.yml
根据约定,您应始终以 yaml 文件(base/src/main/resources/application.yml
)的形式提供 Quarkus 配置。
它将:
-
与其他扩展 codestarts 的配置合并。
-
在生成时根据所选扩展自动转换为所选配置类型(yaml 或 properties)。
index.html 和 Web 扩展 Codestarts
扩展 codestarts 可以通过添加此文件为生成的 index.html 提供一个片段:
base/src/main/resources/META-INF/resources/index.entry.qute.html
{#include index-entry /}
{#include index-entry /} 将使用位于 Quarkus 项目 codestart 中的模板,该模板显示来自 codestart.yml 元数据的标准信息。 |
集成测试
有一个名为 QuarkusCodestartTest
的扩展可以帮助测试扩展 codestarts。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-devtools-testing</artifactId>
<scope>test</scope>
</dependency>
它提供了一种测试以下内容的方法:
-
生成的项目内容(使用不可变的模拟数据)以及快照测试。
-
生成的项目构建/运行(使用真实数据)以及用于运行构建的辅助工具。
在所有测试之前,该扩展将使用模拟数据和真实数据生成指定语言和 codestart 的 Quarkus 项目。您可以在 target/quarkus-codestart-test 目录中找到这些生成的项目。您可以将 real-data 项目在 IDE 中打开,或使用终端进行操作。真实数据是迭代开发扩展 codestart 的最简单方式。 |
该扩展提供了测试项目构建的辅助工具 buildAllProjects
或仅测试特定语言项目 buildProject(Language language)
。它还提供了用于测试内容的辅助工具,请参阅 快照测试。
ConfigYamlCodestartTest 是 Quarkus 核心中的一个好例子。
快照测试
快照测试是一种确保测试生成的内容从一个修订版到另一个修订版(即提交之间)不会改变的方法。这意味着,每次提交生成的内容都需要是不可变的和确定性的(这就是使用模拟数据的原因)。为了能够执行此类检查,我们自动生成生成的内容的快照,并将它们作为后续测试运行的预期输出的引用进行提交。当模板更改时,我们也会提交由此产生的快照更改。这样,在审查期间,我们可以确保应用的代码更改对生成的输出具有预期的效果。
该扩展提供了用于检查内容的辅助工具:
-
checkGeneratedSource()
验证一个类是否与所有语言(或特定语言)的快照匹配。 -
checkGeneratedTestSource()
验证一个测试类是否与所有语言(或特定语言)的快照匹配。 -
assertThatGeneratedFileMatchSnapshot()
检查一个项目文件是否与快照匹配。 -
您可以使用
AbstractPathAssert.satisfies(checkContains("some content"))
或上述方法的任何 Path assert 来检查文件是否包含特定内容。 -
assertThatGeneratedTreeMatchSnapshots()
允许您将特定语言的项目文件结构(树)与其快照进行比较。
为了首先在本地文件系统上生成或更新现有快照文件,在本地运行测试开发 codestart 时需要添加 -Dsnap 。它们需要作为提交的一部分,否则 CI 上的测试将不会通过。 |
编写技巧
-
您的扩展 codestart 必须/应该独立于构建工具和 Dockerfiles。
-
Extension codestarts 应该能够与其他 codestarts 并行工作而不产生干扰(组合使用时)。
-
确保您的类名在所有扩展 codestarts 中是唯一的。
-
仅使用
org.acme
作为包名。 -
为您的 REST 路径使用唯一的路径
/[unique]
。 -
将配置写在 yml 中
src/main/resources/application.yml
。它将与其他 codestarts 的配置合并,并根据所选的配置类型(yaml 或 properties)自动转换。
-
您可以先从 Java 开始,然后在另一个 PR 中添加 Kotlin(创建一个 issue,以免忘记)。
-
如果您有任何问题,请在 https://quarkusio.zulipchat.com/ 上 @ia3andy。
平台 Codestarts 数据
本章对于希望在 平台描述符 中提供 codestart 数据的 Quarkus 平台 开发者来说是相关的。
虽然通常在 codestart.yml 文件中配置 codestart 数据,但平台开发者也可以在平台描述符中提供 codestart 数据,以自定义某些值。
例如,给定一个 codestart.yml
如下:
name: quarkus-magic-codestart
ref: quarkus-magic
type: code
tags: extension-codestart
metadata:
title: Quarkus Magic
description: Quarkus magic
language:
base:
data:
magic:
source: codestart.yml
magic.source
的值可以在平台描述符中这样自定义:
{
"id" : "org.acme.platform:acme-bom-quarkus-platform-descriptor:7.0.7:json:7.0.7",
"platform" : true,
"bom" : "org.acme.platform:acme-magic-bom::pom:7.0.7",
"metadata" : {
"project" : { (1)
"codestart-data" : { (2)
"quarkus-magic-codestart" : { (3)
"magic" : {
"source" : "acme-platform"
}
}
}
},
...
1 | project 包含与项目创建工具有关的元数据。 |
2 | codestart-data 是各种 codestarts 的数据源。 |
3 | 要将嵌套 thereunder 的数据传递到的 codestart 的名称。 |