From 363e5f1c51bc3c35b7f2e12f7f4c7986c4065dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Sat, 21 Feb 2026 13:56:20 +0100 Subject: [PATCH 01/11] feat: upgraded to quarkus 3.31 --- pom.xml | 11 ++++++----- src/main/resources/application.properties | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 3ade41e..b5d92d4 100644 --- a/pom.xml +++ b/pom.xml @@ -6,15 +6,15 @@ project-services 1.0.0-SNAPSHOT - 3.12.1 - 17 + 3.14.1 + 25 UTF-8 UTF-8 quarkus-bom io.quarkus.platform - 3.9.1 + 3.31.4 true - 3.2.5 + 3.5.4 0.3.1 @@ -67,6 +67,7 @@ io.quarkus quarkus-maven-plugin ${quarkus.platform.version} + true @@ -121,7 +122,7 @@ - native + native diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b08a5df..247cd1c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -15,10 +15,10 @@ data-database-name=dontCodeDevData %scalewaytest.projects-database-name=dontCodeTestProjects %scalewaytest.data-database-name=dontCodeTestData -quarkus.http.cors=true +quarkus.http.cors.enabled=true quarkus.http.cors.origins=/.*/ -quarkus.package.type=uber-jar +quarkus.package.jar.type=uber-jar quarkus.log.level=INFO quarkus.log.category."net.dontcode.prj".level=DEBUG From 73666a2a0299b7d6eff1c69e1102c607ee80f1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Mon, 23 Feb 2026 18:20:20 +0100 Subject: [PATCH 02/11] feat: Application generator with Mistral --- .github/workflows/dev-build.yml | 6 +- .github/workflows/main-build.yml | 6 +- .github/workflows/release.yml | 6 +- pom.xml | 11 ++ .../dontcode/prj/GenerateProjectResource.java | 29 +++++ .../dontcode/prj/GenerateProjectService.java | 21 ++++ .../net/dontcode/prj/ProjectResource.java | 109 ++-------------- .../java/net/dontcode/prj/ProjectService.java | 118 ++++++++++++++++++ .../prj/model/DontCodeProjectContent.java | 5 + .../prj/model/DontCodeProjectCreation.java | 4 + .../model/DontCodeProjectCreationType.java | 18 +++ .../prj/model/DontCodeProjectEntities.java | 4 + .../prj/model/DontCodeProjectField.java | 4 + .../prj/model/DontCodeProjectModel.java | 9 ++ src/main/resources/application.properties | 4 + .../prj/GenerateProjectServiceTest.java | 21 ++++ 16 files changed, 267 insertions(+), 108 deletions(-) create mode 100644 src/main/java/net/dontcode/prj/GenerateProjectResource.java create mode 100644 src/main/java/net/dontcode/prj/GenerateProjectService.java create mode 100644 src/main/java/net/dontcode/prj/ProjectService.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectField.java create mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java create mode 100644 src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index e6031c8..3678060 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -21,11 +21,11 @@ jobs: with: fetch-depth: 0 ref: Development - - name: Set up JDK 21 - uses: actions/setup-java@v4 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: 'adopt' - java-version: '21' + java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 with: diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index feeb2cf..99f2387 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -20,11 +20,11 @@ jobs: with: fetch-depth: 0 ref: main - - name: Set up JDK 21 - uses: actions/setup-java@v4 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: 'adopt' - java-version: '21' + java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec03a38..b806524 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,11 +28,11 @@ jobs: with: fetch-depth: 0 ref: main - - name: Set up JDK 21 - uses: actions/setup-java@v4 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: 'adopt' - java-version: '21' + java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 with: diff --git a/pom.xml b/pom.xml index b5d92d4..0ab249b 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,13 @@ pom import + + ${quarkus.platform.group-id} + quarkus-langchain4j-bom + ${quarkus.platform.version} + pom + import + @@ -59,6 +66,10 @@ io.quarkus quarkus-rest-jackson + + io.quarkiverse.langchain4j + quarkus-langchain4j-mistral-ai + ${project.artifactId} diff --git a/src/main/java/net/dontcode/prj/GenerateProjectResource.java b/src/main/java/net/dontcode/prj/GenerateProjectResource.java new file mode 100644 index 0000000..ce655f3 --- /dev/null +++ b/src/main/java/net/dontcode/prj/GenerateProjectResource.java @@ -0,0 +1,29 @@ +package net.dontcode.prj; + +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.bson.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/generate") +@ApplicationScoped +public class GenerateProjectResource { + private static Logger log = LoggerFactory.getLogger(GenerateProjectResource.class); + + @Inject + ProjectService projectService; + + @POST + @Path("/") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni generateProject(Document body, @HeaderParam("DbName") String dbName) { + return projectService.insertProject(body, dbName); + } + +} diff --git a/src/main/java/net/dontcode/prj/GenerateProjectService.java b/src/main/java/net/dontcode/prj/GenerateProjectService.java new file mode 100644 index 0000000..811e1f6 --- /dev/null +++ b/src/main/java/net/dontcode/prj/GenerateProjectService.java @@ -0,0 +1,21 @@ +package net.dontcode.prj; + +import dev.langchain4j.service.SystemMessage; +import dev.langchain4j.service.UserMessage; +import io.quarkiverse.langchain4j.RegisterAiService; +import net.dontcode.prj.model.DontCodeProjectModel; + +@RegisterAiService +@SystemMessage(""" + Tu es un createur d'application utilisant le framework dont-code. Ce framework génère une application à partir d'un fichier json. + Basé sur la demande d'un utilisateur, tu fournis le fichier json permettant de générer l'application voulue. + Quand tu reçois une demande, trouve les objets qui devront être manipulés. Ces objets doivent être définis dans la liste entities du json.Ensuite, pour chaque objet, cherche les champs nécessaire, et leur type. + Ces champs sont renseignés dans la liste fields de chaque entity.Un champ peut-être d'un des types prédéfinis suivant: + "number","string","date","time","date-time","currency","country","money-amount","eur-amount","usd-amount","image","link","rating","recurring-task","task-complete" + ou du type d'une autre entité. + Optionnellement, un champ peut être une référence vers une autre entité, en ajoutant "reference" a la description avec les informations nécessaire pour faire le lien entre les deux entités. + """) +public interface GenerateProjectService { + + DontCodeProjectModel generateProjectJson (String msg); +} diff --git a/src/main/java/net/dontcode/prj/ProjectResource.java b/src/main/java/net/dontcode/prj/ProjectResource.java index 414079e..6c7c612 100644 --- a/src/main/java/net/dontcode/prj/ProjectResource.java +++ b/src/main/java/net/dontcode/prj/ProjectResource.java @@ -1,27 +1,18 @@ package net.dontcode.prj; -import com.mongodb.client.model.FindOneAndReplaceOptions; -import com.mongodb.client.model.ReturnDocument; -import io.quarkus.mongodb.MongoClientName; -import io.quarkus.mongodb.reactive.ReactiveMongoClient; -import io.quarkus.mongodb.reactive.ReactiveMongoCollection; -import io.quarkus.mongodb.reactive.ReactiveMongoDatabase; import io.smallrye.common.annotation.Blocking; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; -import org.bson.Document; -import org.bson.types.ObjectId; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.jboss.resteasy.reactive.RestHeader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; +import org.bson.Document; +import org.jboss.resteasy.reactive.RestHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Path("/project") @ApplicationScoped @@ -29,36 +20,14 @@ public class ProjectResource { private static Logger log = LoggerFactory.getLogger(ProjectResource.class); @Inject - @MongoClientName("projects") - ReactiveMongoClient mongoClient; - - @ConfigProperty(name = "projects-database-name") - String projectDbName; + ProjectService projectService; @GET @Path("/") @Produces(MediaType.APPLICATION_JSON) public Multi listProjects (UriInfo info, @RestHeader("DbName") String dbName) { log.debug("Hostname = {}, DbName Header = {}", info.getAbsolutePath(), dbName); -/* Multi ret = Multi.createFrom().emitter(multiEmitter -> { - for (int i=0;i<100000;i++) { - multiEmitter.emit(Document.parse(""" - { - "projectId":"EGFERGG", - "status":"PIZZADAZRFERFERF", - "data":{ - "value":"name" - } - } - """)); - } - multiEmitter.complete(); - });*/ - Multi ret = getProjects(dbName).find().map(document -> { - changeIdToString(document); - return document; - }); - return ret; + return projectService.listProjects(info, dbName); } @GET @@ -66,15 +35,7 @@ public Multi listProjects (UriInfo info, @RestHeader("DbName") String @Produces(MediaType.APPLICATION_JSON) @Blocking public Uni getProject (String projectName, @HeaderParam("DbName") String dbName) { - Uni ret = getProjects(dbName).find(new Document().append("name", projectName)).toUni().map(document -> { - if( document != null) { - changeIdToString(document); - return Response.ok(document).build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - }); - return ret; + return projectService.getProject(projectName, dbName); } @PUT @@ -82,25 +43,7 @@ public Uni getProject (String projectName, @HeaderParam("DbName") Stri @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Uni updateProject (String projectName, @HeaderParam("DbName") String dbName, Document body) { - changeIdToObjectId(body); - Uni ret = getProjects(dbName).findOneAndReplace(new Document().append("_id", body.get("_id")), body, - new FindOneAndReplaceOptions().upsert(false).returnDocument(ReturnDocument.AFTER)).map(document -> { - if( document != null) { - changeIdToString(document); - return Response.ok(document).build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - }); - return ret; - } - - protected void changeIdToObjectId(Document body) { - body.put("_id", new ObjectId(body.getString("_id"))); - } - - protected void changeIdToString(Document body) { - body.put("_id", body.getObjectId("_id").toHexString()); + return projectService.updateProject(projectName, dbName, body); } @DELETE @@ -108,15 +51,7 @@ protected void changeIdToString(Document body) { @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Uni deleteProject (String projectName, @HeaderParam("DbName") String dbName) { - Uni ret = getProjects(dbName).findOneAndDelete(new Document().append("name", projectName)).map(document -> { - if( document != null) { - changeIdToString(document); - return Response.ok(document).build(); - } else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - }); - return ret; + return projectService.deleteProject(projectName, dbName); } @POST @@ -124,31 +59,7 @@ public Uni deleteProject (String projectName, @HeaderParam("DbName") S @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Uni insertProject(Document body, @HeaderParam("DbName") String dbName) { - //System.out.println("Received"+ body); - return getProjects(dbName).insertOne(body).map(result -> { - changeIdToString(body); - return Response.ok(body).build(); - }); + return projectService.insertProject(body, dbName); } - protected ReactiveMongoCollection getProjects(String dbName) { - return getDatabase(dbName).getCollection("projects", Document.class); - } - - /*protected ReactiveMongoCollection getProjects() { - return getDatabase().getCollection("projects", Document.class); - } - protected ReactiveMongoCollection getProjects(Class clazz) { - return getDatabase().getCollection("projects", clazz); - } - - protected ReactiveMongoDatabase getDatabase () { - return mongoClient.getDatabase(projectDbName); - }*/ - - - protected ReactiveMongoDatabase getDatabase (String dbName) { - if( dbName==null) dbName = projectDbName; - return mongoClient.getDatabase(dbName); - } } diff --git a/src/main/java/net/dontcode/prj/ProjectService.java b/src/main/java/net/dontcode/prj/ProjectService.java new file mode 100644 index 0000000..9262c3c --- /dev/null +++ b/src/main/java/net/dontcode/prj/ProjectService.java @@ -0,0 +1,118 @@ +package net.dontcode.prj; + +import com.mongodb.client.model.FindOneAndReplaceOptions; +import com.mongodb.client.model.ReturnDocument; +import io.quarkus.mongodb.MongoClientName; +import io.quarkus.mongodb.reactive.ReactiveMongoClient; +import io.quarkus.mongodb.reactive.ReactiveMongoCollection; +import io.quarkus.mongodb.reactive.ReactiveMongoDatabase; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import org.bson.Document; +import org.bson.types.ObjectId; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class ProjectService { + private static Logger log = LoggerFactory.getLogger(ProjectService.class); + + @Inject + @MongoClientName("projects") + ReactiveMongoClient mongoClient; + + @ConfigProperty(name = "projects-database-name") + String projectDbName; + + public Multi listProjects (UriInfo info, String dbName) { + log.debug("Hostname = {}, DbName Header = {}", info.getAbsolutePath(), dbName); +/* Multi ret = Multi.createFrom().emitter(multiEmitter -> { + for (int i=0;i<100000;i++) { + multiEmitter.emit(Document.parse(""" + { + "projectId":"EGFERGG", + "status":"PIZZADAZRFERFERF", + "data":{ + "value":"name" + } + } + """)); + } + multiEmitter.complete(); + });*/ + Multi ret = getProjects(dbName).find().map(document -> { + changeIdToString(document); + return document; + }); + return ret; + } + + public Uni getProject (String projectName, String dbName) { + Uni ret = getProjects(dbName).find(new Document().append("name", projectName)).toUni().map(document -> { + if( document != null) { + changeIdToString(document); + return Response.ok(document).build(); + } else { + return Response.status(Response.Status.NOT_FOUND).build(); + } + }); + return ret; + } + + public Uni updateProject (String projectName, String dbName, Document body) { + changeIdToObjectId(body); + Uni ret = getProjects(dbName).findOneAndReplace(new Document().append("_id", body.get("_id")), body, + new FindOneAndReplaceOptions().upsert(false).returnDocument(ReturnDocument.AFTER)).map(document -> { + if( document != null) { + changeIdToString(document); + return Response.ok(document).build(); + } else { + return Response.status(Response.Status.NOT_FOUND).build(); + } + }); + return ret; + } + + protected void changeIdToObjectId(Document body) { + body.put("_id", new ObjectId(body.getString("_id"))); + } + + protected void changeIdToString(Document body) { + body.put("_id", body.getObjectId("_id").toHexString()); + } + + public Uni deleteProject (String projectName, String dbName) { + Uni ret = getProjects(dbName).findOneAndDelete(new Document().append("name", projectName)).map(document -> { + if( document != null) { + changeIdToString(document); + return Response.ok(document).build(); + } else { + return Response.status(Response.Status.NOT_FOUND).build(); + } + }); + return ret; + } + + public Uni insertProject(Document body,String dbName) { + //System.out.println("Received"+ body); + return getProjects(dbName).insertOne(body).map(result -> { + changeIdToString(body); + return Response.ok(body).build(); + }); + } + + protected ReactiveMongoCollection getProjects(String dbName) { + return getDatabase(dbName).getCollection("projects", Document.class); + } + + protected ReactiveMongoDatabase getDatabase (String dbName) { + if( dbName==null) dbName = projectDbName; + return mongoClient.getDatabase(dbName); + } + +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java new file mode 100644 index 0000000..b281492 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java @@ -0,0 +1,5 @@ +package net.dontcode.prj.model; + +public record DontCodeProjectContent (DontCodeProjectCreation creation){ + +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java new file mode 100644 index 0000000..880c257 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java @@ -0,0 +1,4 @@ +package net.dontcode.prj.model; + +public record DontCodeProjectCreation(String name, DontCodeProjectCreationType type, DontCodeProjectEntities[] entities) { +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java new file mode 100644 index 0000000..a1727c4 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java @@ -0,0 +1,18 @@ +package net.dontcode.prj.model; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum DontCodeProjectCreationType { + application("application"); + + private String value; + + DontCodeProjectCreationType(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java new file mode 100644 index 0000000..ad4dae9 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java @@ -0,0 +1,4 @@ +package net.dontcode.prj.model; + +public record DontCodeProjectEntities(String name, DontCodeProjectField[] fields) { +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java new file mode 100644 index 0000000..8abf768 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java @@ -0,0 +1,4 @@ +package net.dontcode.prj.model; + +public record DontCodeProjectField(String name, String type) { +} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java new file mode 100644 index 0000000..e1db346 --- /dev/null +++ b/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java @@ -0,0 +1,9 @@ +package net.dontcode.prj.model; + +public record DontCodeProjectModel ( + String name, + DontCodeProjectContent content +) { + +} + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 247cd1c..c1b1267 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -20,5 +20,9 @@ quarkus.http.cors.origins=/.*/ quarkus.package.jar.type=uber-jar + +quarkus.langchain4j.mistralai.api-key=Ea1iTby8zacARUmgmLVSLVVjcIRHGmre +quarkus.langchain4j.mistralai.chat-model.model-name=codestral-latest + quarkus.log.level=INFO quarkus.log.category."net.dontcode.prj".level=DEBUG diff --git a/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java new file mode 100644 index 0000000..bca2282 --- /dev/null +++ b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java @@ -0,0 +1,21 @@ +package net.dontcode.prj; + +import io.quarkus.test.junit.QuarkusTest; +import jakarta.inject.Inject; +import net.dontcode.prj.model.DontCodeProjectModel; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@QuarkusTest +public class GenerateProjectServiceTest { + + @Inject + GenerateProjectService service; + + @Test + public void testSimpleApplication () { + //DontCodeProjectModel response=service.generateProjectJson("Please create a cooking recipe application"); + //Assertions.assertNotNull(response); + } + +} From e173a9c7b655c6f2818a508c183affc86fe100a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Mon, 23 Feb 2026 18:23:54 +0100 Subject: [PATCH 03/11] fix: build with temurin --- .github/workflows/dev-build.yml | 2 +- .github/workflows/main-build.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 3678060..8988d66 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -24,7 +24,7 @@ jobs: - name: Set up JDK 25 uses: actions/setup-java@v5 with: - distribution: 'adopt' + distribution: 'temurin' java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index 99f2387..ccc3bd5 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -23,7 +23,7 @@ jobs: - name: Set up JDK 25 uses: actions/setup-java@v5 with: - distribution: 'adopt' + distribution: 'temurin' java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b806524..5c75e65 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: - name: Set up JDK 25 uses: actions/setup-java@v5 with: - distribution: 'adopt' + distribution: 'temurin' java-version: '25' - name: Cache Maven repository uses: actions/cache@v4 From 6be23a4a301151a1609c5aaddcb175e57fae3087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Wed, 25 Feb 2026 21:49:31 +0100 Subject: [PATCH 04/11] fix: Removed Mistral api key --- src/main/resources/application.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c1b1267..6a75c91 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -21,7 +21,6 @@ quarkus.http.cors.origins=/.*/ quarkus.package.jar.type=uber-jar -quarkus.langchain4j.mistralai.api-key=Ea1iTby8zacARUmgmLVSLVVjcIRHGmre quarkus.langchain4j.mistralai.chat-model.model-name=codestral-latest quarkus.log.level=INFO From 812364b9edc028fbf9f2f99602eeccc0a33c58e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Wed, 25 Feb 2026 22:17:16 +0100 Subject: [PATCH 05/11] fix: secret mistral key --- .github/workflows/dev-build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 8988d66..8454308 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -38,3 +38,5 @@ jobs: value: "mongodb://localhost:27017" - name: Build with Maven run: mvn -B package --file pom.xml + env: + QUARKUS_LANGCHAIN4J_MISTRALAI_API_KEY: ${{ secrets.QUARKUS_LANGCHAIN4J_MISTRALAI_API_KEY }} \ No newline at end of file From 13fcfd2e3add8e459d17baf3c4bd4034253ed904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Wed, 25 Feb 2026 22:18:42 +0100 Subject: [PATCH 06/11] fix: secret mistral key --- src/test/resources/application.properties | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/test/resources/application.properties diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..4db837a --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1 @@ +quarkus.langchain4j.mistralai.api-key=DUMMY_KEY \ No newline at end of file From 74471edcab3d40262789dfb86af2d9c155c79036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Wed, 25 Feb 2026 23:02:16 +0100 Subject: [PATCH 07/11] feat: Move project model to core --- pom.xml | 13 ++++++++++++- .../dontcode/prj/GenerateProjectService.java | 3 +-- .../prj/model/DontCodeProjectContent.java | 5 ----- .../prj/model/DontCodeProjectCreation.java | 4 ---- .../prj/model/DontCodeProjectCreationType.java | 18 ------------------ .../prj/model/DontCodeProjectEntities.java | 4 ---- .../prj/model/DontCodeProjectField.java | 4 ---- .../prj/model/DontCodeProjectModel.java | 9 --------- .../prj/GenerateProjectServiceTest.java | 7 ++++--- 9 files changed, 17 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectField.java delete mode 100644 src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java diff --git a/pom.xml b/pom.xml index 0ab249b..18f0b07 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ 3.31.4 true 3.5.4 - 0.3.1 + 0.4.1 @@ -70,6 +70,17 @@ io.quarkiverse.langchain4j quarkus-langchain4j-mistral-ai + + net.dontcode.common + quarkus-mongo + ${dontcode-common.version} + + + net.dontcode.common + quarkus-mongo-test + ${dontcode-common.version} + test + ${project.artifactId} diff --git a/src/main/java/net/dontcode/prj/GenerateProjectService.java b/src/main/java/net/dontcode/prj/GenerateProjectService.java index 811e1f6..f31d887 100644 --- a/src/main/java/net/dontcode/prj/GenerateProjectService.java +++ b/src/main/java/net/dontcode/prj/GenerateProjectService.java @@ -1,9 +1,8 @@ package net.dontcode.prj; import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; import io.quarkiverse.langchain4j.RegisterAiService; -import net.dontcode.prj.model.DontCodeProjectModel; +import net.dontcode.core.project.DontCodeProjectModel; @RegisterAiService @SystemMessage(""" diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java deleted file mode 100644 index b281492..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectContent.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.dontcode.prj.model; - -public record DontCodeProjectContent (DontCodeProjectCreation creation){ - -} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java deleted file mode 100644 index 880c257..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreation.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.dontcode.prj.model; - -public record DontCodeProjectCreation(String name, DontCodeProjectCreationType type, DontCodeProjectEntities[] entities) { -} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java deleted file mode 100644 index a1727c4..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectCreationType.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.dontcode.prj.model; - -import com.fasterxml.jackson.annotation.JsonValue; - -public enum DontCodeProjectCreationType { - application("application"); - - private String value; - - DontCodeProjectCreationType(String value) { - this.value = value; - } - - @JsonValue - public String getValue() { - return value; - } -} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java deleted file mode 100644 index ad4dae9..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectEntities.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.dontcode.prj.model; - -public record DontCodeProjectEntities(String name, DontCodeProjectField[] fields) { -} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java deleted file mode 100644 index 8abf768..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectField.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.dontcode.prj.model; - -public record DontCodeProjectField(String name, String type) { -} diff --git a/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java b/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java deleted file mode 100644 index e1db346..0000000 --- a/src/main/java/net/dontcode/prj/model/DontCodeProjectModel.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.dontcode.prj.model; - -public record DontCodeProjectModel ( - String name, - DontCodeProjectContent content -) { - -} - diff --git a/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java index bca2282..ef0833a 100644 --- a/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java +++ b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java @@ -2,7 +2,7 @@ import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; -import net.dontcode.prj.model.DontCodeProjectModel; +import net.dontcode.core.project.DontCodeProjectModel; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -14,8 +14,9 @@ public class GenerateProjectServiceTest { @Test public void testSimpleApplication () { - //DontCodeProjectModel response=service.generateProjectJson("Please create a cooking recipe application"); - //Assertions.assertNotNull(response); + DontCodeProjectModel response=service.generateProjectJson("Please create a cooking recipe application"); + Assertions.assertNotNull(response); + Assertions.assertTrue(response.content().creation().entities().length > 0); } } From 27a955d9e43531dd79480b75d96e9db1a9804b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Sat, 28 Feb 2026 10:42:43 +0100 Subject: [PATCH 08/11] fix: junit5 is now junit --- pom.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 18f0b07..81a1a81 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,12 @@ io.quarkus - quarkus-junit5 + quarkus-junit + test + + + io.quarkus + quarkus-junit-mockito test @@ -54,6 +59,10 @@ io.quarkus quarkus-mutiny + + io.quarkus + quarkus-websockets-next + io.quarkus quarkus-mongodb-client From e82a4f77574aba3d67a1e787963f1e046ec96940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Sat, 28 Feb 2026 10:44:03 +0100 Subject: [PATCH 09/11] feat: Project Generator with Mistral --- .../dontcode/prj/GenerateProjectResource.java | 50 ++++++--- .../dontcode/prj/GenerateProjectService.java | 2 + .../prj/GenerateProjectResourceTest.java | 105 ++++++++++++++++++ .../prj/GenerateProjectServiceTest.java | 7 +- 4 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 src/test/java/net/dontcode/prj/GenerateProjectResourceTest.java diff --git a/src/main/java/net/dontcode/prj/GenerateProjectResource.java b/src/main/java/net/dontcode/prj/GenerateProjectResource.java index ce655f3..f9fb5ce 100644 --- a/src/main/java/net/dontcode/prj/GenerateProjectResource.java +++ b/src/main/java/net/dontcode/prj/GenerateProjectResource.java @@ -1,29 +1,45 @@ package net.dontcode.prj; -import io.smallrye.mutiny.Uni; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.bson.Document; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.quarkus.websockets.next.OnOpen; +import io.quarkus.websockets.next.OnTextMessage; +import io.quarkus.websockets.next.WebSocket; +import jakarta.websocket.EncodeException; +import net.dontcode.common.websocket.MessageEncoderDecoder; +import net.dontcode.core.project.DontCodeProjectModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Path("/generate") -@ApplicationScoped +@WebSocket(path = "/generate") public class GenerateProjectResource { private static Logger log = LoggerFactory.getLogger(GenerateProjectResource.class); - @Inject - ProjectService projectService; + private final GenerateProjectService service; - @POST - @Path("/") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public Uni generateProject(Document body, @HeaderParam("DbName") String dbName) { - return projectService.insertProject(body, dbName); + public GenerateProjectResource(GenerateProjectService service) { + this.service = service; } + + @OnOpen + public String onOpen() { + return "Hello, please describe the application you want to generate."; + } + + @OnTextMessage() + public String onMessage(String message) { + return projectToString(service.generateProjectJson(message)); + } + + protected String projectToString (DontCodeProjectModel prj) { + ObjectMapper mapper = new ObjectMapper(); + String json = ""; + try { + json = mapper.writeValueAsString(prj); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error decoding project", e); + } + return json; + } } diff --git a/src/main/java/net/dontcode/prj/GenerateProjectService.java b/src/main/java/net/dontcode/prj/GenerateProjectService.java index f31d887..090044a 100644 --- a/src/main/java/net/dontcode/prj/GenerateProjectService.java +++ b/src/main/java/net/dontcode/prj/GenerateProjectService.java @@ -2,6 +2,7 @@ import dev.langchain4j.service.SystemMessage; import io.quarkiverse.langchain4j.RegisterAiService; +import jakarta.enterprise.context.SessionScoped; import net.dontcode.core.project.DontCodeProjectModel; @RegisterAiService @@ -14,6 +15,7 @@ ou du type d'une autre entité. Optionnellement, un champ peut être une référence vers une autre entité, en ajoutant "reference" a la description avec les informations nécessaire pour faire le lien entre les deux entités. """) +@SessionScoped public interface GenerateProjectService { DontCodeProjectModel generateProjectJson (String msg); diff --git a/src/test/java/net/dontcode/prj/GenerateProjectResourceTest.java b/src/test/java/net/dontcode/prj/GenerateProjectResourceTest.java new file mode 100644 index 0000000..0f7c883 --- /dev/null +++ b/src/test/java/net/dontcode/prj/GenerateProjectResourceTest.java @@ -0,0 +1,105 @@ +package net.dontcode.prj; + +import io.quarkus.test.InjectMock; +import io.quarkus.test.common.http.TestHTTPResource; +import io.quarkus.test.junit.QuarkusTest; +import jakarta.websocket.*; +import net.dontcode.core.Message; +import net.dontcode.core.project.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.ExecutionException; + +import static org.mockito.ArgumentMatchers.anyString; + +@QuarkusTest +public class GenerateProjectResourceTest { + + @TestHTTPResource("/generate") + URI generateUri; + + @InjectMock + GenerateProjectService serviceMock; + + @Test + public void testGeneration() throws DeploymentException, IOException, InterruptedException { + DontCodeProjectEntities[] entities = new DontCodeProjectEntities[]{}; + Mockito.when(serviceMock.generateProjectJson(anyString())).thenReturn( + new DontCodeProjectModel("Test", + new DontCodeProjectContent( + new DontCodeProjectCreation("Test App", DontCodeProjectCreationType.application, entities)))); + ClientTestSession.opened=false; + try (Session session = ContainerProvider.getWebSocketContainer().connectToServer(ClientTestSession.class, generateUri)) { + // Wait the data to be saved in the database +/** for (int i = 0; i < 10; i++) { + Thread.sleep(50); + if( ClientTestSession.opened) { + break; + } + } + Assertions.assertTrue(ClientTestSession.opened, "Session was not opened");**/ + ClientTestSession.response=null; + + session.getAsyncRemote().sendText("Generate a new Test Application").get(); + + // Wait for the answer + for (int i = 0; i < 10; i++) { + Thread.sleep(50); + if( ClientTestSession.response!=null) { + break; + } + } + + Assertions.assertNotNull(ClientTestSession.response); + ClientTestSession.response=null; + session.getAsyncRemote().sendText("The application should be named Super Test").get(); + + // Wait for the answer + for (int i = 0; i < 10; i++) { + Thread.sleep(50); + if( ClientTestSession.response!=null) { + break; + } + } + + Assertions.assertNotNull(ClientTestSession.response); + Mockito.verify(serviceMock, Mockito.times(2)).generateProjectJson(anyString()); + + } catch (ExecutionException e) { + System.err.println(e.getCause().getMessage()); + throw new RuntimeException(e); + } + } + + @ClientEndpoint + public static class ClientTestSession { + + public static boolean opened=false; + public static String response=null; + + public ClientTestSession () { + } + + @OnOpen + public void open(Session session) { + opened=true; + } + + @OnMessage + void message(String msg) throws DecodeException { + response=msg; + } + + @OnError + void error (Throwable error) { + System.err.println("Error "+ error.getMessage()); + } + + } + + +} diff --git a/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java index ef0833a..7dc661e 100644 --- a/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java +++ b/src/test/java/net/dontcode/prj/GenerateProjectServiceTest.java @@ -14,9 +14,10 @@ public class GenerateProjectServiceTest { @Test public void testSimpleApplication () { - DontCodeProjectModel response=service.generateProjectJson("Please create a cooking recipe application"); - Assertions.assertNotNull(response); - Assertions.assertTrue(response.content().creation().entities().length > 0); + + //DontCodeProjectModel response=service.generateProjectJson("Please create a cooking recipe application"); + //Assertions.assertNotNull(response); + //Assertions.assertTrue(response.content().creation().entities().length > 0); } } From c660082a1579e9831b3002332844bf843ed64a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Sat, 28 Feb 2026 11:29:36 +0100 Subject: [PATCH 10/11] fix: add support for snapshots --- pom.xml | 2 +- .../net/dontcode/prj/PrjTestResource.java | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 81a1a81..3ba4c6c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ 3.31.4 true 3.5.4 - 0.4.1 + 0.4.1-SNAPSHOT diff --git a/src/main/java/net/dontcode/prj/PrjTestResource.java b/src/main/java/net/dontcode/prj/PrjTestResource.java index 67445ef..75111f2 100644 --- a/src/main/java/net/dontcode/prj/PrjTestResource.java +++ b/src/main/java/net/dontcode/prj/PrjTestResource.java @@ -1,6 +1,11 @@ package net.dontcode.prj; +import io.quarkus.arc.Arc; +import io.quarkus.arc.ManagedContext; import io.smallrye.mutiny.Uni; +import jakarta.enterprise.context.SessionScoped; +import jakarta.inject.Inject; +import net.dontcode.core.project.DontCodeProjectModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,6 +20,9 @@ public class PrjTestResource { private static Logger log = LoggerFactory.getLogger(PrjTestResource.class); +// @Inject +// GenerateProjectService generateProjectService; + @POST @Consumes(MediaType.APPLICATION_JSON) public Response testAsIde(String update) { @@ -46,4 +54,25 @@ public Uni cookie(@CookieParam("Test") String testCookie) { new NewCookie(new Cookie("Test", Integer.toString(nextValue), "/", "localhost"), null, 60*60, false)).build()); } + +/* @GET + @Path("/generator") + @Produces(MediaType.APPLICATION_JSON) + public Uni generator(@QueryParam("message") String message) { + // We create a session context just to call the session scoped service + ManagedContext sessionContext = null; + try { + sessionContext = Arc.requireContainer().sessionContext(); + if (!sessionContext.isActive()) { + sessionContext.activate(); + } + DontCodeProjectModel response=generateProjectService.generateProjectJson(message); + return Uni.createFrom().item(Response.ok().entity(response).build()); + + } finally { + if (sessionContext != null) { + sessionContext.terminate(); + } + } + }*/ } From 2e7466535652f4232500b0aab64d1ac0636df2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Collin?= Date: Sat, 28 Feb 2026 11:35:16 +0100 Subject: [PATCH 11/11] fix: add support for snapshots --- pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pom.xml b/pom.xml index 3ba4c6c..8e9280d 100644 --- a/pom.xml +++ b/pom.xml @@ -157,4 +157,17 @@ + + + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + +