Micronaut projectgen

API to generate JVM projects

Version: 0.0.2-SNAPSHOT

1 Introduction

Micronaut ProjectGen offers an API to generate JVM projects.

2 Release History

For this project, you can find a list of releases (with release notes) here:

3 Modules

3.1 Core Module

The following dependency contains the core APIs to generate applications.

implementation("io.micronaut.projectgen:micronaut-projectgen-core")
<dependency>
    <groupId>io.micronaut.projectgen</groupId>
    <artifactId>micronaut-projectgen-core</artifactId>
</dependency>

3.2 Test Module

The following dependency contains utilities to test the generated application.

testImplementation("io.micronaut.projectgen:micronaut-projectgen-test")
<dependency>
    <groupId>io.micronaut.projectgen</groupId>
    <artifactId>micronaut-projectgen-test</artifactId>
    <scope>test</scope>
</dependency>

3.3 HTTP Server Module

If you want to expose your project generator in an HTTP Server, add the following dependency:

implementation("io.micronaut.projectgen:micronaut-projectgen-http-server")
<dependency>
    <groupId>io.micronaut.projectgen</groupId>
    <artifactId>micronaut-projectgen-http-server</artifactId>
</dependency>

3.3.1 Download ZIP

A POST endpoint with a application/x-www-form-urlencoded content type allows you to download a ZIP file:

🔗
Table 1. Configuration Properties for DownloadZipControllerConfiguration
Property Type Description

projectgen.controllers.download-zip.enabled

boolean

Whether the controller is enabled. Default value: true.

projectgen.controllers.download-zip.path

java.lang.String

Controller path. Default value: /api/v1/download/zip

3.3.2 Features

A POST endpoint with a application/x-www-form-urlencoded content type allows you to get a JSON payload with the visible features.

🔗
Table 1. Configuration Properties for FeaturesControllerConfiguration
Property Type Description

projectgen.controllers.features.enabled

boolean

Whether the controller is enabled. Default value: true.

projectgen.controllers.features.path

java.lang.String

Controller path. Default value: /api/v1/features

3.3.3 Diff

Adding the following dependency, a bean of type FeatureDiffer is registered:

implementation("io.github.java-diff-utils:java-diff-utils:4.15")
<dependency>
    <groupId>io.github.java-diff-utils</groupId>
    <artifactId>java-diff-utils</artifactId>
    <version>4.15</version>
</dependency>

Once you have a bean of type FeatureDiffer and the io.micronaut.projectgen:micronaut-projectgen-http-server dependency the following endpoints which accept aPOST endpoints with a application/x-www-form-urlencoded content type.

🔗
Table 1. Configuration Properties for DiffControllerConfiguration
Property Type Description

project.controllers.diff.enabled

boolean

Whether the controller is enabled. Default value: true.

project.controllers.diff.path

java.lang.String

Controller path. Default value: /api/v1/diff

🔗
Table 2. Configuration Properties for DownloadDiffControllerConfiguration
Property Type Description

projectgen.controllers.download-diff.enabled

boolean

Whether the controller is enabled. Default value: true.

projectgen.controllers.download-diff.path

java.lang.String

Controller path. Default value: /api/v1/download/diff

4 Features

To generate a project, you create beans of type Feature.

Each feature has a unique identifier; you can offer a UI to allow users to select a feature.

5 Demo

To talk about the ProjectGen API, let’s discuss the following demo: a Hello World application with Maven and Gradle.

The project structure will be like this:

├── build.gradle.kts
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── mvnw
├── mvnw.bat
├── pom.xml
├── settings.gradle.kts
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── example
    │               └── HelloWorld.java
    └── test
        └── java
            └── com
                └── example
                    └── HelloWorldTest.java

You want to generate a build.gradle.kts with the following content:

plugins {
    id("java")
    id("application")
}
group = "io.micronaut.projectgen"
version = "1.0.0"
repositories {
    mavenCentral()
}
dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}
tasks.test {
    useJUnitPlatform()
}

application {
    mainClass.set("com.example.HelloWorld")
}

and a pom.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>io.micronaut.projectgen</groupId>
  <artifactId>demo-project</artifactId>
  <version>1.0.0</version>
  <properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.10.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.1.2</version>
      </plugin>
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.3.0</version>
          <configuration>
              <archive>
                  <manifest>
                      <mainClass>com.example.HelloWorld</mainClass>
                  </manifest>
              </archive>
          </configuration>
      </plugin>
    </plugins>
  </build>
</project>

5.1 Options

To generate a project, you need an implementation of the interface Options.

