From e48d5e0965997c5f4fc0df8d955a887de24b0b18 Mon Sep 17 00:00:00 2001 From: Tim Chamberlain Date: Tue, 27 May 2025 17:05:37 -0500 Subject: [PATCH 01/18] added labels as a param when searching for PVSs --- .../qqq/backend/javalin/QJavalinImplementation.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java index 5ed116b1..a127b9f7 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java @@ -1925,6 +1925,7 @@ public class QJavalinImplementation { String searchTerm = context.queryParam("searchTerm"); String ids = context.queryParam("ids"); + String labels = context.queryParam("labels"); SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput(); setupSession(context, input); @@ -1937,6 +1938,11 @@ public class QJavalinImplementation List idList = new ArrayList<>(Arrays.asList(ids.split(","))); input.setIdList(idList); } + else if(StringUtils.hasContent(labels)) + { + List labelList = new ArrayList<>(Arrays.asList(labels.split(","))); + input.setLabelList(labelList); + } SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input); From 707400a8b2c26858cdb784ecd8c14e1113d06322 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sat, 14 Jun 2025 16:07:51 -0500 Subject: [PATCH 02/18] Added support for loading static files from the filesystem as as from jars (based on a system property) --- qqq-middleware-javalin/pom.xml | 12 ++++ .../SimpleFileSystemDirectoryRouter.java | 68 ++++++++++++++----- ...ApplicationJavalinServerClasspathTest.java | 61 +++++++++++++++++ .../QApplicationJavalinServerTest.java | 40 ++++++++--- 4 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java diff --git a/qqq-middleware-javalin/pom.xml b/qqq-middleware-javalin/pom.xml index dc94f1ae..43ff6aef 100644 --- a/qqq-middleware-javalin/pom.xml +++ b/qqq-middleware-javalin/pom.xml @@ -122,6 +122,18 @@ src/main/java + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + + ${project.basedir}/src/test/resources/static-site.jar + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java index c6504be1..89e424e2 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java @@ -49,16 +49,34 @@ import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; public class SimpleFileSystemDirectoryRouter implements QJavalinRouteProviderInterface { private static final QLogger LOG = QLogger.getLogger(SimpleFileSystemDirectoryRouter.class); + public static boolean loadStaticFilesFromJar = false; + + static + { + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // read the property to see if we should load static files from the jar file or from the file system // + // Javan only supports loading via one method per path, so its a choice of one or the other... // + /////////////////////////////////////////////////////////////////////////////////////////////////////// + try + { + String propertyName = "qqq.javalin.enableStaticFilesFromJar"; // TODO: make a more general way to handle properties like this system-wide via a central config class + String propertyValue = System.getProperty(propertyName, ""); + if(propertyValue.equals("true")) + { + loadStaticFilesFromJar = true; + } + } + catch(Exception e) + { + e.printStackTrace(); + } + } private final String hostedPath; private final String fileSystemPath; - private QCodeReference routeAuthenticator; - private QInstance qInstance; - - /******************************************************************************* ** Constructor ** @@ -98,25 +116,41 @@ public class SimpleFileSystemDirectoryRouter implements QJavalinRouteProviderInt ***************************************************************************/ private void handleJavalinStaticFileConfig(StaticFileConfig staticFileConfig) { - URL resource = getClass().getClassLoader().getResource(fileSystemPath); - if(resource == null) - { - String message = "Could not find file system path: " + fileSystemPath; - if(fileSystemPath.startsWith("/") && getClass().getClassLoader().getResource(fileSystemPath.replaceFirst("^/+", "")) != null) - { - message += ". For non-absolute paths, do not prefix with a leading slash."; - } - throw new RuntimeException(message); - } if(!hostedPath.startsWith("/")) { LOG.warn("hostedPath [" + hostedPath + "] should probably start with a leading slash..."); } - staticFileConfig.directory = resource.getFile(); - staticFileConfig.hostedPath = hostedPath; - staticFileConfig.location = Location.EXTERNAL; + /// ///////////////////////////////////////////////////////////////////////////////////// + // Handle loading static files from the jar OR the filesystem based on system property // + /// ///////////////////////////////////////////////////////////////////////////////////// + if(SimpleFileSystemDirectoryRouter.loadStaticFilesFromJar) + { + staticFileConfig.directory = fileSystemPath; + staticFileConfig.hostedPath = hostedPath; + staticFileConfig.location = Location.CLASSPATH; + LOG.info("Static File Config : hostedPath [" + hostedPath + "] : directory [" + staticFileConfig.directory + "] : location [CLASSPATH]"); + } + else + { + URL resource = getClass().getClassLoader().getResource(fileSystemPath); + if(resource == null) + { + String message = "Could not find file system path: " + fileSystemPath; + if(fileSystemPath.startsWith("/") && getClass().getClassLoader().getResource(fileSystemPath.replaceFirst("^/+", "")) != null) + { + message += ". For non-absolute paths, do not prefix with a leading slash."; + } + throw new RuntimeException(message); + } + + staticFileConfig.directory = resource.getFile(); + staticFileConfig.hostedPath = hostedPath; + staticFileConfig.location = Location.EXTERNAL; + LOG.info("Static File Config : hostedPath [" + hostedPath + "] : directory [" + staticFileConfig.directory + "] : location [EXTERNAL]"); + } + } diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java new file mode 100644 index 00000000..f75b99d1 --- /dev/null +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java @@ -0,0 +1,61 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2024. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.middleware.javalin; + + +import com.kingsrook.qqq.middleware.javalin.routeproviders.SimpleFileSystemDirectoryRouter; +import kong.unirest.HttpResponse; +import kong.unirest.Unirest; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + + +/******************************************************************************* + ** Unit test for QApplicationJavalinServer with static files served from classpath + *******************************************************************************/ +class QApplicationJavalinServerClasspathTest +{ + private static final int PORT = 6265; + private QApplicationJavalinServer javalinServer; + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testStaticRouterFilesFromClasspath() throws Exception + { + System.setProperty("qqq.javalin.enableStaticFilesFromJar", "true"); + + javalinServer = new QApplicationJavalinServer(new QApplicationJavalinServerTest.TestApplication()) + .withServeFrontendMaterialDashboard(false) + .withPort(PORT) + .withAdditionalRouteProvider(new SimpleFileSystemDirectoryRouter("/statically-served-from-jar", "static-site-from-jar/")); + + javalinServer.start(); + + Unirest.config().setDefaultResponseEncoding("UTF-8"); + HttpResponse response = Unirest.get("http://localhost:" + PORT + "/statically-served-from-jar/foo-in-jar.html").asString(); + assertEquals("Foo in a Jar!\n", response.getBody()); + } +} \ No newline at end of file diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java index a6bf4085..1d3c8e72 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java @@ -52,6 +52,16 @@ class QApplicationJavalinServerTest + /*************************************************************************** + ** + ***************************************************************************/ + private static AbstractQQQApplication getQqqApplication() + { + return new TestApplication(); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -196,6 +206,26 @@ class QApplicationJavalinServerTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testStaticRouterFilesFromExternal() throws Exception + { + System.setProperty("qqq.javalin.enableStaticFilesFromJar", "false"); + + javalinServer = new QApplicationJavalinServer(getQqqApplication()) + .withServeFrontendMaterialDashboard(false) + .withPort(PORT); + javalinServer.start(); + + Unirest.config().setDefaultResponseEncoding("UTF-8"); + HttpResponse response = Unirest.get("http://localhost:" + PORT + "/statically-served/foo.html").asString(); + assertEquals("Foo? Bar!", response.getBody()); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -296,16 +326,6 @@ class QApplicationJavalinServerTest - /*************************************************************************** - ** - ***************************************************************************/ - private static AbstractQQQApplication getQqqApplication() - { - return new TestApplication(); - } - - - /*************************************************************************** ** ***************************************************************************/ From eab87b9d807f0693a534e259367556ea871e0162 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 15 Jun 2025 10:01:11 -0500 Subject: [PATCH 03/18] Added missing jar for unit test --- .../src/test/resources/static-site.jar | Bin 0 -> 621 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 qqq-middleware-javalin/src/test/resources/static-site.jar diff --git a/qqq-middleware-javalin/src/test/resources/static-site.jar b/qqq-middleware-javalin/src/test/resources/static-site.jar new file mode 100644 index 0000000000000000000000000000000000000000..f5e203e4f9f831591b5b63cd7af1eb4552e8f677 GIT binary patch literal 621 zcmWIWW@h1HVBlb2xH#c#6ay0AWME~0p0C?y-!rFuymj?1@_OrPojY@WbCAIm;|EWR^t^m^Jbf>guG$i0V06v+ zf^pD=0(~!^Gn}783(lQCt9$me&dMuKo<4fY1hkZ$!=cRQoior1M<50{0^;67XzmpS z$`+R-mSiUD7H5{E>ZTRt=jvu97U?70eHcxP3N9^a`T4q;c_7_-86~+n#i!4QpEwij z5%R%HC+G>pQCo|*#|i-T^MM`3$i&5fI~ajVkN`ZSAc4xrB*K6QR%E||f)xR@flRno zq(BbvMp%w5Ob{k)05Wle5W*3lFhcelD2x!`F_4MX2(%Cj@MdKL>0$vwAw~uUS0H9! F00191kAVOH literal 0 HcmV?d00001 From d13fc4a8638ffe5e226ae285fbc13240af605ead Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 15 Jun 2025 10:35:18 -0500 Subject: [PATCH 04/18] Removed - Merged back into overall unit tests --- ...ApplicationJavalinServerClasspathTest.java | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java deleted file mode 100644 index f75b99d1..00000000 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerClasspathTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * QQQ - Low-code Application Framework for Engineers. - * Copyright (C) 2021-2024. Kingsrook, LLC - * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States - * contact@kingsrook.com - * https://github.com/Kingsrook/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.kingsrook.qqq.middleware.javalin; - - -import com.kingsrook.qqq.middleware.javalin.routeproviders.SimpleFileSystemDirectoryRouter; -import kong.unirest.HttpResponse; -import kong.unirest.Unirest; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - - -/******************************************************************************* - ** Unit test for QApplicationJavalinServer with static files served from classpath - *******************************************************************************/ -class QApplicationJavalinServerClasspathTest -{ - private static final int PORT = 6265; - private QApplicationJavalinServer javalinServer; - - - - /******************************************************************************* - ** - *******************************************************************************/ - @Test - void testStaticRouterFilesFromClasspath() throws Exception - { - System.setProperty("qqq.javalin.enableStaticFilesFromJar", "true"); - - javalinServer = new QApplicationJavalinServer(new QApplicationJavalinServerTest.TestApplication()) - .withServeFrontendMaterialDashboard(false) - .withPort(PORT) - .withAdditionalRouteProvider(new SimpleFileSystemDirectoryRouter("/statically-served-from-jar", "static-site-from-jar/")); - - javalinServer.start(); - - Unirest.config().setDefaultResponseEncoding("UTF-8"); - HttpResponse response = Unirest.get("http://localhost:" + PORT + "/statically-served-from-jar/foo-in-jar.html").asString(); - assertEquals("Foo in a Jar!\n", response.getBody()); - } -} \ No newline at end of file From f6859d040f36a3ec915f22c86cc26473026725d7 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 15 Jun 2025 10:36:11 -0500 Subject: [PATCH 05/18] Refactored to use the constructor instead of the class/static method to load properties - makes unit test runtime cleaning --- .../SimpleFileSystemDirectoryRouter.java | 30 +++++++++---------- .../QApplicationJavalinServerTest.java | 24 +++++++++++++++ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java index 89e424e2..e30c94a9 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/routeproviders/SimpleFileSystemDirectoryRouter.java @@ -51,8 +51,21 @@ public class SimpleFileSystemDirectoryRouter implements QJavalinRouteProviderInt private static final QLogger LOG = QLogger.getLogger(SimpleFileSystemDirectoryRouter.class); public static boolean loadStaticFilesFromJar = false; - static + + private final String hostedPath; + private final String fileSystemPath; + private QCodeReference routeAuthenticator; + private QInstance qInstance; + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public SimpleFileSystemDirectoryRouter(String hostedPath, String fileSystemPath) { + this.hostedPath = hostedPath; + this.fileSystemPath = fileSystemPath; + /////////////////////////////////////////////////////////////////////////////////////////////////////// // read the property to see if we should load static files from the jar file or from the file system // // Javan only supports loading via one method per path, so its a choice of one or the other... // @@ -72,21 +85,6 @@ public class SimpleFileSystemDirectoryRouter implements QJavalinRouteProviderInt } } - private final String hostedPath; - private final String fileSystemPath; - private QCodeReference routeAuthenticator; - private QInstance qInstance; - - /******************************************************************************* - ** Constructor - ** - *******************************************************************************/ - public SimpleFileSystemDirectoryRouter(String hostedPath, String fileSystemPath) - { - this.hostedPath = hostedPath; - this.fileSystemPath = fileSystemPath; - } - /*************************************************************************** diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java index 1d3c8e72..a9524022 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/middleware/javalin/QApplicationJavalinServerTest.java @@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.instances.AbstractQQQApplication; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.javalin.TestUtils; +import com.kingsrook.qqq.middleware.javalin.routeproviders.SimpleFileSystemDirectoryRouter; import com.kingsrook.qqq.middleware.javalin.specs.v1.MiddlewareVersionV1; import io.javalin.http.HttpStatus; import kong.unirest.HttpResponse; @@ -70,6 +71,7 @@ class QApplicationJavalinServerTest { javalinServer.stop(); TestApplication.callCount = 0; + System.clearProperty("qqq.javalin.enableStaticFilesFromJar"); } @@ -226,6 +228,28 @@ class QApplicationJavalinServerTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testStaticRouterFilesFromClasspath() throws Exception + { + System.setProperty("qqq.javalin.enableStaticFilesFromJar", "true"); + + javalinServer = new QApplicationJavalinServer(new QApplicationJavalinServerTest.TestApplication()) + .withServeFrontendMaterialDashboard(false) + .withPort(PORT) + .withAdditionalRouteProvider(new SimpleFileSystemDirectoryRouter("/statically-served-from-jar", "static-site-from-jar/")); + + javalinServer.start(); + + Unirest.config().setDefaultResponseEncoding("UTF-8"); + HttpResponse response = Unirest.get("http://localhost:" + PORT + "/statically-served-from-jar/foo-in-jar.html").asString(); + assertEquals("Foo in a Jar!\n", response.getBody()); + } + + + /******************************************************************************* ** *******************************************************************************/ From eca359cf6938ef8e0bd0972d137deb2fa0df6789 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 2 Jul 2025 12:32:37 -0500 Subject: [PATCH 06/18] Try not manually installing java 17, and parse jacoco outputs more directly (per Cursor) --- .circleci/config.yml | 20 ++++++-------------- pom.xml | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7433d19e..952363a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,21 +17,13 @@ commands: path: << parameters.module >>/target/site/jacoco/jacoco-resources when: always - install_java17: + check_java_version: steps: - run: - name: Install Java 17 + name: Check Java Version command: | - sudo apt-get update - sudo apt install -y openjdk-17-jdk - sudo rm /etc/alternatives/java - sudo ln -s /usr/lib/jvm/java-17-openjdk-amd64/bin/java /etc/alternatives/java - - run: - ## used by jacoco uncovered class reporting in pom.xml - name: Install html2text - command: | - sudo apt-get update - sudo apt-get install -y html2text + java -version + echo "Java version check completed" mvn_verify: steps: @@ -139,7 +131,7 @@ jobs: executor: localstack/default steps: ## - localstack/startup - - install_java17 + - check_java_version - mvn_verify - check_middleware_api_versions @@ -147,7 +139,7 @@ jobs: executor: localstack/default steps: ## - localstack/startup - - install_java17 + - check_java_version - mvn_verify - check_middleware_api_versions - mvn_jar_deploy diff --git a/pom.xml b/pom.xml index a8d48433..a09cd325 100644 --- a/pom.xml +++ b/pom.xml @@ -249,25 +249,25 @@ echo " See also target/site/jacoco/index.html" echo " and https://www.jacoco.org/jacoco/trunk/doc/counters.html" echo "------------------------------------------------------------" -if which xpath > /dev/null 2>&1; then +# Parse Jacoco HTML coverage summary using grep and sed +if [ -f target/site/jacoco/index.html ]; then echo "Element\nInstructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$.headers - xpath -n -q -e '/html/body/table/tfoot/tr[1]/td/text()' target/site/jacoco/index.html > /tmp/$$.values + # Extract values from the footer row of the coverage table + grep -A 12 '' target/site/jacoco/index.html | grep '' | sed 's/\([^<]*\)<\/td>/\1/' | tr '\n' '\t' | sed 's/\t$/\n/' > /tmp/$$.values paste /tmp/$$.headers /tmp/$$.values | tail +2 | awk -v FS='\t' '{printf("%-20s %s\n",$1,$2)}' rm /tmp/$$.headers /tmp/$$.values else - echo "xpath is not installed. Jacoco coverage summary will not be produced here..."; + echo "Jacoco coverage summary could not be parsed..."; fi -if which html2text > /dev/null 2>&1; then - echo "Untested classes, per Jacoco:" - echo "-----------------------------" - for i in target/site/jacoco/*/index.html; do - html2text -width 500 -nobs $i | sed '1,/^Total/d;' | grep -v Created | sed 's/ \+/ /g' | sed 's/ [[:digit:]]$//' | grep -v 0$ | cut -d' ' -f1; - done; - echo -else - echo "html2text is not installed. Untested classes from Jacoco will not be printed here..."; -fi +echo "Untested classes, per Jacoco:" +echo "-----------------------------" +# Parse Jacoco XML reports directly to find classes with 0% coverage +find target/site/jacoco -name "jacoco.xml" -exec grep -l ' From 779dfd25d095a502dd76041b6392627179f008a6 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 2 Jul 2025 13:03:06 -0500 Subject: [PATCH 07/18] Cursor rewrite of store-artifacts/jacoco-site --- .circleci/config.yml | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 952363a8..c2e70028 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,18 +5,6 @@ orbs: browser-tools: circleci/browser-tools@1.4.7 commands: - store_jacoco_site: - parameters: - module: - type: string - steps: - - store_artifacts: - path: << parameters.module >>/target/site/jacoco/index.html - when: always - - store_artifacts: - path: << parameters.module >>/target/site/jacoco/jacoco-resources - when: always - check_java_version: steps: - run: @@ -41,26 +29,9 @@ commands: name: Run Maven Verify command: | mvn -s .circleci/mvn-settings.xml -T4 verify - - store_jacoco_site: - module: qqq-backend-core - - store_jacoco_site: - module: qqq-backend-module-filesystem - - store_jacoco_site: - module: qqq-backend-module-rdbms - - store_jacoco_site: - module: qqq-backend-module-api - - store_jacoco_site: - module: qqq-middleware-api - - store_jacoco_site: - module: qqq-middleware-javalin - - store_jacoco_site: - module: qqq-middleware-picocli - - store_jacoco_site: - module: qqq-middleware-slack - - store_jacoco_site: - module: qqq-language-support-javascript - - store_jacoco_site: - module: qqq-sample-project + - store_artifacts: + path: "*/target/site/jacoco/" + when: always - run: name: Save test results command: | From 58dbcfd42bef07c4f86268407fd3cfacc8bfe3a0 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 2 Jul 2025 13:06:20 -0500 Subject: [PATCH 08/18] manual rewrite of jacoco summary reporting shell lines --- pom.xml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index a09cd325..a69a3ce8 100644 --- a/pom.xml +++ b/pom.xml @@ -251,22 +251,19 @@ echo "------------------------------------------------------------" # Parse Jacoco HTML coverage summary using grep and sed if [ -f target/site/jacoco/index.html ]; then - echo "Element\nInstructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$.headers + echo -e "Instructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$headers # Extract values from the footer row of the coverage table - grep -A 12 '' target/site/jacoco/index.html | grep '' | sed 's/\([^<]*\)<\/td>/\1/' | tr '\n' '\t' | sed 's/\t$/\n/' > /tmp/$$.values + sed 's/<\/\w\+>/&\n/g' target/site/jacoco/index.html | grep -A 12 '' | grep '\([^<]*\)<\/td>/\1/' | grep -v Total > /tmp/$$.values paste /tmp/$$.headers /tmp/$$.values | tail +2 | awk -v FS='\t' '{printf("%-20s %s\n",$1,$2)}' rm /tmp/$$.headers /tmp/$$.values else - echo "Jacoco coverage summary could not be parsed..."; + echo "Jacoco coverage summary was not found."; fi echo "Untested classes, per Jacoco:" echo "-----------------------------" # Parse Jacoco XML reports directly to find classes with 0% coverage -find target/site/jacoco -name "jacoco.xml" -exec grep -l '/&\n/g;s/<\/class>/&\n/g' target/site/jacoco/jacoco.xml | grep -v 'counter type="CLASS" missed="0"' | sed 's/>.*//;s/.*\///;s/".*//' echo ]]> From 04e64b04ab8df7bff4a9fa0c49138355a474de79 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 13:08:53 -0500 Subject: [PATCH 09/18] test output updates: - by default, make tests put all their output into files (under target/surefire-reports/) - with system property -DtestOutputToFile=false to get all output on console; - have circleci store that output as artifacts; - run mvn in 'batch mode' in circleci, for quieter output (no download progress, no color codes) --- .circleci/config.yml | 53 ++++++++++++++++++++++++++++++++++++++++---- README.md | 14 ++++++++++++ pom.xml | 8 ++++--- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c2e70028..83312064 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,10 +28,55 @@ commands: - run: name: Run Maven Verify command: | - mvn -s .circleci/mvn-settings.xml -T4 verify + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode verify - store_artifacts: path: "*/target/site/jacoco/" when: always + - store_artifacts: + path: "*/target/test-logs/" + when: always + - run: + name: Concatenate test output files + command: | + # Create artifacts directory + mkdir -p ~/test-output-artifacts/ + + # Find all module directories that have target/surefire-reports + for module_dir in */; do + if [ -d "${module_dir}target/surefire-reports" ]; then + module_name=$(basename "${module_dir%/}") + output_file="~/test-output-artifacts/${module_name}-test-output.txt" + + echo "Processing module: ${module_name}" + echo "Output file: ${output_file}" + + # Concatenate all .txt files in the surefire-reports directory + if [ -n "$(find "${module_dir}target/surefire-reports" -name "*.txt" -type f)" ]; then + echo "=== Test Output for ${module_name} ===" > "${output_file}" + echo "Generated at: $(date)" >> "${output_file}" + echo "==========================================" >> "${output_file}" + echo "" >> "${output_file}" + + # Sort files to ensure consistent ordering + find "${module_dir}target/surefire-reports" -name "*.txt" -type f | sort | while read -r txt_file; do + echo "--- File: $(basename "${txt_file}") ---" >> "${output_file}" + cat "${txt_file}" >> "${output_file}" + echo "" >> "${output_file}" + echo "--- End of $(basename "${txt_file}") ---" >> "${output_file}" + echo "" >> "${output_file}" + done + + echo "Concatenated test output for ${module_name} to ${output_file}" + else + echo "No .txt files found in ${module_dir}target/surefire-reports" + fi + fi + done + when: always + - store_artifacts: + path: ~/test-output-artifacts + destination: test-output + when: always - run: name: Save test results command: | @@ -54,8 +99,8 @@ commands: - run: name: Build and Run ValidateApiVersions command: | - mvn -s .circleci/mvn-settings.xml -T4 install -DskipTests - mvn -s .circleci/mvn-settings.xml -pl qqq-middleware-javalin package appassembler:assemble -DskipTests + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode install -DskipTests + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode -pl qqq-middleware-javalin package appassembler:assemble -DskipTests qqq-middleware-javalin/target/appassembler/bin/ValidateApiVersions -r $(pwd) mvn_jar_deploy: @@ -71,7 +116,7 @@ commands: - run: name: Run Maven Jar Deploy command: | - mvn -s .circleci/mvn-settings.xml -T4 flatten:flatten jar:jar deploy:deploy + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode flatten:flatten jar:jar deploy:deploy - save_cache: paths: - ~/.m2 diff --git a/README.md b/README.md index 797f0e0b..8a810ee7 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,20 @@ There are a few useful IntelliJ settings files, under `qqq-dev-tools/intellij`: One will likely also want the [Kingsrook Commentator Plugin](https://plugins.jetbrains.com/plugin/19325-kingsrook-commentator). +## Test Logging +By default, when ran from the command line, mvn surefire will make each test's +output (e.g., System.out, err, printStackTrace, and all logger calls) go into a +file under target/surefire-reports/${className}.txt. + +The system property `-DtestOutputToFile=false` can be given on the command line +to get all of this output on the console. + +In the IDE (e.g,. IntelliJ), output goes to the Console. + +In CircleCI, output goes to files, and those files are concatenated together and +stored as artifacts. + + ## License QQQ - Low-code Application Framework for Engineers. \ Copyright (C) 2020-2024. Kingsrook, LLC \ diff --git a/pom.xml b/pom.xml index a69a3ce8..291e05db 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,7 @@ 0.80 0.95 none + true @@ -141,6 +142,8 @@ @{jaCoCoArgLine} + + ${testOutputToFile} @@ -249,10 +252,9 @@ echo " See also target/site/jacoco/index.html" echo " and https://www.jacoco.org/jacoco/trunk/doc/counters.html" echo "------------------------------------------------------------" -# Parse Jacoco HTML coverage summary using grep and sed +# Parse Jacoco HTML coverage summary if [ -f target/site/jacoco/index.html ]; then - echo -e "Instructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$headers - # Extract values from the footer row of the coverage table + echo -e "Instructions Missed\nInstruction Coverage\nBranches Missed\nBranch Coverage\nComplexity Missed\nComplexity Hit\nLines Missed\nLines Hit\nMethods Missed\nMethods Hit\nClasses Missed\nClasses Hit\n" > /tmp/$$.headers sed 's/<\/\w\+>/&\n/g' target/site/jacoco/index.html | grep -A 12 '' | grep '\([^<]*\)<\/td>/\1/' | grep -v Total > /tmp/$$.values paste /tmp/$$.headers /tmp/$$.values | tail +2 | awk -v FS='\t' '{printf("%-20s %s\n",$1,$2)}' rm /tmp/$$.headers /tmp/$$.values From fc6f7b084dd7bfd96632eeb0e4e6001d0df94d72 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 14:48:52 -0500 Subject: [PATCH 10/18] Enhance Jacoco coverage summary output to include module name and improve readability with additional separators. --- pom.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 291e05db..0f55dd18 100644 --- a/pom.xml +++ b/pom.xml @@ -247,7 +247,7 @@ if [ ! -e target/site/jacoco/index.html ]; then fi echo -echo "Jacoco coverage summary report:" +echo "Jacoco coverage summary report for module: ${project.artifactId}" echo " See also target/site/jacoco/index.html" echo " and https://www.jacoco.org/jacoco/trunk/doc/counters.html" echo "------------------------------------------------------------" @@ -261,11 +261,14 @@ if [ -f target/site/jacoco/index.html ]; then else echo "Jacoco coverage summary was not found."; fi +echo "-----------------------------" +echo -echo "Untested classes, per Jacoco:" +echo "Untested classes, per Jacoco for module: ${project.artifactId}" echo "-----------------------------" # Parse Jacoco XML reports directly to find classes with 0% coverage sed 's//&\n/g;s/<\/class>/&\n/g' target/site/jacoco/jacoco.xml | grep -v 'counter type="CLASS" missed="0"' | sed 's/>.*//;s/.*\///;s/".*//' +echo "-----------------------------" echo ]]> From 171c73c4e4837a930e0fe779e01629bdd0ff7032 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 14:49:17 -0500 Subject: [PATCH 11/18] Update CircleCI configuration to use absolute paths for test output artifacts --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 83312064..1a02379d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,13 +39,13 @@ commands: name: Concatenate test output files command: | # Create artifacts directory - mkdir -p ~/test-output-artifacts/ + mkdir -p /home/circleci/test-output-artifacts/ # Find all module directories that have target/surefire-reports for module_dir in */; do if [ -d "${module_dir}target/surefire-reports" ]; then module_name=$(basename "${module_dir%/}") - output_file="~/test-output-artifacts/${module_name}-test-output.txt" + output_file="/home/circleci/test-output-artifacts/${module_name}-test-output.txt" echo "Processing module: ${module_name}" echo "Output file: ${output_file}" @@ -74,7 +74,7 @@ commands: done when: always - store_artifacts: - path: ~/test-output-artifacts + path: /home/circleci/test-output-artifacts destination: test-output when: always - run: From 7b2b1814272282b01398f83bb9fb8c45ebf1f812 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 15:03:25 -0500 Subject: [PATCH 12/18] split mvn verify into mvn build (which will have lots of output about downloading deps) and mvn test, to run tests (moving to test goal instead of verify, since we don't have any int-tests that would run in a verify, and we don't really need to do a packge) --- .circleci/config.yml | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a02379d..a9ddd154 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,7 +13,7 @@ commands: java -version echo "Java version check completed" - mvn_verify: + mvn_build: steps: - checkout - restore_cache: @@ -26,9 +26,24 @@ commands: command: | echo "RDBMS_PASSWORD=$RDBMS_PASSWORD" >> qqq-sample-project/.env - run: - name: Run Maven Verify + name: Run Maven Compile command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode verify + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode compile + - save_cache: + paths: + - ~/.m2 + key: v1-dependencies-{{ checksum "pom.xml" }} + + mvn_test: + steps: + - checkout + - restore_cache: + keys: + - v1-dependencies-{{ checksum "pom.xml" }} + - run: + name: Run Maven Test + command: | + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode test - store_artifacts: path: "*/target/site/jacoco/" when: always @@ -64,6 +79,8 @@ commands: echo "" >> "${output_file}" echo "--- End of $(basename "${txt_file}") ---" >> "${output_file}" echo "" >> "${output_file}" + echo "" >> "${output_file}" + echo "" >> "${output_file}" done echo "Concatenated test output for ${module_name} to ${output_file}" @@ -85,10 +102,6 @@ commands: when: always - store_test_results: path: ~/test-results - - save_cache: - paths: - - ~/.m2 - key: v1-dependencies-{{ checksum "pom.xml" }} check_middleware_api_versions: steps: @@ -148,7 +161,8 @@ jobs: steps: ## - localstack/startup - check_java_version - - mvn_verify + - mvn_build + - mvn_test - check_middleware_api_versions mvn_deploy: @@ -156,7 +170,8 @@ jobs: steps: ## - localstack/startup - check_java_version - - mvn_verify + - mvn_build + - mvn_test - check_middleware_api_versions - mvn_jar_deploy From 14a3dad3c879ecf5083b2751c1a541f151d88c43 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 15:13:15 -0500 Subject: [PATCH 13/18] Refactor CircleCI config to run tests and API version checks in parallel - Split mvn_test job into separate build, test, and api_version_check jobs - Run test and api_version_check in parallel after build completes - Both parallel jobs use compiled outputs from build via Maven cache - Remove unnecessary check_java_version steps - Remove unused test-logs artifact storage - Add jacoco:report to generate coverage reports - Maintain sequential execution in mvn_deploy job --- .circleci/config.yml | 47 +++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a9ddd154..cf61ae84 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,14 +5,6 @@ orbs: browser-tools: circleci/browser-tools@1.4.7 commands: - check_java_version: - steps: - - run: - name: Check Java Version - command: | - java -version - echo "Java version check completed" - mvn_build: steps: - checkout @@ -43,13 +35,10 @@ commands: - run: name: Run Maven Test command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode test + mvn -s .circleci/mvn-settings.xml -T4 --batch-mode test jacoco:report - store_artifacts: path: "*/target/site/jacoco/" when: always - - store_artifacts: - path: "*/target/test-logs/" - when: always - run: name: Concatenate test output files command: | @@ -156,20 +145,24 @@ commands: when: always jobs: - mvn_test: + build: executor: localstack/default steps: - ## - localstack/startup - - check_java_version - mvn_build + + test: + executor: localstack/default + steps: - mvn_test + + api_version_check: + executor: localstack/default + steps: - check_middleware_api_versions mvn_deploy: executor: localstack/default steps: - ## - localstack/startup - - check_java_version - mvn_build - mvn_test - check_middleware_api_versions @@ -184,13 +177,31 @@ jobs: workflows: test_only: jobs: - - mvn_test: + - build: context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] filters: branches: ignore: /(dev|integration.*)/ tags: ignore: /(version|snapshot)-.*/ + - test: + context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] + requires: + - build + filters: + branches: + ignore: /(dev|integration.*)/ + tags: + ignore: /(version|snapshot)-.*/ + - api_version_check: + context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] + requires: + - build + filters: + branches: + ignore: /(dev|integration.*)/ + tags: + ignore: /(version|snapshot)-.*/ deploy: jobs: From 0aaf1849621486fed82296c02b90834e3a7ab60b Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 15:24:54 -0500 Subject: [PATCH 14/18] move concatenate-test-output to its own script; switch back to verify, so we get jacoco reports; switch to no-tranffer-progress from batch-mode, so we still get color output --- .circleci/concatenate-test-output.sh | 48 +++++++++++++++++++++++ .circleci/config.yml | 57 ++++++---------------------- 2 files changed, 59 insertions(+), 46 deletions(-) create mode 100755 .circleci/concatenate-test-output.sh diff --git a/.circleci/concatenate-test-output.sh b/.circleci/concatenate-test-output.sh new file mode 100755 index 00000000..e86efd8e --- /dev/null +++ b/.circleci/concatenate-test-output.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +############################################################################ +## Script to concatenate all .txt files in the surefire-reports directory +## into a single artifact that can be stored in CI. +############################################################################ + +mkdir -p /home/circleci/test-output-artifacts/ + +################################################################### +## Find all module directories that have target/surefire-reports ## +################################################################### +for module_dir in */; do + if [ -d "${module_dir}target/surefire-reports" ]; then + module_name=$(basename "${module_dir%/}") + output_file="/home/circleci/test-output-artifacts/${module_name}-test-output.txt" + + echo "Processing module: ${module_name}" + echo "Output file: ${output_file}" + + ################################################################## + ## Concatenate all .txt files in the surefire-reports directory ## + ################################################################## + if [ -n "$(find "${module_dir}target/surefire-reports" -name "*.txt" -type f)" ]; then + echo "=== Test Output for ${module_name} ===" > "${output_file}" + echo "Generated at: $(date)" >> "${output_file}" + echo "==========================================" >> "${output_file}" + echo "" >> "${output_file}" + + ############################################## + ## Sort files to ensure consistent ordering ## + ############################################## + find "${module_dir}target/surefire-reports" -name "*.txt" -type f | sort | while read -r txt_file; do + echo "--- File: $(basename "${txt_file}") ---" >> "${output_file}" + cat "${txt_file}" >> "${output_file}" + echo "" >> "${output_file}" + echo "--- End of $(basename "${txt_file}") ---" >> "${output_file}" + echo "" >> "${output_file}" + echo "" >> "${output_file}" + echo "" >> "${output_file}" + done + + echo "Concatenated test output for ${module_name} to ${output_file}" + else + echo "No .txt files found in ${module_dir}target/surefire-reports" + fi + fi +done \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index cf61ae84..a50edc3a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,64 +20,29 @@ commands: - run: name: Run Maven Compile command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode compile + mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress compile - save_cache: paths: - ~/.m2 key: v1-dependencies-{{ checksum "pom.xml" }} - mvn_test: + mvn_verify: steps: - checkout - restore_cache: keys: - v1-dependencies-{{ checksum "pom.xml" }} - run: - name: Run Maven Test + name: Run Maven Verify command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode test jacoco:report + mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress verify - store_artifacts: + name: Store Jacoco reports path: "*/target/site/jacoco/" when: always - run: name: Concatenate test output files - command: | - # Create artifacts directory - mkdir -p /home/circleci/test-output-artifacts/ - - # Find all module directories that have target/surefire-reports - for module_dir in */; do - if [ -d "${module_dir}target/surefire-reports" ]; then - module_name=$(basename "${module_dir%/}") - output_file="/home/circleci/test-output-artifacts/${module_name}-test-output.txt" - - echo "Processing module: ${module_name}" - echo "Output file: ${output_file}" - - # Concatenate all .txt files in the surefire-reports directory - if [ -n "$(find "${module_dir}target/surefire-reports" -name "*.txt" -type f)" ]; then - echo "=== Test Output for ${module_name} ===" > "${output_file}" - echo "Generated at: $(date)" >> "${output_file}" - echo "==========================================" >> "${output_file}" - echo "" >> "${output_file}" - - # Sort files to ensure consistent ordering - find "${module_dir}target/surefire-reports" -name "*.txt" -type f | sort | while read -r txt_file; do - echo "--- File: $(basename "${txt_file}") ---" >> "${output_file}" - cat "${txt_file}" >> "${output_file}" - echo "" >> "${output_file}" - echo "--- End of $(basename "${txt_file}") ---" >> "${output_file}" - echo "" >> "${output_file}" - echo "" >> "${output_file}" - echo "" >> "${output_file}" - done - - echo "Concatenated test output for ${module_name} to ${output_file}" - else - echo "No .txt files found in ${module_dir}target/surefire-reports" - fi - fi - done + command: .circleci/concatenate-test-output.sh when: always - store_artifacts: path: /home/circleci/test-output-artifacts @@ -101,8 +66,8 @@ commands: - run: name: Build and Run ValidateApiVersions command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode install -DskipTests - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode -pl qqq-middleware-javalin package appassembler:assemble -DskipTests + mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress install -DskipTests + mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress -pl qqq-middleware-javalin package appassembler:assemble -DskipTests qqq-middleware-javalin/target/appassembler/bin/ValidateApiVersions -r $(pwd) mvn_jar_deploy: @@ -118,7 +83,7 @@ commands: - run: name: Run Maven Jar Deploy command: | - mvn -s .circleci/mvn-settings.xml -T4 --batch-mode flatten:flatten jar:jar deploy:deploy + mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress flatten:flatten jar:jar deploy:deploy - save_cache: paths: - ~/.m2 @@ -153,7 +118,7 @@ jobs: test: executor: localstack/default steps: - - mvn_test + - mvn_verify api_version_check: executor: localstack/default @@ -164,7 +129,7 @@ jobs: executor: localstack/default steps: - mvn_build - - mvn_test + - mvn_verify - check_middleware_api_versions - mvn_jar_deploy From 8531feef70bbb3a8d2924407f3c5034e91fc9897 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 3 Jul 2025 15:41:09 -0500 Subject: [PATCH 15/18] Add script to collect JaCoCo reports and update CircleCI config to use it --- .circleci/collect-jacoco-reports.sh | 26 ++++++++++++++++++++++++++ .circleci/config.yml | 8 ++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100755 .circleci/collect-jacoco-reports.sh diff --git a/.circleci/collect-jacoco-reports.sh b/.circleci/collect-jacoco-reports.sh new file mode 100755 index 00000000..dca6bbad --- /dev/null +++ b/.circleci/collect-jacoco-reports.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################ +## Script to collect all JaCoCo reports from different modules into a +## single directory for easier artifact storage in CI. +############################################################################ + +mkdir -p /home/circleci/jacoco-reports/ + +############################################################## +## Find all module directories that have target/site/jacoco ## +############################################################## +for module_dir in */; do + if [ -d "${module_dir}target/site/jacoco" ]; then + module_name=$(basename "${module_dir%/}") + target_dir="/home/circleci/jacoco-reports/${module_name}" + + echo "Collecting JaCoCo reports for module: ${module_name}" + + cp -r "${module_dir}target/site/jacoco" "${target_dir}" + + echo "Copied JaCoCo reports for ${module_name} to ${target_dir}" + fi +done + +echo "All JaCoCo reports collected to /home/circleci/jacoco-reports/" \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index a50edc3a..748c1a64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,9 +36,13 @@ commands: name: Run Maven Verify command: | mvn -s .circleci/mvn-settings.xml -T4 --no-transfer-progress verify + - run: + name: Collect JaCoCo reports + command: .circleci/collect-jacoco-reports.sh + when: always - store_artifacts: - name: Store Jacoco reports - path: "*/target/site/jacoco/" + path: /home/circleci/jacoco-reports + destination: jacoco-reports when: always - run: name: Concatenate test output files From abfdf09b32bc4fc0c2544e600918323a08894c96 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 14 Jul 2025 17:01:15 -0500 Subject: [PATCH 16/18] Rewrite deploy workflow to also be split up --- .circleci/config.yml | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 748c1a64..2371adbf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -129,12 +129,9 @@ jobs: steps: - check_middleware_api_versions - mvn_deploy: + deploy: executor: localstack/default steps: - - mvn_build - - mvn_verify - - check_middleware_api_versions - mvn_jar_deploy publish_asciidoc: @@ -174,13 +171,41 @@ workflows: deploy: jobs: - - mvn_deploy: + - build: context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] filters: branches: only: /(dev|integration.*)/ tags: only: /(version|snapshot)-.*/ + - test: + context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] + requires: + - build + filters: + branches: + only: /(dev|integration.*)/ + tags: + only: /(version|snapshot)-.*/ + - api_version_check: + context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] + requires: + - build + filters: + branches: + only: /(dev|integration.*)/ + tags: + only: /(version|snapshot)-.*/ + - deploy: + context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] + requires: + - test + - api_version_check + filters: + branches: + only: /(dev|integration.*)/ + tags: + only: /(version|snapshot)-.*/ - publish_asciidoc: filters: branches: From fc4b34306fd6d437e80aaae6c9a617c02b771ba7 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 14 Jul 2025 17:07:30 -0500 Subject: [PATCH 17/18] Remove duplicated sshd-sftp dep --- qqq-backend-module-filesystem/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qqq-backend-module-filesystem/pom.xml b/qqq-backend-module-filesystem/pom.xml index c389a018..ec34d48e 100644 --- a/qqq-backend-module-filesystem/pom.xml +++ b/qqq-backend-module-filesystem/pom.xml @@ -55,11 +55,6 @@ sshd-sftp 2.14.0 - - org.apache.sshd - sshd-sftp - 2.14.0 - cloud.localstack From d311e28e60b4767213859a08d51cb738760b11cd Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 14 Jul 2025 17:10:30 -0500 Subject: [PATCH 18/18] Revert "Rewrite deploy workflow to also be split up" This reverts commit abfdf09b32bc4fc0c2544e600918323a08894c96. --- .circleci/config.yml | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2371adbf..748c1a64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -129,9 +129,12 @@ jobs: steps: - check_middleware_api_versions - deploy: + mvn_deploy: executor: localstack/default steps: + - mvn_build + - mvn_verify + - check_middleware_api_versions - mvn_jar_deploy publish_asciidoc: @@ -171,41 +174,13 @@ workflows: deploy: jobs: - - build: + - mvn_deploy: context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] filters: branches: only: /(dev|integration.*)/ tags: only: /(version|snapshot)-.*/ - - test: - context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] - requires: - - build - filters: - branches: - only: /(dev|integration.*)/ - tags: - only: /(version|snapshot)-.*/ - - api_version_check: - context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] - requires: - - build - filters: - branches: - only: /(dev|integration.*)/ - tags: - only: /(version|snapshot)-.*/ - - deploy: - context: [ qqq-maven-registry-credentials, build-qqq-sample-app ] - requires: - - test - - api_version_check - filters: - branches: - only: /(dev|integration.*)/ - tags: - only: /(version|snapshot)-.*/ - publish_asciidoc: filters: branches: