跳到主要内容

2024-09-17

一言

有些梦想虽然遥不可及,但不是不可能实现。只要我足够的强。 --- 《秦时明月》 · 小学生


English

once again : 再次

It's again possible : 再次可行

Powershell 导出目录权限列表

要导出 D:\Sharing_Data 目录下一级子目录的用户权限列表,可以使用 PowerShell命令提示符(Command Prompt) 中的 icacls 工具。以下是两种方法的详细步骤:


方法一:使用 PowerShell

  1. 打开 PowerShell

    • Win + X,选择 Windows PowerShell(管理员)Windows Terminal(管理员)
  2. 运行以下脚本

    # 设置共享目录路径
    $sharedPath = "D:\Sharing_Data"

    # 获取一级子目录
    $subDirectories = Get-ChildItem -Path $sharedPath -Directory

    # 创建一个空数组来存储权限信息
    $permissionsList = @()

    foreach ($dir in $subDirectories) {
    # 获取当前子目录的ACL(访问控制列表)
    $acl = Get-Acl -Path $dir.FullName

    foreach ($access in $acl.Access) {
    # 创建一个自定义对象来存储信息
    $permission = [PSCustomObject]@{
    Directory = $dir.Name
    Identity = $access.IdentityReference
    FileSystemRights = $access.FileSystemRights
    AccessControlType = $access.AccessControlType
    }
    # 添加到数组中
    $permissionsList += $permission
    }
    }

    # 导出到CSV文件
    $permissionsList | Export-Csv -Path "D:\Sharing_Data_Permissions.csv" -NoTypeInformation -Encoding UTF8

    Write-Output "权限列表已成功导出到 D:\Sharing_Data_Permissions.csv"
  3. 解释脚本内容

    • 获取子目录Get-ChildItem -Path $sharedPath -Directory 获取 D:\Sharing_Data 下的所有一级子目录。
    • 获取权限Get-Acl 获取每个子目录的权限信息。
    • 整理数据:将目录名、用户、权限类型等信息整理成表格形式。
    • 导出CSV:将整理好的权限信息导出到 D:\Sharing_Data_Permissions.csv 文件中。
  4. 查看导出的权限文件

    导出的 D:\Sharing_Data_Permissions.csv 文件可以使用 Excel 或任何支持 CSV 格式的应用程序打开,方便查看和分析。


方法二:使用命令提示符中的 icacls

  1. 打开命令提示符

    • Win + R,输入 cmd,然后按 Enter
  2. 运行以下命令

    cd /d D:\Sharing_Data
    for /D %G in (*) do icacls "%G" >> D:\Sharing_Data_Permissions.txt

    注意

    • 如果你将此命令写入批处理文件(.bat),需要将 %G 替换为 %%G,即:
      for /D %%G in (*) do icacls "%%G" >> D:\Sharing_Data_Permissions.txt
  3. 解释命令内容

    • for /D %G in (*):遍历 D:\Sharing_Data 目录下的所有一级子目录。
    • icacls "%G":获取每个子目录的权限信息。
    • >> D:\Sharing_Data_Permissions.txt:将权限信息追加到 D:\Sharing_Data_Permissions.txt 文件中。
  4. 查看导出的权限文件

    打开 D:\Sharing_Data_Permissions.txt 文件,即可查看各子目录的权限列表。


选择哪种方法?

  • PowerShell 方法 更加灵活和强大,适合需要进一步处理和分析权限数据的场景。
  • icacls 方法 简单快捷,适合快速导出权限信息到文本文件。

根据你的需求选择合适的方法即可。如果需要更详细的权限信息或格式化的数据,推荐使用 PowerShell 方法。


额外提示

  • 管理员权限:确保以管理员身份运行 PowerShell 或命令提示符,以避免权限不足导致无法读取某些目录的权限信息。
  • 编码问题:在导出到 CSV 文件时,使用 UTF-8 编码可以避免中文字符显示为乱码。
  • 权限说明
    • IdentityReference:表示用户或用户组。
    • FileSystemRights:表示具体的权限类型,如读取、写入、修改等。
    • AccessControlType:表示是允许(Allow)还是拒绝(Deny)权限。

开发gradle插件

创建一个自定义的 Gradle 插件 codegen-jooq-gradle-plugin,其插件 ID 为 org.moonlit.jooq,并在其中为 gradle-jooq-plugin 添加默认配置,可以按照以下步骤进行。整个过程包括设置插件项目、定义插件逻辑、添加默认配置、打包发布插件等。

以下是详细的步骤和代码示例:

1. 创建插件项目

首先,创建一个新的 Gradle 项目来开发你的插件。

mkdir codegen-jooq-gradle-plugin
cd codegen-jooq-gradle-plugin
gradle init --type java-gradle-plugin

这将创建一个基本的 Gradle 插件项目结构。

2. 配置 build.gradle

编辑 build.gradle 文件,添加必要的依赖和插件信息。

plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'java'
}

group = 'org.moonlit'
version = '1.0.0'

repositories {
mavenCentral()
}

dependencies {
implementation 'org.jooq:jooq:3.18.4' // 根据需要调整版本
implementation 'nu.studer:gradle-jooq-plugin:5.2.1' // 使用 gradle-jooq-plugin 的版本
}

gradlePlugin {
plugins {
codegenJooq {
id = 'org.moonlit.jooq'
implementationClass = 'org.moonlit.jooq.CodegenJooqPlugin'
displayName = 'Codegen JOOQ Gradle Plugin'
description = 'A custom Gradle plugin that extends gradle-jooq-plugin with default configurations.'
}
}
}

publishing {
publications {
pluginMaven(MavenPublication) {
from components.java
groupId = 'org.moonlit'
artifactId = 'codegen-jooq-gradle-plugin'
version = '1.0.0'
}
}
// 配置仓库,例如 Maven Central 或者本地仓库
repositories {
mavenLocal()
// maven {
// url = uri("https://your.repository.url")
// credentials {
// username = project.findProperty("repoUser") ?: ""
// password = project.findProperty("repoPassword") ?: ""
// }
// }
}
}

说明:

  • 插件依赖nu.studer:gradle-jooq-plugin 是你要扩展的插件。
  • 插件发布:配置了 maven-publish 插件以便将自定义插件发布到 Maven 仓库或本地仓库。

3. 创建插件实现类

src/main/java/org/moonlit/jooq/ 目录下创建 CodegenJooqPlugin.java 文件。

package org.moonlit.jooq;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.jooq.gradle.JooqGenerate;
import nu.studer.gradle.jooq.JooqPluginExtension;
import nu.studer.gradle.jooq.JooqPlugin;

public class CodegenJooqPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
// 应用原始的 gradle-jooq-plugin
project.getPluginManager().apply("nu.studer.jooq");

// 获取 Jooq 插件的扩展
JooqPluginExtension jooqExtension = project.getExtensions().getByType(JooqPluginExtension.class);

// 设置默认配置
jooqExtension.getVersion().convention("3.18.4"); // 设置 JOOQ 版本

// 配置生成器
jooqExtension.generateAll(new Action<JooqGenerate>() {
@Override
public void execute(JooqGenerate generate) {
generate.getInputSchema().convention("public");
generate.getOutputDirectory().convention(new File(project.getBuildDir(), "generated-jooq"));
// 添加更多默认配置
generate.getGenerator().getName().convention("org.jooq.codegen.DefaultGenerator");
// 例如,设置目标包名
generate.getGenerator().getStrategy().getName().convention("org.jooq.codegen.DefaultGeneratorStrategy");
}
});

// 你可以在这里添加更多默认的配置,例如数据库连接、生成策略等
}
}

说明:

  • 应用原始插件:首先应用 nu.studer.jooq 插件。
  • 配置默认值:为 jooq 插件的扩展设置默认配置,如 JOOQ 版本、输入 schema、输出目录等。
  • 扩展配置:可以根据需要添加更多默认配置,以简化使用者的配置。

4. 配置 plugin 元数据

确保 resources/META-INF/gradle-plugins/org.moonlit.jooq.properties 文件存在,并包含以下内容:

implementation-class=org.moonlit.jooq.CodegenJooqPlugin

这将告知 Gradle 使用哪个类作为插件的实现。

5. 打包和发布插件

本地发布

你可以将插件发布到本地 Maven 仓库,以便在本地测试。

./gradlew publishToMavenLocal

发布到远程仓库

如果你希望将插件发布到 Maven Central 或其他远程仓库,请确保在 build.gradle 中正确配置 publishing 部分,并根据目标仓库的要求提供认证信息。

6. 使用自定义插件

在需要使用该插件的项目中,按照以下步骤配置:

1. 在 settings.gradle 中添加插件仓库

如果插件已发布到 Maven Central,可以直接使用:

pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
mavenCentral()
// 如果发布到其他仓库,添加相应的 URL
}
}

2. 在 build.gradle 中应用插件

plugins {
id 'org.moonlit.jooq' version '1.0.0'
}

// 由于插件已经预配置了一些默认值,你只需要根据需要进行最少的配置
jooq {
version = '3.18.4' // 可选,如果你希望覆盖默认版本
configurations {
main { // 'main' 是默认的配置名称
// 你可以根据需要覆盖默认配置
jdbc {
driver = 'org.postgresql.Driver'
url = 'jdbc:postgresql://localhost:5432/mydb'
user = 'username'
password = 'password'
}
generator {
name = 'org.jooq.codegen.DefaultGenerator'
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
}
database {
name = 'org.jooq.meta.postgres.PostgresDatabase'
inputSchema = 'public'
}
generate {
daos = true
records = true
immutablePojos = true
}
target {
packageName = 'com.example.jooq'
directory = "${project.buildDir}/generated-jooq"
}
}
}
}
}

3. 生成 JOOQ 类

运行以下任务生成 JOOQ 类:

./gradlew generateJooq

7. 提高插件的灵活性

为了使插件更灵活,可以为插件添加自定义扩展,让用户可以在需要时覆盖默认配置。

修改插件实现类

package org.moonlit.jooq;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.jooq.gradle.JooqGenerate;
import nu.studer.gradle.jooq.JooqPluginExtension;
import nu.studer.gradle.jooq.JooqPlugin;

public class CodegenJooqPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
// 应用原始的 gradle-jooq-plugin
project.getPluginManager().apply("nu.studer.jooq");

// 获取 Jooq 插件的扩展
JooqPluginExtension jooqExtension = project.getExtensions().getByType(JooqPluginExtension.class);

// 设置默认配置,可以让用户覆盖
jooqExtension.getVersion().convention("3.18.4"); // 默认 JOOQ 版本

jooqExtension.configurations().all(configuration -> {
configuration.generate(generate -> {
// 设置默认值,如果用户未覆盖
generate.getInputSchema().convention("public");
generate.getOutputDirectory().convention(new File(project.getBuildDir(), "generated-jooq"));
generate.getGenerator().getName().convention("org.jooq.codegen.DefaultGenerator");
generate.getGenerator().getStrategy().getName().convention("org.jooq.codegen.DefaultGeneratorStrategy");
// 更多默认配置
});
});
}
}

使用自定义扩展

用户可以在 build.gradle 中覆盖默认配置,例如:

jooq {
version = '3.19.0' // 覆盖默认版本
configurations {
main {
jdbc {
url = 'jdbc:mysql://localhost:3306/mydb'
// 其他 JDBC 配置
}
generator {
target {
packageName = 'com.example.customjooq'
}
}
}
}
}

8. 版本管理和持续集成

为了确保插件的版本管理和持续集成,建议:

  • 使用 Git 进行版本控制。
  • 配置 CI/CD 管道(如 GitHub Actions、GitLab CI 等)自动构建和发布插件。
  • 遵循语义化版本(SemVer)原则管理插件版本。

9. 示例项目

为了帮助用户更好地理解和使用你的插件,可以创建一个示例项目,并在 README.md 中提供使用说明。

示例项目结构

example-project/
├── build.gradle
├── settings.gradle
└── src/
└── main/
└── java/

示例 build.gradle

plugins {
id 'org.moonlit.jooq' version '1.0.0'
}

repositories {
mavenLocal()
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = 'org.postgresql.Driver'
url = 'jdbc:postgresql://localhost:5432/mydb'
user = 'username'
password = 'password'
}
generator {
database {
name = 'org.jooq.meta.postgres.PostgresDatabase'
inputSchema = 'public'
}
target {
packageName = 'com.example.jooq'
}
}
}
}
}

总结

通过以上步骤,你可以创建一个自定义的 Gradle 插件 codegen-jooq-gradle-plugin,为 gradle-jooq-plugin 添加默认配置,简化在 Gradle 项目中的配置过程。确保在开发过程中进行充分的测试,并为插件用户提供清晰的文档和使用示例,以提升插件的易用性和可靠性。

如果在开发过程中遇到任何问题,建议参考以下资源:

希望这些信息对你有所帮助!

在为 codegen-jooq-gradle-plugin 添加单元测试以确保插件的可用性和正确性时,建议使用 Gradle TestKit。Gradle TestKit 允许你编写功能性测试,这些测试可以实际运行 Gradle 构建并验证插件的行为。

以下是详细的步骤和代码示例,帮助你在插件项目中添加和配置单元测试。

gradle插件项目配置测试

1. 配置测试环境

首先,确保在 build.gradle 文件中添加必要的测试依赖和配置。

修改 build.gradle

plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'java'
}

group = 'org.moonlit'
version = '1.0.0'

repositories {
mavenCentral()
}

dependencies {
implementation 'org.jooq:jooq:3.18.4'
implementation 'nu.studer:gradle-jooq-plugin:5.2.1'

// 测试依赖
testImplementation gradleTestKit()
testImplementation 'junit:junit:4.13.2' // 使用 JUnit 4
// 如果你使用 JUnit 5,可以使用以下依赖
// testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
}

gradlePlugin {
plugins {
codegenJooq {
id = 'org.moonlit.jooq'
implementationClass = 'org.moonlit.jooq.CodegenJooqPlugin'
displayName = 'Codegen JOOQ Gradle Plugin'
description = 'A custom Gradle plugin that extends gradle-jooq-plugin with default configurations.'
}
}
}

publishing {
publications {
pluginMaven(MavenPublication) {
from components.java
groupId = 'org.moonlit'
artifactId = 'codegen-jooq-gradle-plugin'
version = '1.0.0'
}
}
repositories {
mavenLocal()
// 配置远程仓库(如需要)
}
}

// 配置测试使用 JUnit 4
test {
useJUnit()
// 如果使用 JUnit 5,可以配置如下
// useJUnitPlatform()
}

说明:

  • 测试依赖
    • gradleTestKit():提供 Gradle TestKit 的依赖。
    • junit:junit:4.13.2:JUnit 4 的依赖。如果你偏好 JUnit 5,可以使用相应的依赖并调整测试配置。
  • 测试配置
    • test { useJUnit() }:配置测试使用 JUnit。如果使用 JUnit 5,请使用 useJUnitPlatform()

2. 创建测试类

src/test/java/org/moonlit/jooq/ 目录下创建测试类 CodegenJooqPluginTest.java

创建目录结构

确保你的项目结构如下:

codegen-jooq-gradle-plugin/
├── build.gradle
├── settings.gradle
├── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── moonlit/
│ │ └── jooq/
│ │ └── CodegenJooqPlugin.java
│ └── test/
│ └── java/
│ └── org/
│ └── moonlit/
│ └── jooq/
│ └── CodegenJooqPluginTest.java

编写测试类

package org.moonlit.jooq;

import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static org.junit.Assert.*;

public class CodegenJooqPluginTest {

@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder();

private File buildFile;

@Test
public void testPluginAppliesSuccessfully() throws IOException {
// 创建临时项目目录
File projectDir = testProjectDir.getRoot();

// 创建 build.gradle 文件
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" name = 'org.jooq.codegen.DefaultGenerator'\n" +
" strategy {\n" +
" name = 'org.jooq.codegen.DefaultGeneratorStrategy'\n" +
" }\n" +
" database {\n" +
" name = 'org.jooq.meta.h2.H2Database'\n" +
" inputSchema = 'PUBLIC'\n" +
" }\n" +
" generate {\n" +
" daos = true\n" +
" records = true\n" +
" immutablePojos = true\n" +
" }\n" +
" target {\n" +
" packageName = 'com.example.jooq'\n" +
" directory = '${project.buildDir}/generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// 运行 Gradle 任务
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());
}

@Test
public void testPluginConfiguration() throws IOException {
// 创建临时项目目录
File projectDir = testProjectDir.getRoot();

// 创建 build.gradle 文件
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" target {\n" +
" packageName = 'com.custom.jooq'\n" +
" directory = '${project.buildDir}/custom-generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// 运行 Gradle 任务
BuildResult result = GradleRunner.create()
.withProjectDir(projectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());

// 验证生成目录是否存在
File generatedDir = new File(projectDir, "build/custom-generated-jooq");
assertTrue(generatedDir.exists());
}
}

说明:

  • @Rule TemporaryFolder:创建一个临时项目目录,用于隔离测试环境,确保每个测试运行在干净的环境中。

  • testPluginAppliesSuccessfully()

    • 创建一个简单的 build.gradle 文件,应用自定义插件并配置基本的 JOOQ 设置。
    • 使用 GradleRunner 运行 generateJooq 任务。
    • 断言任务执行成功。
  • testPluginConfiguration()

    • 创建一个包含自定义配置的 build.gradle 文件,覆盖插件的默认配置。
    • 运行 generateJooq 任务。
    • 断言任务执行成功,并验证生成的目录是否存在。

3. 运行测试

在项目根目录下运行以下命令以执行测试:

./gradlew test

测试结果将显示在控制台,并生成测试报告在 build/reports/tests/test/index.html。你可以打开该文件查看详细的测试结果。

4. 使用 JUnit 5(可选)

如果你更喜欢使用 JUnit 5,可以按照以下步骤进行配置:

修改 build.gradle

dependencies {
implementation 'org.jooq:jooq:3.18.4'
implementation 'nu.studer:gradle-jooq-plugin:5.2.1'

// 测试依赖
testImplementation gradleTestKit()
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' // JUnit 5
}

test {
useJUnitPlatform()
}

编写 JUnit 5 测试类

package org.moonlit.jooq;

import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.*;

public class CodegenJooqPluginJUnit5Test {

@TempDir
File testProjectDir;

private File buildFile;

@Test
public void testPluginAppliesSuccessfully() throws IOException {
// 创建 build.gradle 文件
buildFile = new File(testProjectDir, "build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n" +
"\n" +
"jooq {\n" +
" configurations {\n" +
" main {\n" +
" jdbc {\n" +
" driver = 'org.h2.Driver'\n" +
" url = 'jdbc:h2:mem:testdb'\n" +
" user = 'sa'\n" +
" password = ''\n" +
" }\n" +
" generator {\n" +
" name = 'org.jooq.codegen.DefaultGenerator'\n" +
" strategy {\n" +
" name = 'org.jooq.codegen.DefaultGeneratorStrategy'\n" +
" }\n" +
" database {\n" +
" name = 'org.jooq.meta.h2.H2Database'\n" +
" inputSchema = 'PUBLIC'\n" +
" }\n" +
" generate {\n" +
" daos = true\n" +
" records = true\n" +
" immutablePojos = true\n" +
" }\n" +
" target {\n" +
" packageName = 'com.example.jooq'\n" +
" directory = '${project.buildDir}/generated-jooq'\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// 运行 Gradle 任务
BuildResult result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());
}
}

说明:

  • 使用 JUnit 5 的注解 @TempDir 代替 JUnit 4 的 @Rule TemporaryFolder
  • 使用 org.junit.jupiter.api 的断言方法。

5. 增加更多测试

为了确保插件的不同功能和配置都能正常工作,建议编写更多的测试用例。例如:

  • 测试默认配置:验证插件在没有额外配置时使用的默认值是否正确。
  • 测试自定义配置:验证用户覆盖默认配置时,插件是否正确应用了这些配置。
  • 测试错误处理:验证插件在配置错误或缺失时能否给出适当的错误提示。
  • 测试任务执行:验证插件添加的任务是否按预期执行,例如生成的代码是否存在且正确。

示例:测试默认配置

@Test
public void testDefaultConfiguration() throws IOException {
// 创建 build.gradle 文件,仅应用插件,不添加额外配置
buildFile = testProjectDir.newFile("build.gradle");
String buildFileContent = "plugins {\n" +
" id 'org.moonlit.jooq'\n" +
"}\n" +
"\n" +
"repositories {\n" +
" mavenCentral()\n" +
"}\n";

Files.write(buildFile.toPath(), buildFileContent.getBytes());

// 运行 Gradle 任务
BuildResult result = GradleRunner.create()
.withProjectDir(testProjectDir.getRoot())
.withPluginClasspath()
.withArguments("generateJooq")
.build();

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq").getOutcome());

// 验证默认生成目录
File generatedDir = new File(testProjectDir.getRoot(), "build/generated-jooq");
assertTrue(generatedDir.exists());
}

6. 使用 Spock 进行测试(可选)

如果你更喜欢使用 Groovy 和 Spock 框架进行测试,可以参考以下示例。

添加 Spock 依赖

build.gradle 中添加 Spock 相关依赖:

dependencies {
implementation 'org.jooq:jooq:3.18.4'
implementation 'nu.studer:gradle-jooq-plugin:5.2.1'

// 测试依赖
testImplementation gradleTestKit()
testImplementation 'org.spockframework:spock-core:2.0-groovy-3.0'
testImplementation 'org.codehaus.groovy:groovy-all:3.0.9'
}

test {
useJUnitPlatform()
}

编写 Spock 测试类

package org.moonlit.jooq

import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import spock.lang.Specification
import spock.lang.TempDir

import java.nio.file.Files

class CodegenJooqPluginSpockTest extends Specification {

@TempDir
File testProjectDir

File buildFile

def "插件应用成功并生成代码"() {
given:
buildFile = new File(testProjectDir, "build.gradle")
buildFile.text = """
plugins {
id 'org.moonlit.jooq'
}

repositories {
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = 'org.h2.Driver'
url = 'jdbc:h2:mem:testdb'
user = 'sa'
password = ''
}
generator {
name = 'org.jooq.codegen.DefaultGenerator'
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
}
database {
name = 'org.jooq.meta.h2.H2Database'
inputSchema = 'PUBLIC'
}
generate {
daos = true
records = true
immutablePojos = true
}
target {
packageName = 'com.example.jooq'
directory = '\${project.buildDir}/generated-jooq'
}
}
}
}
}
"""

when:
def result = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build()

then:
result.task(":generateJooq").outcome == TaskOutcome.SUCCESS

and:
new File(testProjectDir, "build/generated-jooq").exists()
}
}

说明:

  • Spock 框架:使用 Spock 进行测试,可以编写更具可读性的测试用例。
  • @TempDir:Spock 使用 @TempDir 注解创建临时目录。
  • 测试用例结构
    • given:设置测试前的条件和环境。
    • when:执行测试操作。
    • then:断言测试结果。

7. 持续集成(CI)

为了确保插件在每次提交时都通过测试,建议配置持续集成(CI)工具,如 GitHub ActionsGitLab CI 等。以下是使用 GitHub Actions 的示例。

创建 GitHub Actions 配置

在项目根目录下创建 .github/workflows/gradle.yml 文件:

name: Gradle CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

说明:

  • 触发条件:在 main 分支上的推送和拉取请求触发构建。
  • 作业步骤
    • 检出代码。
    • 设置 JDK 环境(这里使用 JDK 11,可以根据需要调整)。
    • 授予 gradlew 执行权限。
    • 运行 ./gradlew build,这将执行所有测试并构建项目。

8. 总结

通过以上步骤,你已经为自定义的 Gradle 插件 codegen-jooq-gradle-plugin 添加了单元测试,确保插件在不同配置下都能正常工作。以下是关键点的回顾:

  1. 配置测试环境:在 build.gradle 中添加 Gradle TestKit 和测试框架(JUnit 或 Spock)的依赖。
  2. 编写测试类:使用 Gradle TestKit 创建临时项目,应用插件,运行任务,并验证结果。
  3. 运行测试:通过 ./gradlew test 执行测试,确保所有测试通过。
  4. 扩展测试用例:编写更多测试用例,覆盖插件的各种配置和场景。
  5. 集成持续集成:配置 CI 工具,如 GitHub Actions,自动运行测试,确保代码质量。

使用Kotlin替换Groovy

好的,将之前基于 Groovy 的 build.gradle 示例转换为基于 Kotlin 的 build.gradle.kts,并调整测试部分以使用 Kotlin 和 JUnit 5,可以按照以下步骤进行。以下内容涵盖了插件项目的配置、插件实现、单元测试以及持续集成的设置,全部使用 Kotlin DSL。

1. 配置 build.gradle.kts

首先,将 build.gradle 文件转换为 build.gradle.kts,并调整其中的语法以符合 Kotlin DSL 的要求。

修改 build.gradle.kts

plugins {
`java-gradle-plugin`
`maven-publish`
`java`
}

group = "org.moonlit"
version = "1.0.0"

repositories {
mavenCentral()
}

dependencies {
implementation("org.jooq:jooq:3.18.4") // 根据需要调整版本
implementation("nu.studer:gradle-jooq-plugin:5.2.1") // 使用 gradle-jooq-plugin 的版本

// 测试依赖
testImplementation(gradleTestKit())
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") // 使用 JUnit 5
}

gradlePlugin {
plugins {
create("codegenJooq") {
id = "org.moonlit.jooq"
implementationClass = "org.moonlit.jooq.CodegenJooqPlugin"
displayName = "Codegen JOOQ Gradle Plugin"
description = "A custom Gradle plugin that extends gradle-jooq-plugin with default configurations."
}
}
}

publishing {
publications {
create<MavenPublication>("pluginMaven") {
from(components["java"])
groupId = "org.moonlit"
artifactId = "codegen-jooq-gradle-plugin"
version = "1.0.0"
}
}
repositories {
mavenLocal()
// 配置远程仓库(如需要)
/*
maven {
url = uri("https://your.repository.url")
credentials {
username = findProperty("repoUser") as String? ?: ""
password = findProperty("repoPassword") as String? ?: ""
}
}
*/
}
}

tasks.test {
useJUnitPlatform()
}

说明:

  • 插件应用:使用 Kotlin DSL 的插件语法,使用反引号 `` ` 包裹需要的插件名称。
  • 依赖管理:使用 Kotlin 的字符串模板语法。
  • 插件发布:使用 create<MavenPublication> 来创建 Maven 发布配置。
  • 测试配置:配置测试任务使用 JUnit 5 平台。

2. 创建插件实现类

插件的实现类保持不变,因为它是用 Java 编写的。如果你希望使用 Kotlin 编写插件实现,也可以选择这样做,但这里保持原样。

src/main/java/org/moonlit/jooq/ 目录下创建 CodegenJooqPlugin.java 文件(如果还未创建)。

package org.moonlit.jooq;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Action;
import nu.studer.gradle.jooq.JooqPluginExtension;
import nu.studer.gradle.jooq.JooqGenerate;

import java.io.File;

public class CodegenJooqPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
// 应用原始的 gradle-jooq-plugin
project.getPluginManager().apply("nu.studer.jooq");

// 获取 Jooq 插件的扩展
JooqPluginExtension jooqExtension = project.getExtensions().getByType(JooqPluginExtension.class);

// 设置默认配置
jooqExtension.getVersion().convention("3.18.4"); // 设置 JOOQ 版本

// 配置生成器
jooqExtension.getConfigurations().all(configuration -> {
configuration.getGenerate().convention(new Action<JooqGenerate>() {
@Override
public void execute(JooqGenerate generate) {
generate.getInputSchema().convention("public");
generate.getOutputDirectory().convention(new File(project.getBuildDir(), "generated-jooq"));
// 添加更多默认配置
generate.getGenerator().getName().convention("org.jooq.codegen.DefaultGenerator");
// 例如,设置目标包名
generate.getGenerator().getStrategy().getName().convention("org.jooq.codegen.DefaultGeneratorStrategy");
}
});
});

// 你可以在这里添加更多默认的配置,例如数据库连接、生成策略等
}
}

3. 添加单元测试

使用 Gradle TestKitJUnit 5 进行插件的单元测试。以下是如何编写基于 Kotlin 的测试类。

配置测试环境

确保 build.gradle.kts 文件中已经包含了必要的测试依赖和配置,如上所述。

创建测试类

src/test/kotlin/org/moonlit/jooq/ 目录下创建测试类 CodegenJooqPluginTest.kt

创建目录结构

确保项目结构如下:

codegen-jooq-gradle-plugin/
├── build.gradle.kts
├── settings.gradle.kts
├── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── moonlit/
│ │ └── jooq/
│ │ └── CodegenJooqPlugin.java
│ └── test/
│ └── kotlin/
│ └── org/
│ └── moonlit/
│ └── jooq/
│ └── CodegenJooqPluginTest.kt
编写测试类
package org.moonlit.jooq

import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import java.nio.file.Files

class CodegenJooqPluginTest {

@TempDir
lateinit var testProjectDir: File

private lateinit var buildFile: File

@Test
fun `test plugin applies successfully`() {
// 创建 build.gradle.kts 文件
buildFile = File(testProjectDir, "build.gradle.kts")
val buildFileContent = """
plugins {
id("org.moonlit.jooq") version "1.0.0"
}

repositories {
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:testdb"
user = "sa"
password = ""
}
generator {
name = "org.jooq.codegen.DefaultGenerator"
strategy {
name = "org.jooq.codegen.DefaultGeneratorStrategy"
}
database {
name = "org.jooq.meta.h2.H2Database"
inputSchema = "PUBLIC"
}
generate {
daos = true
records = true
immutablePojos = true
}
target {
packageName = "com.example.jooq"
directory = "${'$'}{project.buildDir}/generated-jooq"
}
}
}
}
}
""".trimIndent()

Files.write(buildFile.toPath(), buildFileContent.toByteArray())

// 运行 Gradle 任务
val result: BuildResult = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build()

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq")?.outcome)
}

@Test
fun `test plugin configuration`() {
// 创建 build.gradle.kts 文件
buildFile = File(testProjectDir, "build.gradle.kts")
val buildFileContent = """
plugins {
id("org.moonlit.jooq") version "1.0.0"
}

repositories {
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:testdb"
user = "sa"
password = ""
}
generator {
target {
packageName = "com.custom.jooq"
directory = "${'$'}{project.buildDir}/custom-generated-jooq"
}
}
}
}
}
""".trimIndent()

Files.write(buildFile.toPath(), buildFileContent.toByteArray())

// 运行 Gradle 任务
val result: BuildResult = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build()

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq")?.outcome)

// 验证生成目录是否存在
val generatedDir = File(testProjectDir, "build/custom-generated-jooq")
assertTrue(generatedDir.exists())
}

@Test
fun `test default configuration`() {
// 创建 build.gradle.kts 文件,仅应用插件,不添加额外配置
buildFile = File(testProjectDir, "build.gradle.kts")
val buildFileContent = """
plugins {
id("org.moonlit.jooq") version "1.0.0"
}

repositories {
mavenCentral()
}
""".trimIndent()

Files.write(buildFile.toPath(), buildFileContent.toByteArray())

// 运行 Gradle 任务
val result: BuildResult = GradleRunner.create()
.withProjectDir(testProjectDir)
.withPluginClasspath()
.withArguments("generateJooq")
.build()

// 断言任务成功
assertEquals(TaskOutcome.SUCCESS, result.task(":generateJooq")?.outcome)

// 验证默认生成目录
val generatedDir = File(testProjectDir, "build/generated-jooq")
assertTrue(generatedDir.exists())
}
}

说明:

  • @TempDir:使用 JUnit 5 的 @TempDir 注解创建临时目录,替代 JUnit 4 的 @Rule
  • 测试方法:使用 Kotlin 的测试方法名称,采用反引号包裹以支持空格和更具描述性的名称。
  • 字符串模板:使用 Kotlin 的字符串模板语法 ${'$'}{} 来嵌入变量。
  • 断言:使用 JUnit 5 的断言方法,如 assertEqualsassertTrue

4. 使用 JUnit 5

上面的测试类已经配置为使用 JUnit 5。如果你希望进一步自定义或扩展测试配置,可以在 build.gradle.kts 中进行调整。

示例 build.gradle.kts 测试配置

tasks.test {
useJUnitPlatform()
}

5. 持续集成(CI)

配置 GitHub Actions 以使用 Kotlin DSL 的 Gradle 项目进行持续集成。创建 .github/workflows/gradle.yml 文件。

创建 GitHub Actions 配置

name: Gradle CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

说明:

  • 触发条件:在 main 分支上的推送和拉取请求触发构建。
  • 作业步骤
    • 检出代码。
    • 设置 JDK 环境(这里使用 JDK 11,可以根据需要调整)。
    • 授予 gradlew 执行权限。
    • 运行 ./gradlew build,这将执行所有测试并构建项目。

6. 示例项目

为了帮助用户更好地理解和使用你的插件,可以创建一个基于 Kotlin DSL 的示例项目,并在 README.md 中提供使用说明。

示例项目结构

example-project/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
└── main/
└── kotlin/
└── com/
└── example/
└── App.kt

示例 build.gradle.kts

plugins {
id("org.moonlit.jooq") version "1.0.0"
}

repositories {
mavenLocal()
mavenCentral()
}

jooq {
configurations {
main {
jdbc {
driver = "org.postgresql.Driver"
url = "jdbc:postgresql://localhost:5432/mydb"
user = "username"
password = "password"
}
generator {
database {
name = "org.jooq.meta.postgres.PostgresDatabase"
inputSchema = "public"
}
target {
packageName = "com.example.jooq"
directory = "${"$"}{project.buildDir}/generated-jooq"
}
}
}
}
}

说明:

  • 插件应用:应用自定义插件 org.moonlit.jooq
  • 仓库配置:添加 mavenLocalmavenCentral 仓库。
  • JOOQ 配置:配置 JDBC 连接和生成器设置,使用默认配置的同时允许覆盖。

7. 总结

通过以上步骤,你已经成功将基于 Groovy 的 build.gradle 文件转换为基于 Kotlin 的 build.gradle.kts,并调整了单元测试以使用 Kotlin 和 JUnit 5。以下是关键点的回顾:

  1. Kotlin DSL 配置
    • 使用 build.gradle.kts 进行项目配置。
    • 调整插件应用和依赖管理以符合 Kotlin 语法。
  2. 单元测试
    • 使用 Gradle TestKitJUnit 5 编写测试。
    • 使用 Kotlin 编写测试类,利用 @TempDir 创建临时目录。
  3. 持续集成
    • 配置 GitHub Actions 以自动构建和测试插件。
  4. 示例项目
    • 创建一个使用自定义插件的示例项目,展示如何在 Kotlin DSL 中应用插件和进行配置。

确保在开发过程中持续编写和维护测试用例,这将大大提升插件的稳定性和可靠性。如果在开发过程中遇到任何问题,建议参考以下资源:

gradle testing

testing {  
suites {
// Configure the built-in test suite
val test by getting(JvmTestSuite::class) {
// Use JUnit Jupiter test framework
useJUnitJupiter("5.10.3")
}

// Create a new test suite
val functionalTest by registering(JvmTestSuite::class) {
dependencies {
// functionalTest test suite depends on the production code in tests
implementation(project())
}

targets {
all {
// This test suite should run after the built-in test suite has run its tests
testTask.configure { shouldRunAfter(test) }
}
}
}
}
}

这段代码是使用 Gradle Kotlin DSL 定义了一个用于配置测试套件的部分。它使用了 Gradle 的 testing 块,并定义了两个测试套件:一个是内置的 test 套件,另一个是自定义的 functionalTest 套件。具体的解释如下:

1. testing

testing 是 Gradle 用于配置测试套件的 DSL(领域特定语言)。它允许你定义和配置不同的测试套件(如单元测试、功能测试等)。

2. suites

suites 是用于定义多个测试套件的容器。每个测试套件可以有自己的配置和依赖。

3. 内置的 test 测试套件

  • val test by getting(JvmTestSuite::class):这里获取了内置的 test 测试套件,这个套件默认用于执行 JVM(Java Virtual Machine)相关的单元测试。
  • useJUnitJupiter("5.10.3"):指定该套件使用 JUnit Jupiter 作为测试框架,具体的版本是 5.10.3。JUnit Jupiter 是 JUnit 5 中的模块,支持现代化的测试写法。

4. 创建新的 functionalTest 测试套件

  • val functionalTest by registering(JvmTestSuite::class):这里定义了一个新的 functionalTest 测试套件,继承自 JvmTestSuite 类,表示它是一个针对 JVM 运行的测试套件。

  • 依赖配置

    dependencies {
    implementation(project())
    }

    这段代码表示 functionalTest 套件的依赖关系。implementation(project()) 表示 functionalTest 测试套件依赖于项目的生产代码。这意味着运行功能测试时会使用项目中的代码。

  • 运行顺序配置

    targets {
    all {
    testTask.configure { shouldRunAfter(test) }
    }
    }

    这里配置了 functionalTest 测试套件的运行顺序:

    • testTask.configure { shouldRunAfter(test) }:表示 functionalTest 测试任务应该在内置的 test 测试任务之后运行。这确保功能测试在单元测试运行完毕后才会执行。

总结

这段代码完成了以下配置:

  1. 配置内置单元测试套件,使用 JUnit Jupiter 作为测试框架。
  2. 定义了一个新的功能测试套件 functionalTest,并配置了其依赖关系,确保它依赖于项目的生产代码。
  3. 确保功能测试在单元测试之后执行,通过 shouldRunAfter(test) 来定义运行顺序。

gradle testing vs dependencies中添加测试依赖

在你的代码中,使用了 dependencies 块来定义项目的依赖关系,特别是 testImplementation 部分。这段代码的作用和你前面提到的 testing 块有一些区别,主要表现在测试组织和配置的方式上。让我先解释你这段代码的作用,然后再对比这两种方式是否能达到相同效果。

1. 你这段代码的作用

dependencies {
implementation("org.jooq:jooq:3.18.4")
implementation("nu.studer:gradle-jooq-plugin:5.2.1")

testImplementation(gradleTestKit())
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
}
  • implementation:

    • "org.jooq:jooq:3.18.4":引入了 JOOQ 库版本 3.18.4,用于项目中处理数据库访问。
    • "nu.studer:gradle-jooq-plugin:5.2.1":引入了 Gradle JOOQ 插件,帮助你生成基于数据库 schema 的代码。
  • testImplementation:

    • testImplementation(gradleTestKit()):引入了 Gradle TestKit,这个库可以用于编写测试来验证 Gradle 插件或构建脚本的行为。通常用于测试 Gradle 插件开发。
    • "org.junit.jupiter:junit-jupiter:5.8.1":引入了 JUnit Jupiter(JUnit 5)的测试框架,版本为 5.8.1,用于编写和执行单元测试或功能测试。

2. CodegenJooqPluginTest.kt 文件的作用

src/test/kotlin/org/moonlit/jooq/ 目录下创建的测试类 CodegenJooqPluginTest.kt,假设你在其中编写的是针对 JOOQ 代码生成插件的测试,通常是通过 JUnit 框架来执行的。

你可能会在这个测试类中使用 Gradle TestKit 来测试你的 Gradle 构建脚本行为,或者通过 JUnit 框架来测试与 JOOQ 相关的代码逻辑。

3. 与前面代码的比较(testing 块 vs dependencies 块)

  • testing

    • 用于声明多个测试套件(例如 testfunctionalTest),并为每个测试套件定义不同的依赖和运行顺序。
    • 这种方式是 Gradle 6.7 之后引入的新方式,适合需要精细化控制多个测试阶段或任务的情况。例如:确保功能测试在单元测试之后执行。
  • 你当前的 dependencies

    • 这是传统的 Gradle 配置方式,直接通过 testImplementation 为所有的测试类提供依赖。这种方式适合你只需要一个简单的测试层次结构,比如单元测试。
    • 不提供类似 testing 块中的多测试套件、运行顺序的细粒度控制,所有测试都会被放到默认的 test 任务中运行。

4. 效果对比

  • 共同点

    • 两种方式都能引入 JUnit 作为测试框架,执行测试类(如 CodegenJooqPluginTest.kt)。
    • 如果你只需要一个简单的单元测试环境,你的 dependencies 块就足够了,可以使用 JUnit 测试 JOOQ 生成的代码,或测试与 Gradle 插件的集成。
  • 不同点

    • 使用 testing 块,你可以更灵活地定义多个测试套件(例如 testfunctionalTest),并可以控制它们的执行顺序。这对于复杂的项目或需要分开运行不同类型测试(如单元测试和集成测试)更有帮助。
    • 你当前的 dependencies 方式虽然简洁,但如果将来需要功能测试或集成测试,可能不够灵活,因为它只会生成一个默认的 test 任务,所有测试都会被一起执行。

5. 适用场景建议

  • 如果你目前只需要简单的单元测试,或者测试你自己开发的 Gradle 插件行为,那么你现在的 dependencies 配置是足够的。
  • 如果你想将测试分为多个阶段,或未来需要更多测试类型(如功能测试、集成测试),那么使用 testing 块并配置不同的测试套件会更合适。

总结:

你当前的 dependencies 块配置方式可以满足单一测试套件的需求,适合简单的测试场景。但如果你需要类似前面 testing 块中的多套件、多类型测试并控制执行顺序,就需要使用更高级的 testing DSL 配置方式。