For example:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.BuildTool;
import io.micronaut.projectgen.core.buildtools.gradle.GradleDsl;
import io.micronaut.projectgen.core.options.GenericOptionsBuilder;
import io.micronaut.projectgen.core.options.JdkVersion;
import io.micronaut.projectgen.core.options.Options;

import java.util.List;

public final class OptionsFactory {
    private OptionsFactory() {
    }

    public static Options create(List<String> features) {
        return GenericOptionsBuilder.builder()
                .name("demo")
                .packageName("com.example")
                .group("io.micronaut.projectgen")
                .artifact("demo-project")
                .version("1.0.0")
                .features(features)
                .buildTools(List.of(BuildTool.MAVEN, BuildTool.GRADLE))
                .gradleDsl(GradleDsl.KOTLIN)
                .java(JdkVersion.JDK_21)
                .build();
    }
}

5.2 Add Dependency

The following feature adds a dependency:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.MavenCentral;
import io.micronaut.projectgen.core.buildtools.dependencies.Dependency;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.generator.ModuleContext;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;

@Singleton
class JunitJupiter implements Feature {
    private static final Dependency DEPENDENCY_JUNIT_JUPITER = Dependency.builder() (1)
        .groupId("org.junit.jupiter")
        .artifactId("junit-jupiter")
        .version("5.10.2")
        .test()
        .build();

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public String getName() {
        return "junit-jupiter";
    }

    @Override
    public String getDescription() {
        return "Adds the JUnit Jupiter dependency to the project";
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        ModuleContext module = generatorContext.getRootModule();
        if (OptionUtils.hasGradleBuildTool(generatorContext.getOptions())) {
            module.repositories().add(new MavenCentral()); (1)
        }
        module.addDependency(DEPENDENCY_JUNIT_JUPITER); (2)
    }
}
1 A feature can add repository.
2 You can use fluid Dependency API to add dependencies to your project.

5.3 Add Build Properties

The following feature adds build properties:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.BuildProperties;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.options.Options;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;

@Singleton
class MavenCompilerProperties implements Feature {
    @Override
    public String getName() {
        return "maven-compiler-properties";
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        Options options = generatorContext.getOptions();
        if (OptionUtils.hasMavenBuildTool(options)) {
            BuildProperties buildProperties = generatorContext.getRootModule()
                .buildProperties();
            String java = String.valueOf(options
                .java()
                .majorVersion());
            buildProperties.put("maven.compiler.source", java);
            buildProperties.put("maven.compiler.target", java);
        }
    }
}

5.4 Add Gradle Plugins

You can use ProjectGen GradlePlugin API to add Gradle Plugins to a project.

The following feature adds the Gradle Java Plugin.

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.gradle.GradlePlugin;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;

@Singleton
class GradleJavaPluginFeature implements Feature {
    @Override
    public String getName() {
        return "gradle-plugin-java";
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        if (OptionUtils.hasGradleBuildTool(generatorContext.getOptions())) {
            int javaVersion = generatorContext.getOptions()
                .java()
                .majorVersion();
            generatorContext.getRootModule()
                .addBuildPlugin(GradlePlugin.builder()
                    .id("java")
                    .extension(String.format("""
                        java {
                            sourceCompatibility = JavaVersion.VERSION_%1$d
                            targetCompatibility = JavaVersion.VERSION_%1$d
                        }
                        tasks.test {
                            useJUnitPlatform()
                        }""", javaVersion))
                .build());
        }
    }
}

The following feature adds Gradle Application Plugin:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.gradle.GradlePlugin;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;

@Singleton
class GradleApplicationPluginFeature implements Feature {
    @Override
    public String getName() {
        return "gradle-plugin-application";
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        if (OptionUtils.hasGradleBuildTool(generatorContext.getOptions())) {
            generatorContext.getRootModule()
                .addBuildPlugin(GradlePlugin.builder()
                    .id("application")
                    .extension("""
                application {
                    mainClass.set("%s.HelloWorld")
                }""".formatted(generatorContext.getOptions().packageName()))
                    .build());
        }

    }
}

5.5 Add Maven Plugins

You can use ProjectGen MavenPlugin API to add Maven Plugins to a project.

The following feature adds the Maven Jar Plugin.

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.maven.MavenPlugin;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import jakarta.inject.Singleton;

@Singleton
class MavenJarPluginFeature implements Feature {
    @Override
    public String getName() {
        return "maven-jar-plugin";
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        generatorContext.getRootModule().addBuildPlugin(MavenPlugin.builder()
            .groupId("org.apache.maven.plugins")
            .artifactId("maven-jar-plugin")
            .extension(String.format("""
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>%s.HelloWorld</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>""", generatorContext.getOptions().packageName()))
            .build());
    }
}

The following feature adds Maven Surefire Plugin:

package io.micronaut.projectgen.demo;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.projectgen.core.buildtools.maven.MavenPlugin;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;

@Singleton
class MavenSurefirePlugin implements Feature {
    private static final @NonNull MavenPlugin MAVEN_PLUGIN_SUREFIRE = MavenPlugin.builder() (1)
        .groupId("org.apache.maven.plugins")
        .artifactId("maven-surefire-plugin")
        .version("3.1.2")
        .build();

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public String getName() {
        return "maven-surefire-plugin";
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        if (OptionUtils.hasMavenBuildTool(generatorContext.getOptions())) {
            generatorContext.getRootModule().addBuildPlugin(MAVEN_PLUGIN_SUREFIRE);
        }
    }
}

5.6 Add Code

The following feature adds source code:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.generator.ModuleContext;
import io.micronaut.projectgen.core.template.StringTemplate;
import jakarta.inject.Singleton;

@Singleton
class SampleCode implements Feature {
    @Override
    public String getName() {
        return "sample-code";
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        ModuleContext module = generatorContext.getRootModule();
        addHelloWorldJavaClass(module);
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    private void addHelloWorldJavaClass(ModuleContext module) {
        String path = "src/main/java/com/example/HelloWorld.java";
        module.addTemplate("HelloWorld.java", new io.micronaut.projectgen.core.template.StringTemplate(path, """
            package com.example;

            public class HelloWorld {
                public static void main(String[] args) {
                    System.out.println(hello());
                }

                public static String hello() {
                    return "Hello, World!";
                }
            }
            """));
    }
}

You can add files to the generated project. The previous example shows a String, but you can use the RockerWritable API to render files with Rocker Templates.

5.7 Default Feature

You can create beans of type DefaultFeature to be automatically applied if the method DefaultFeature::shouldApply evaluates to true.

A common pattern is to define a DefaultFeature to act as the entry point of the project generation.

A feature can apply other features as shown below:

package io.micronaut.projectgen.demo;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.projectgen.core.buildtools.BuildProperties;
import io.micronaut.projectgen.core.buildtools.MavenCentral;
import io.micronaut.projectgen.core.buildtools.dependencies.Dependency;
import io.micronaut.projectgen.core.buildtools.gradle.GradlePlugin;
import io.micronaut.projectgen.core.buildtools.maven.MavenPlugin;
import io.micronaut.projectgen.core.feature.DefaultFeature;
import io.micronaut.projectgen.core.feature.Feature;
import io.micronaut.projectgen.core.feature.FeatureContext;
import io.micronaut.projectgen.core.generator.GeneratorContext;
import io.micronaut.projectgen.core.generator.ModuleContext;
import io.micronaut.projectgen.core.options.Options;
import io.micronaut.projectgen.core.utils.OptionUtils;
import jakarta.inject.Singleton;
import io.micronaut.projectgen.core.template.StringTemplate;
import java.util.Set;

@Singleton
class Root implements DefaultFeature {

    private final GradleJavaPluginFeature gradleJavaPluginFeature;
    private final GradleApplicationPluginFeature gradleApplicationPluginFeature;
    private final MavenSurefirePlugin mavenSurefirePlugin;
    private final MavenJarPluginFeature mavenJarPluginFeature;
    private final SampleCode sampleCode;
    private final MavenCompilerProperties mavenCompilerProperties;

    Root(GradleJavaPluginFeature gradleJavaPluginFeature,
         GradleApplicationPluginFeature gradleApplicationPluginFeature,
         MavenSurefirePlugin mavenSurefirePlugin,
         MavenJarPluginFeature mavenJarPluginFeature,
         SampleCode sampleCode, MavenCompilerProperties mavenCompilerProperties) {
        this.gradleJavaPluginFeature = gradleJavaPluginFeature;
        this.gradleApplicationPluginFeature = gradleApplicationPluginFeature;
        this.mavenSurefirePlugin = mavenSurefirePlugin;
        this.mavenJarPluginFeature = mavenJarPluginFeature;
        this.sampleCode = sampleCode;
        this.mavenCompilerProperties = mavenCompilerProperties;
    }

    @Override
    public void processSelectedFeatures(FeatureContext featureContext) {
        featureContext.addFeature(gradleJavaPluginFeature);
        featureContext.addFeature(gradleApplicationPluginFeature);
        featureContext.addFeature(mavenSurefirePlugin);
        featureContext.addFeature(mavenJarPluginFeature);
        featureContext.addFeature(sampleCode);
        featureContext.addFeature(mavenCompilerProperties);
    }

    @Override
    public boolean shouldApply(Options options, Set<Feature> selectedFeatures) {
        return true;
    }

    @Override
    public String getName() {
        return "entry-point";
    }

    @Override
    public String getDescription() {
        return "It generates a Hello World Maven and Gradle project";
    }

    @Override
    public boolean isVisible() {
        return false;
    }

    @Override
    public void apply(GeneratorContext generatorContext) {
        ModuleContext module = generatorContext.getRootModule();
        Options options = generatorContext.getOptions();
        populateModuleAttributes(module, options);
    }

    private void populateModuleAttributes(ModuleContext module, Options options) {
        module.moduleAttributes()
            .setCoordinate(Dependency.builder()
                .groupId(options.group())
                .artifactId(options.artifact())
                .version(options.version())
                .build());
    }
}

5.8 Project Generation in a Command Line Application

Generate projects in a command line application is a common use case of project generation. The following example shows a Micronaut CLI application which generates a project:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.BuildTool;
import io.micronaut.projectgen.core.buildtools.gradle.GradleDsl;
import io.micronaut.projectgen.core.generator.ProjectGenerator;
import io.micronaut.projectgen.core.options.GenericOptionsBuilder;
import io.micronaut.projectgen.core.options.JdkVersion;
import io.micronaut.projectgen.core.options.Options;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import jakarta.inject.Inject;

import java.io.File;
import java.util.List;

@Command(
    name = "create",
    description = "Create a new project"
)
public class CreateCommand implements Runnable {
    @CommandLine.Option(
        names = { "--output", "-o" },
        required = true,
        description = "The output folder where the project file will be generated")
    private File outputDir;

    @CommandLine.Option(
        names = { "--features", "-f" },
        description = "Comma-separated list of features to include",
        split = ",")
    private List<String> features;

    @Inject
    ProjectGenerator projectGenerator;

    @Override
    public void run() {
        if (!outputDir.exists() || !outputDir.isDirectory()) {
            System.err.println("Provided path is not an existing directory: " + outputDir);
        } else {
            Options options = GenericOptionsBuilder.builder()
                .name("demo")
                .packageName("com.example")
                .group("io.micronaut.projectgen")
                .artifact("demo-project")
                .version("1.0.0")
                .features(features)
                .buildTools(List.of(BuildTool.GRADLE, BuildTool.MAVEN))
                .gradleDsl(GradleDsl.KOTLIN)
                .java(JdkVersion.JDK_21)
                .build();
            projectGenerator.writeTo(options, outputDir);
        }
    }
}
1 To generate a project into a folder, you can use the ProjectGenerator API.

5.9 Project Generation in a HTTP Server

The following controller renders an HTML with a button that downloads a ZIP file with a project:

package io.micronaut.projectgen.demo;

import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;

@Controller
class HomeController {

    @Get
    @Produces(MediaType.TEXT_HTML)
    String index() {
        return """
            <!DOCTYPE html>
            <html>
            <head>
            <title>Download Project</title>
            </head>
            <body>
            <form action="/api/v1/download/zip" method="POST">
                <fieldset>
                    <input type="hidden" name="name" value="demo"/>
                    <input type="hidden" name="packageName" value="com.example"/>
                    <input type="hidden" name="group" value="io.micronaut.projectgen"/>
                    <input type="hidden" name="artifact" value="demo-project"/>
                    <input type="hidden" name="version" value="1.0.0"/>
                    <input type="hidden" name="build" value="MAVEN,GRADLE"/>
                    <input type="hidden" name="gradleDsl" value="KOTLIN"/>
                    <input type="hidden" name="java" value="21"/>
                    <input type="checkbox" name="features" value="hello-world-test"/> Generate Test<br/>
                    <input type="submit" value="Download" />
                </fieldset>

            </form>
            </body>
            </html>
            """;
    }
}
To render server-side HTML, use Micronaut Views.
package io.micronaut.projectgen.demo;

import io.micronaut.http.HttpRequest;
import io.micronaut.http.MediaType;
import io.micronaut.http.client.BlockingHttpClient;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.projectgen.core.buildtools.BuildTool;
import io.micronaut.projectgen.core.buildtools.gradle.GradleDsl;
import io.micronaut.projectgen.core.options.JdkVersion;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@MicronautTest
class FeaturesTest {

    @Test
    void testFeaturesEndpoint(@Client("/") HttpClient httpClient) throws JSONException {
        BlockingHttpClient client = httpClient.toBlocking();

        Map<String, Object> form = new HashMap<>();
        form.put("name", "demo");
        form.put("packageName", "com.example");
        form.put("group", "io.micronaut.projectgen");
        form.put("artifact", "demo-project");
        form.put("version", "1.0.0");
        form.put("features", "hello-world-test");
        form.put("build", List.of(BuildTool.MAVEN, BuildTool.GRADLE));
        form.put("gradleDsl", GradleDsl.KOTLIN);
        form.put("java", JdkVersion.JDK_21);

        HttpRequest<?> request = HttpRequest.POST("/api/v1/features", form)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
        String json = assertDoesNotThrow(() -> client.retrieve(request));
        assertNotNull(json);
        String expected = """
            {
                "features":
                    [
                        {
                            "name":"hello-world-test",
                            "title":"Add Test",
                            "description":"Add Unit tests with Junit5 dependency",
                            "preview":false,
                            "community":false
                         }
                    ]
            }
            """;
        JSONAssert.assertEquals(
            expected, json, JSONCompareMode.LENIENT);
    }
}

5.10 Test Project Generation

You can test the project generation easily:

package io.micronaut.projectgen.demo;

import io.micronaut.projectgen.core.buildtools.BuildTool;
import io.micronaut.projectgen.core.buildtools.Scope;
import io.micronaut.projectgen.core.io.PreviewGenerator;
import io.micronaut.projectgen.core.options.Options;
import io.micronaut.projectgen.test.BuildTestVerifier;
import io.micronaut.projectgen.test.GradleBuildTestVerifier;
import io.micronaut.projectgen.test.MavenBuildTestVerifier;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@MicronautTest(startApplication = false)
class ProjectGenTest {

    @Test
    void testProjectGeneration(PreviewGenerator previewGenerator) throws Exception {
        Options options = OptionsFactory.create(Collections.emptyList());
        Map<String, String> project = previewGenerator.generate(options);
        assertTrue(project.containsKey("mvnw"));
        assertTrue(project.containsKey("mvnw.bat"));
        assertTrue(project.containsKey(".mvn/wrapper/maven-wrapper.jar"));
        assertTrue(project.containsKey(".mvn/wrapper/maven-wrapper.properties"));
        assertTrue(project.containsKey("pom.xml"));
        assertTrue(project.containsKey("src/main/java/com/example/HelloWorld.java"));
        assertFalse(project.containsKey("src/test/java/com/example/HelloWorldTest.java"));
        String pom = project.get("pom.xml");
        BuildTestVerifier verifier = new MavenBuildTestVerifier(pom, options.language());
        assertEquals("21", verifier.getProperty("maven.compiler.source"));
        assertEquals("21", verifier.getProperty("maven.compiler.target"));
        assertTrue(verifier.hasBuildPlugin("org.apache.maven.plugins", "maven-jar-plugin"));
        String buildGradleKts = project.get("build.gradle.kts");
        verifier = new GradleBuildTestVerifier(buildGradleKts, BuildTool.GRADLE, options.language(), options.testFramework());
        assertFalse(verifier.hasDependency("org.junit.jupiter", "junit-jupiter", Scope.TEST));
        assertTrue(verifier.hasBuildPlugin("java"));
        assertTrue(verifier.hasBuildPlugin("application"));
        assertTrue(project.containsKey("settings.gradle.kts"));
        String settings = project.get("settings.gradle.kts");
        assertEquals("""
        rootProject.name="demo"
        """, settings);
        assertTrue(project.containsKey("gradlew"));
        assertTrue(project.containsKey("gradlew.bat"));
        assertTrue(project.containsKey("gradle/wrapper/gradle-wrapper.jar"));
        assertTrue(project.containsKey("gradle/wrapper/gradle-wrapper.properties"));

        options = OptionsFactory.create(List.of("hello-world-test"));
        project = previewGenerator.generate(options);
        buildGradleKts = project.get("build.gradle.kts");
        assertTrue(project.containsKey("src/test/java/com/example/HelloWorldTest.java"));
        verifier = new GradleBuildTestVerifier(buildGradleKts, BuildTool.GRADLE, options.language(), options.testFramework());
        assertTrue(verifier.hasDependency("org.junit.jupiter", "junit-jupiter", Scope.TEST), buildGradleKts);

        assertTrue(project.containsKey("projectgen.properties"));
        String props = project.get("projectgen.properties");
        assertEquals("""
            artifact=demo-project
            java=JDK_21
            buildTools[0]=maven
            buildTools[1]=gradle
            gradleDsl=KOTLIN
            name=demo
            packageName=com.example
            version=1.0.0
            group=io.micronaut.projectgen
            """, props);
    }
}

6 Repository

You can find the source code of this project in this repository: