From 1cf738767c2265dca702bf9db2efd925f9ab2c7c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 May 2024 15:30:36 +0000 Subject: [PATCH 001/115] Update Jetty packages --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7c861d34..64281785 100644 --- a/build.gradle +++ b/build.gradle @@ -66,8 +66,8 @@ dependencies { implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty:jetty-servlet:9.4.54.v20240208' - implementation 'org.eclipse.jetty:jetty-xml:9.4.54.v20240208' + implementation 'org.eclipse.jetty:jetty-servlet:11.0.21' + implementation 'org.eclipse.jetty:jetty-xml:12.0.9' implementation 'org.mozilla:rhino:1.7.13' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' From ed575bc4c5f5e047ec50642666343398db509507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sun, 19 May 2024 02:05:49 +0200 Subject: [PATCH 002/115] Update README.md Minor edits --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a735855f..2a134485 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ Helma is built with [Gradle](https://gradle.org), the build task depends on the ### Additional Prerequisites * [Rsync](https://rsync.samba.org) version ≥ 3.1.0 -* [NodeJS](https://nodejs.org) LTS version +* [Node.js](https://nodejs.org) LTS version -Clone this repository to your machine and start the build process with `./gradlew install`. The build script is going to ask you if you want to update the installation, enter `y`. +Clone this repository to your machine and start the build process with `./gradlew install`. The build script is going to ask you if you want to update the installation, enter `yes` or `no`. > ⚠️ > Please be aware that this step is going to overwrite files in the installation directory – escpecially at a later time when there might be substantial changes. Should this happen by accident you find the previous installation in the `backups` directory. From c087cb731eef411e278b65ed0c75ef9743cd7810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 14:11:15 +0200 Subject: [PATCH 003/115] Use correct version of Jetty servlet --- build.gradle | 2 +- src/main/java/helma/main/ApplicationManager.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 68e45638..9cf24ba9 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty:jetty-servlet:11.0.21' + implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.9' implementation 'org.eclipse.jetty:jetty-xml:12.0.9' implementation 'org.mozilla:rhino:1.7.13' implementation 'org.sejda.imageio:webp-imageio:0.1.6' diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 2deb88ee..edce8483 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -22,8 +22,8 @@ import org.apache.xmlrpc.XmlRpcHandler; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.ee9.servlet.ServletContextHandler; +import org.eclipse.jetty.ee9.servlet.ServletHolder; import helma.framework.core.Application; import helma.framework.repository.FileRepository; From a943124d45ce51c8c4be9b39fb9bc937e45312da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:04:17 +0200 Subject: [PATCH 004/115] Fix creating Jetty server from config file --- src/main/java/helma/main/JettyServer.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/helma/main/JettyServer.java b/src/main/java/helma/main/JettyServer.java index 88ba8c10..cfd30264 100644 --- a/src/main/java/helma/main/JettyServer.java +++ b/src/main/java/helma/main/JettyServer.java @@ -16,11 +16,12 @@ package helma.main; - import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.URLResourceFactory; import org.eclipse.jetty.xml.XmlConfiguration; import java.net.URL; @@ -36,18 +37,20 @@ public class JettyServer { public static JettyServer init(Server server, ServerConfig config) throws IOException { File configFile = config.getConfigFile(); if (configFile != null && configFile.exists()) { - return new JettyServer(configFile.toURI().toURL()); + URLResourceFactory resourceFactory = new URLResourceFactory(); + Resource resource = resourceFactory.newResource(configFile.toURI()); + return new JettyServer(resource); } else if (config.hasWebsrvPort()) { return new JettyServer(config.getWebsrvPort(), server); } return null; } - private JettyServer(URL url) throws IOException { + private JettyServer(Resource resource) throws IOException { http = new org.eclipse.jetty.server.Server(); try { - XmlConfiguration config = new XmlConfiguration(url); + XmlConfiguration config = new XmlConfiguration(resource); config.configure(http); } catch (IOException e) { @@ -59,7 +62,7 @@ public class JettyServer { private JettyServer(InetSocketAddress webPort, Server server) throws IOException { - + http = new org.eclipse.jetty.server.Server(); // start embedded web server if port is specified From 26975a109a0a13771eb3e955ceca930de9e10103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:07:22 +0200 Subject: [PATCH 005/115] Method ServerConnector.setSoLingerTime() was removed --- src/main/java/helma/main/JettyServer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/helma/main/JettyServer.java b/src/main/java/helma/main/JettyServer.java index cfd30264..c28be40a 100644 --- a/src/main/java/helma/main/JettyServer.java +++ b/src/main/java/helma/main/JettyServer.java @@ -76,7 +76,6 @@ public class JettyServer { connector.setHost(webPort.getAddress().getHostAddress()); connector.setPort(webPort.getPort()); connector.setIdleTimeout(30000); - connector.setSoLingerTime(-1); connector.setAcceptorPriorityDelta(0); connector.setAcceptQueueSize(0); From 62630ae0687524f743b8332af59c412dad480eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:08:17 +0200 Subject: [PATCH 006/115] Modernize for loop --- src/main/java/helma/main/JettyServer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/helma/main/JettyServer.java b/src/main/java/helma/main/JettyServer.java index c28be40a..83e09bcf 100644 --- a/src/main/java/helma/main/JettyServer.java +++ b/src/main/java/helma/main/JettyServer.java @@ -102,12 +102,13 @@ public class JettyServer { } private void openListeners() throws IOException { - // opening the listener here allows us to run on priviledged port 80 under jsvc + // opening the listener here allows us to run on privileged port 80 under jsvc // even as non-root user, because init() is called with root privileges // while start() will be called with the user we will actually run as - Connector[] connectors = http.getConnectors(); - for (int i = 0; i < connectors.length; i++) { - ((ServerConnector) connectors[i]).open(); + for (var connector : http.getConnectors()) { + if (connector instanceof ServerConnector) { + ((ServerConnector) connector).open(); + } } } } From 0165e7c80ee63a5415f7a8c28e8ef771e9bb7d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:17:43 +0200 Subject: [PATCH 007/115] Fix setup of static resource --- src/main/java/helma/main/ApplicationManager.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index edce8483..c56ccce0 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -19,11 +19,13 @@ import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.xmlrpc.XmlRpcHandler; + import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.ee9.servlet.ServletContextHandler; import org.eclipse.jetty.ee9.servlet.ServletHolder; +import org.eclipse.jetty.util.resource.ResourceFactory; import helma.framework.core.Application; import helma.framework.repository.FileRepository; @@ -481,19 +483,21 @@ public class ApplicationManager implements XmlRpcHandler { // if there is a static direcory specified, mount it if (this.staticDir != null) { + String staticPath = getAbsoluteFile(this.staticDir).getPath(); - File staticContent = getAbsoluteFile(this.staticDir); - - getLogger().info("Serving static from " + staticContent.getPath()); + getLogger().info("Serving static from " + staticPath); getLogger().info("Mounting static at " + staticMountpoint); ResourceHandler rhandler = new ResourceHandler(); - rhandler.setResourceBase(staticContent.getPath()); + rhandler.setBaseResource(ResourceFactory.of(rhandler).newResource(staticPath)); rhandler.setWelcomeFiles(staticHome); - staticContext = ApplicationManager.this.context.addContext(staticMountpoint, ""); //$NON-NLS-1$ + ContextHandler staticContext = new ContextHandler(); + staticContext.setContextPath(staticMountpoint); + staticContext.setBaseResourceAsString(""); staticContext.setHandler(rhandler); + ApplicationManager.this.context.addHandler(staticContext); staticContext.start(); } From 304ea4e456f5e585b66bda940fb58708df5f3cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:21:56 +0200 Subject: [PATCH 008/115] Fix creation of app context --- src/main/java/helma/main/ApplicationManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index c56ccce0..78f66623 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -501,7 +501,10 @@ public class ApplicationManager implements XmlRpcHandler { staticContext.start(); } - appContext = new ServletContextHandler(context, pathPattern, true, true); + appContext = new ServletContextHandler(ServletContextHandler.SESSIONS); + appContext.setContextPath(pathPattern); + context.addHandler(appContext); + Class servletClass = servletClassName == null ? EmbeddedServletClient.class : Class.forName(servletClassName); ServletHolder holder = new ServletHolder(servletClass); From fa59a2785858b4b77c14a7c789c2e5ede21c68c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:24:28 +0200 Subject: [PATCH 009/115] Fix creation of protected context --- src/main/java/helma/main/ApplicationManager.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 78f66623..6bb1eb58 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -536,10 +536,9 @@ public class ApplicationManager implements XmlRpcHandler { } if (protectedStaticDir != null) { - File protectedContent = getAbsoluteFile(protectedStaticDir); - appContext.setResourceBase(protectedContent.getPath()); - getLogger().info("Serving protected static from " + - protectedContent.getPath()); + String protectedContent = getAbsoluteFile(protectedStaticDir).getPath(); + appContext.setBaseResourceAsString(protectedContent); + getLogger().info("Serving protected static from " + protectedContent); } // Remap the context paths and start From d67d0235bd11dcdd13f0b3dcea8e0d3cadd6d90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:25:41 +0200 Subject: [PATCH 010/115] Prevent java.lang.IllegalStateException: Shared scheduler not started --- src/main/java/helma/main/ApplicationManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 6bb1eb58..755b65b8 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -543,7 +543,9 @@ public class ApplicationManager implements XmlRpcHandler { // Remap the context paths and start ApplicationManager.this.context.mapContexts(); - this.appContext.start(); + // FIXME: Causing java.lang.IllegalStateException: Shared scheduler not started + // Is it necessary, anway? + //this.appContext.start(); } // register as XML-RPC handler From 441d952b3502949862f2beeea75a2262934ba959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:26:18 +0200 Subject: [PATCH 011/115] Prevent incompatible types: ServletContextHandler cannot be converted to Handler --- src/main/java/helma/main/ApplicationManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 755b65b8..2c9c357c 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -564,7 +564,9 @@ public class ApplicationManager implements XmlRpcHandler { // unbind from Jetty HTTP server if (ApplicationManager.this.jetty != null) { if (this.appContext != null) { - ApplicationManager.this.context.removeHandler(this.appContext); + // FIXME: Causing incompatible types: ServletContextHandler cannot be converted to Handler + // Is it necessary, anyway? + //ApplicationManager.this.context.removeHandler(this.appContext); this.appContext.stop(); this.appContext.destroy(); this.appContext = null; From 973b3493cb996f4501e6755e2dd20eb8a89f1ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:30:10 +0200 Subject: [PATCH 012/115] Prevent java.lang.IllegalArgumentException: Resource String is invalid --- src/main/java/helma/main/ApplicationManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 2c9c357c..957eb7fe 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -494,7 +494,8 @@ public class ApplicationManager implements XmlRpcHandler { ContextHandler staticContext = new ContextHandler(); staticContext.setContextPath(staticMountpoint); - staticContext.setBaseResourceAsString(""); + // FIXME: Causing java.lang.IllegalArgumentException: Resource String is invalid + //staticContext.setBaseResourceAsString(""); staticContext.setHandler(rhandler); ApplicationManager.this.context.addHandler(staticContext); From 3dbcd792a6319d16b97548aca462d5b9b5a45e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:44:59 +0200 Subject: [PATCH 013/115] Migrate to Jakarte servlet API 5 --- build.gradle | 2 +- src/main/java/helma/framework/CookieTrans.java | 2 +- src/main/java/helma/framework/RequestBean.java | 6 +++--- src/main/java/helma/framework/RequestTrans.java | 6 +++--- src/main/java/helma/framework/ResponseBean.java | 2 +- src/main/java/helma/framework/ResponseTrans.java | 2 +- src/main/java/helma/servlet/AbstractServletClient.java | 10 ++++++---- src/main/java/helma/servlet/EmbeddedServletClient.java | 2 +- .../java/helma/servlet/StandaloneServletClient.java | 6 +++--- 9 files changed, 20 insertions(+), 18 deletions(-) diff --git a/build.gradle b/build.gradle index 9cf24ba9..700545c0 100644 --- a/build.gradle +++ b/build.gradle @@ -64,7 +64,7 @@ dependencies { implementation 'commons-logging:commons-logging:1.3.2' implementation 'commons-net:commons-net:3.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' - implementation 'javax.servlet:javax.servlet-api:4.0.1' + implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.9' implementation 'org.eclipse.jetty:jetty-xml:12.0.9' diff --git a/src/main/java/helma/framework/CookieTrans.java b/src/main/java/helma/framework/CookieTrans.java index fed45960..5293b843 100644 --- a/src/main/java/helma/framework/CookieTrans.java +++ b/src/main/java/helma/framework/CookieTrans.java @@ -17,7 +17,7 @@ package helma.framework; import java.io.Serializable; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.Cookie; /** * Cookie Transmitter. A simple, serializable representation diff --git a/src/main/java/helma/framework/RequestBean.java b/src/main/java/helma/framework/RequestBean.java index 49091022..bf377a63 100644 --- a/src/main/java/helma/framework/RequestBean.java +++ b/src/main/java/helma/framework/RequestBean.java @@ -16,12 +16,12 @@ package helma.framework; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Map; /** - * + * */ public class RequestBean implements Serializable { private static final long serialVersionUID = -6826881712426326687L; @@ -89,7 +89,7 @@ public class RequestBean implements Serializable { * @return the header value, or null */ public String getHeader(String name) { - return req.getHeader(name); + return req.getHeader(name); } /** diff --git a/src/main/java/helma/framework/RequestTrans.java b/src/main/java/helma/framework/RequestTrans.java index 83665ba8..ec8218fe 100644 --- a/src/main/java/helma/framework/RequestTrans.java +++ b/src/main/java/helma/framework/RequestTrans.java @@ -19,9 +19,9 @@ package helma.framework; import helma.util.SystemMap; import helma.util.StringUtils; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Cookie; import org.apache.commons.codec.binary.Base64; diff --git a/src/main/java/helma/framework/ResponseBean.java b/src/main/java/helma/framework/ResponseBean.java index 71688a96..a1a8c9fa 100644 --- a/src/main/java/helma/framework/ResponseBean.java +++ b/src/main/java/helma/framework/ResponseBean.java @@ -19,7 +19,7 @@ package helma.framework; import helma.objectmodel.db.Transactor; import helma.scripting.ScriptingException; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.Serializable; import java.io.StringWriter; import java.io.PrintWriter; diff --git a/src/main/java/helma/framework/ResponseTrans.java b/src/main/java/helma/framework/ResponseTrans.java index 583b41b1..28fc3e65 100644 --- a/src/main/java/helma/framework/ResponseTrans.java +++ b/src/main/java/helma/framework/ResponseTrans.java @@ -21,7 +21,7 @@ import helma.framework.core.Application; import helma.util.*; import helma.scripting.ScriptingException; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.*; import java.security.*; import java.util.*; diff --git a/src/main/java/helma/servlet/AbstractServletClient.java b/src/main/java/helma/servlet/AbstractServletClient.java index 77284078..561405b0 100644 --- a/src/main/java/helma/servlet/AbstractServletClient.java +++ b/src/main/java/helma/servlet/AbstractServletClient.java @@ -22,12 +22,14 @@ package helma.servlet; import helma.framework.*; import helma.framework.core.Application; import helma.util.*; + import java.io.*; import java.util.*; import java.security.SecureRandom; import java.security.NoSuchAlgorithmException; -import javax.servlet.*; -import javax.servlet.http.*; + +import jakarta.servlet.*; +import jakarta.servlet.http.*; import org.apache.commons.codec.binary.Base64; import org.apache.commons.fileupload.disk.DiskFileItemFactory; @@ -218,7 +220,7 @@ public abstract class AbstractServletClient extends HttpServlet { // read file uploads List uploads = null; - ServletRequestContext reqcx = new ServletRequestContext(request); + JakartaServletRequestContext reqcx = new JakartaServletRequestContext(request); if (ServletFileUpload.isMultipartContent(reqcx)) { // get session for upload progress monitoring @@ -653,7 +655,7 @@ public abstract class AbstractServletClient extends HttpServlet { map.put(name, newValues); } - protected List parseUploads(ServletRequestContext reqcx, RequestTrans reqtrans, + protected List parseUploads(JakartaServletRequestContext reqcx, RequestTrans reqtrans, final UploadStatus uploadStatus, String encoding) throws FileUploadException, UnsupportedEncodingException { // handle file upload diff --git a/src/main/java/helma/servlet/EmbeddedServletClient.java b/src/main/java/helma/servlet/EmbeddedServletClient.java index 80b3cd6e..9f9a37cc 100644 --- a/src/main/java/helma/servlet/EmbeddedServletClient.java +++ b/src/main/java/helma/servlet/EmbeddedServletClient.java @@ -19,7 +19,7 @@ package helma.servlet; import helma.framework.*; import helma.framework.core.Application; import helma.main.*; -import javax.servlet.*; +import jakarta.servlet.*; /** * Servlet client that runs a Helma application for the embedded diff --git a/src/main/java/helma/servlet/StandaloneServletClient.java b/src/main/java/helma/servlet/StandaloneServletClient.java index 5e1af952..bdfeeeae 100644 --- a/src/main/java/helma/servlet/StandaloneServletClient.java +++ b/src/main/java/helma/servlet/StandaloneServletClient.java @@ -23,7 +23,7 @@ import helma.main.ServerConfig; import helma.main.Server; import java.io.*; -import javax.servlet.*; +import jakarta.servlet.*; import java.util.*; /** @@ -98,7 +98,7 @@ public final class StandaloneServletClient extends AbstractServletClient { repositoryImpl = "helma.framework.repository.FileRepository"; } } - + try { Repository newRepository = (Repository) Class.forName(repositoryImpl) .getConstructor(parameters) @@ -116,7 +116,7 @@ public final class StandaloneServletClient extends AbstractServletClient { } } } - + // add app dir FileRepository appRep = new FileRepository(appDir); log("adding repository: " + appDir); From 90e45c91158978e649cad78ef02fdb3a51e35199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 15:46:19 +0200 Subject: [PATCH 014/115] Migrate to Apache file upload API 2 w/ Jakarta --- build.gradle | 3 +- .../helma/servlet/AbstractServletClient.java | 31 ++++++++++++------- src/main/java/helma/util/MimePart.java | 6 ++-- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 700545c0..0260b537 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,8 @@ configurations { dependencies { implementation 'com.google.code.gson:gson:2.10.1' implementation 'commons-codec:commons-codec:1.17.0' - implementation 'commons-fileupload:commons-fileupload:1.5' + implementation 'org.apache.commons:commons-fileupload2-core:2.0.0-M2' + implementation 'org.apache.commons:commons-fileupload2-jakarta:2.0.0-M1' implementation 'commons-logging:commons-logging:1.3.2' implementation 'commons-net:commons-net:3.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' diff --git a/src/main/java/helma/servlet/AbstractServletClient.java b/src/main/java/helma/servlet/AbstractServletClient.java index 561405b0..52d1a91d 100644 --- a/src/main/java/helma/servlet/AbstractServletClient.java +++ b/src/main/java/helma/servlet/AbstractServletClient.java @@ -24,18 +24,27 @@ import helma.framework.core.Application; import helma.util.*; import java.io.*; -import java.util.*; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + import java.security.SecureRandom; import java.security.NoSuchAlgorithmException; +import java.util.*; import jakarta.servlet.*; import jakarta.servlet.http.*; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.*; -import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.apache.commons.fileupload.servlet.ServletRequestContext; + +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.core.FileUploadSizeException; +import org.apache.commons.fileupload2.core.ProgressListener; + +import org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload; +import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload; +import org.apache.commons.fileupload2.jakarta.JakartaServletRequestContext; /** * This is an abstract Hop servlet adapter. This class communicates with hop applications @@ -222,7 +231,7 @@ public abstract class AbstractServletClient extends HttpServlet { List uploads = null; JakartaServletRequestContext reqcx = new JakartaServletRequestContext(request); - if (ServletFileUpload.isMultipartContent(reqcx)) { + if (JakartaServletFileUpload.isMultipartContent(reqcx)) { // get session for upload progress monitoring UploadStatus uploadStatus = getApplication().getUploadStatus(reqtrans); try { @@ -230,7 +239,7 @@ public abstract class AbstractServletClient extends HttpServlet { } catch (Exception upx) { log("Error in file upload", upx); String message; - boolean tooLarge = (upx instanceof FileUploadBase.SizeLimitExceededException); + boolean tooLarge = (upx instanceof FileUploadSizeException); if (tooLarge) { message = "File upload size exceeds limit of " + uploadLimit + " kB"; } else { @@ -657,10 +666,10 @@ public abstract class AbstractServletClient extends HttpServlet { protected List parseUploads(JakartaServletRequestContext reqcx, RequestTrans reqtrans, final UploadStatus uploadStatus, String encoding) - throws FileUploadException, UnsupportedEncodingException { + throws FileUploadException, UnsupportedCharsetException, IOException { // handle file upload - DiskFileItemFactory factory = new DiskFileItemFactory(); - FileUpload upload = new FileUpload(factory); + DiskFileItemFactory factory = DiskFileItemFactory.builder().get(); + JakartaServletFileUpload upload = new JakartaServletFileUpload(factory); // use upload limit for individual file size, but also set a limit on overall size upload.setFileSizeMax(uploadLimit * 1024); upload.setSizeMax(totalUploadLimit * 1024); @@ -683,7 +692,7 @@ public abstract class AbstractServletClient extends HttpServlet { Object value; // check if this is an ordinary HTML form element or a file upload if (item.isFormField()) { - value = item.getString(encoding); + value = item.getString(Charset.forName(encoding)); } else { value = new MimePart(item); } diff --git a/src/main/java/helma/util/MimePart.java b/src/main/java/helma/util/MimePart.java index f69f1d61..e4ed29d8 100644 --- a/src/main/java/helma/util/MimePart.java +++ b/src/main/java/helma/util/MimePart.java @@ -16,7 +16,7 @@ package helma.util; -import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload2.core.FileItem; import java.io.*; import java.util.Date; @@ -238,7 +238,7 @@ public class MimePart implements Serializable { file = new File(base, filename); if (fileItem != null) { - fileItem.write(file); + fileItem.write(file.toPath()); // null out fileItem, since calling write() may have moved the temp file fileItem = null; } else { @@ -249,7 +249,7 @@ public class MimePart implements Serializable { // return file name return filename; } catch (Exception x) { - System.err.println("Error in MimePart.writeToFile(): " + x); + System.err.println("Error in MimePart.writeToFile(): " + x); return null; } } From 79d83389f21ef949eb7113bfef28206836707d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 25 May 2024 16:16:04 +0200 Subject: [PATCH 015/115] Use canonical paths when creating static contexts --- src/main/java/helma/main/ApplicationManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 957eb7fe..7d31b764 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -483,7 +483,7 @@ public class ApplicationManager implements XmlRpcHandler { // if there is a static direcory specified, mount it if (this.staticDir != null) { - String staticPath = getAbsoluteFile(this.staticDir).getPath(); + String staticPath = getAbsoluteFile(this.staticDir).getCanonicalPath(); getLogger().info("Serving static from " + staticPath); getLogger().info("Mounting static at " + staticMountpoint); @@ -537,7 +537,7 @@ public class ApplicationManager implements XmlRpcHandler { } if (protectedStaticDir != null) { - String protectedContent = getAbsoluteFile(protectedStaticDir).getPath(); + String protectedContent = getAbsoluteFile(protectedStaticDir).getCanonicalPath(); appContext.setBaseResourceAsString(protectedContent); getLogger().info("Serving protected static from " + protectedContent); } From 9143faf35ec71163ebb9727daf6e1975602cc7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Thu, 30 May 2024 18:49:45 +0200 Subject: [PATCH 016/115] Add release action --- .github/workflows/release.yml | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..28a2249c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Build with Gradle + run: ./gradlew assembleDist + + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "$GITHUB_REF_NAME" \ + --repo "$GITHUB_REPOSITORY" \ + --title "Helma $GITHUB_REF_NAME" \ + --generate-notes + + - name: Upload assets + run: | + gh release upload "$GITHUB_REF_NAME" \ + build/distributions/helma-*.* + --clobber From 85f610211227d9d24428ebb96dd65bb1edd8e4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Jun 2024 15:17:34 +0200 Subject: [PATCH 017/115] Add reusable workflow for setting up SSH agent --- .github/actions/ssh/action.yml | 42 ++++++++++++++++++++++++++++++++++ .github/workflows/stage.yml | 21 +++++++---------- 2 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 .github/actions/ssh/action.yml diff --git a/.github/actions/ssh/action.yml b/.github/actions/ssh/action.yml new file mode 100644 index 00000000..5c4886ab --- /dev/null +++ b/.github/actions/ssh/action.yml @@ -0,0 +1,42 @@ +name: SSH setup +description: Set up the SSH agent + +inputs: + config: + description: The SSH configuration + required: true + key: + description: The private SSH key + required: true + known-hosts: + description: The list of known hosts + required: true + +runs: + using: composite + + steps: + - name: Configure SSH + shell: sh + env: + CONFIG: ${{ inputs.config }} + KNOWN_HOSTS: ${{ inputs.known-hosts }} + run: | + mkdir -p ~/.ssh + echo "${CONFIG}" > ~/.ssh/config + echo "${KNOWN_HOSTS}" > ~/.ssh/known_hosts + + - name: Start SSH agent + shell: bash + env: + SOCKET: /tmp/ssh-agent.sock + run: | + echo "SSH_AUTH_SOCK=${SOCKET}" >> $GITHUB_ENV + ssh-agent -a ${SOCKET} > /dev/null + + - name: Add SSH key + shell: bash + env: + KEY: ${{ inputs.key }} + run: | + ssh-add - <<< "${KEY}" diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index af3e3b17..177d84b1 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -1,10 +1,6 @@ name: Deploy (Staging) -on: - workflow_dispatch - -env: - SSH_AUTH_SOCK: /tmp/ssh-agent.sock +on: workflow_dispatch jobs: stage: @@ -17,6 +13,13 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up SSH agent + uses: ./.github/actions/ssh + with: + config: ${{ vars.SSH_CONFIG }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} + - name: Set up Java uses: actions/setup-java@v4 with: @@ -29,14 +32,6 @@ jobs: - name: Build with Gradle run: ./gradlew installDist - - name: Set up SSH agent - run: | - ssh-agent -a $SSH_AUTH_SOCK > /dev/null - ssh-add - <<< "${{ secrets.SSH_PRIVATE_KEY }}" - mkdir -p ~/.ssh - echo '${{ vars.SSH_CONFIG }}' > ~/.ssh/config - echo '${{ vars.KNOWN_HOSTS }}' > ~/.ssh/known_hosts - - name: Publish to staging server run: | rsync build/install/helma/ antville.dev:/ \ From 4b8d121266d2b5da2f9f747a8ab16834a60f2ce6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:07:00 +0000 Subject: [PATCH 018/115] Update Lucene packages to v2.9.4 --- modules/helma/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/helma/build.gradle b/modules/helma/build.gradle index f78f66d4..6b8c2b5e 100644 --- a/modules/helma/build.gradle +++ b/modules/helma/build.gradle @@ -1,8 +1,8 @@ dependencies { runtimeOnly 'ch.ethz.ganymed:ganymed-ssh2:build209' runtimeOnly 'net.sourceforge.jexcelapi:jxl:2.5.7' - runtimeOnly 'org.apache.lucene:lucene-analyzers:2.2.0' - runtimeOnly 'org.apache.lucene:lucene-core:2.2.0' + runtimeOnly 'org.apache.lucene:lucene-analyzers:2.9.4' + runtimeOnly 'org.apache.lucene:lucene-core:2.9.4' } jar.enabled = false From 4ae840d3c955e81c9ed6b60bc1175e946ff7cb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Jun 2024 15:17:34 +0200 Subject: [PATCH 019/115] Add reusable workflow for setting up SSH agent --- .github/actions/ssh/action.yml | 42 +++++++++++++++++++++++++++ .github/workflows/stage.yml | 30 +++++++++----------- src/dist/extras/deploy.sh | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 .github/actions/ssh/action.yml create mode 100644 src/dist/extras/deploy.sh diff --git a/.github/actions/ssh/action.yml b/.github/actions/ssh/action.yml new file mode 100644 index 00000000..5c4886ab --- /dev/null +++ b/.github/actions/ssh/action.yml @@ -0,0 +1,42 @@ +name: SSH setup +description: Set up the SSH agent + +inputs: + config: + description: The SSH configuration + required: true + key: + description: The private SSH key + required: true + known-hosts: + description: The list of known hosts + required: true + +runs: + using: composite + + steps: + - name: Configure SSH + shell: sh + env: + CONFIG: ${{ inputs.config }} + KNOWN_HOSTS: ${{ inputs.known-hosts }} + run: | + mkdir -p ~/.ssh + echo "${CONFIG}" > ~/.ssh/config + echo "${KNOWN_HOSTS}" > ~/.ssh/known_hosts + + - name: Start SSH agent + shell: bash + env: + SOCKET: /tmp/ssh-agent.sock + run: | + echo "SSH_AUTH_SOCK=${SOCKET}" >> $GITHUB_ENV + ssh-agent -a ${SOCKET} > /dev/null + + - name: Add SSH key + shell: bash + env: + KEY: ${{ inputs.key }} + run: | + ssh-add - <<< "${KEY}" diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index af3e3b17..97c4961d 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -1,10 +1,6 @@ name: Deploy (Staging) -on: - workflow_dispatch - -env: - SSH_AUTH_SOCK: /tmp/ssh-agent.sock +on: workflow_dispatch jobs: stage: @@ -17,6 +13,13 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set up SSH agent + uses: ./.github/actions/ssh + with: + config: ${{ vars.SSH_CONFIG }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} + - name: Set up Java uses: actions/setup-java@v4 with: @@ -29,22 +32,17 @@ jobs: - name: Build with Gradle run: ./gradlew installDist - - name: Set up SSH agent - run: | - ssh-agent -a $SSH_AUTH_SOCK > /dev/null - ssh-add - <<< "${{ secrets.SSH_PRIVATE_KEY }}" - mkdir -p ~/.ssh - echo '${{ vars.SSH_CONFIG }}' > ~/.ssh/config - echo '${{ vars.KNOWN_HOSTS }}' > ~/.ssh/known_hosts - - name: Publish to staging server run: | - rsync build/install/helma/ antville.dev:/ \ + rsync ./build/install/helma/ antville.dev:./ \ --verbose --archive --delete --compress \ - --filter 'protect /lib/ext' \ + --filter '+ /bin' \ + --filter '+ /extras' \ --filter '+ /launcher.jar' \ + --filter '- /lib/ext' \ --filter '+ /lib' \ - --filter '- /*' \ + --filter '+ /modules' \ + --filter '- /*' - name: Restart Helma run: ssh antville.dev restart diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh new file mode 100644 index 00000000..fa426a8b --- /dev/null +++ b/src/dist/extras/deploy.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Use this script as forced command of an authorized SSH key: +# command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC… + +case "$SSH_ORIGINAL_COMMAND" in + ping) + echo pong + ;; + + deploy-helma) + rsync ./ p3k.org:./ \ + --archive --compress --delete --verbose \ + --filter '+ /bin' \ + --filter '+ /extras' \ + --filter '+ /launcher.jar' \ + --filter '- /lib/ext' \ + --filter '+ /lib' \ + --filter '+ /modules' \ + --filter '- /*' + ;; + + deploy-antville) + rsync ./apps/antville/ p3k.org:./apps/antville/ \ + --archive --compress --delete --verbose \ + --filter '+ /claustra' \ + --filter '+ /code' \ + --filter '+ /compat' \ + --filter '+ /i18n' \ + --filter '+ /lib' \ + --filter '- /*' + rsync ./apps/antville/static/helma/ p3k.org:/var/www/weblogs.at/ \ + --archive --compress --verbose \ + --filter '+ /fonts' \ + --filter '+ /formica.html' \ + --filter '+ /img' \ + --filter '+ /scripts' \ + --filter '+ /styles' \ + --filter '- /*' + ;; + + restart) + printf 'Restarting Helma… ' + sudo /bin/systemctl restart helma + printf '%s\n' 'done.' + ;; + + *) + # Allow any rsync command but restrict it to the installation directory + rrsync -wo /home/helma + ;; +esac From 14ccdf06910f2c131b4070f3abd752a079001f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Jun 2024 20:48:01 +0200 Subject: [PATCH 020/115] Add deployment workflow --- .github/workflows/deploy.yml | 26 ++++++++++++++++++ src/dist/extras/deploy.sh | 52 ------------------------------------ 2 files changed, 26 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/deploy.yml delete mode 100644 src/dist/extras/deploy.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..fb6355e9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,26 @@ +name: Deploy (Production) + +on: + workflow_dispatch: {} + push: + branches: + - helma-🐜 + +jobs: + deploy: + runs-on: ubuntu-latest + + environment: + name: p3k.org + url: https://blog.p3k.org + + steps: + - name: Set up SSH agent + uses: antville/helma/.github/actions/ssh@helma-🐜 + with: + config: ${{ vars.SSH_CONFIG }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} + + - name: Copy files to production server + run: ssh staging-server deploy-helma diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh deleted file mode 100644 index fa426a8b..00000000 --- a/src/dist/extras/deploy.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -# Use this script as forced command of an authorized SSH key: -# command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC… - -case "$SSH_ORIGINAL_COMMAND" in - ping) - echo pong - ;; - - deploy-helma) - rsync ./ p3k.org:./ \ - --archive --compress --delete --verbose \ - --filter '+ /bin' \ - --filter '+ /extras' \ - --filter '+ /launcher.jar' \ - --filter '- /lib/ext' \ - --filter '+ /lib' \ - --filter '+ /modules' \ - --filter '- /*' - ;; - - deploy-antville) - rsync ./apps/antville/ p3k.org:./apps/antville/ \ - --archive --compress --delete --verbose \ - --filter '+ /claustra' \ - --filter '+ /code' \ - --filter '+ /compat' \ - --filter '+ /i18n' \ - --filter '+ /lib' \ - --filter '- /*' - rsync ./apps/antville/static/helma/ p3k.org:/var/www/weblogs.at/ \ - --archive --compress --verbose \ - --filter '+ /fonts' \ - --filter '+ /formica.html' \ - --filter '+ /img' \ - --filter '+ /scripts' \ - --filter '+ /styles' \ - --filter '- /*' - ;; - - restart) - printf 'Restarting Helma… ' - sudo /bin/systemctl restart helma - printf '%s\n' 'done.' - ;; - - *) - # Allow any rsync command but restrict it to the installation directory - rrsync -wo /home/helma - ;; -esac From f2feef4332279a682dc500e1c8486e36c5764ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Jun 2024 22:28:24 +0200 Subject: [PATCH 021/115] Use generic name for the staging server --- .github/workflows/stage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 97c4961d..692beac1 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -34,7 +34,7 @@ jobs: - name: Publish to staging server run: | - rsync ./build/install/helma/ antville.dev:./ \ + rsync ./build/install/helma/ staging-server:./ \ --verbose --archive --delete --compress \ --filter '+ /bin' \ --filter '+ /extras' \ @@ -45,4 +45,4 @@ jobs: --filter '- /*' - name: Restart Helma - run: ssh antville.dev restart + run: ssh staging-server restart From 55dbc0359cbe1207b8b91526db7bc27dd8e4144d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 14 Jun 2024 23:00:48 +0200 Subject: [PATCH 022/115] Revert "Update dependency gradle to v8.8" --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138..b82aa23a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf13..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From def303c0690f92380c476f08e19511679935b2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:19:28 +0200 Subject: [PATCH 023/115] Define Java versions in a more general way --- build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index e5150e09..7fbd71a4 100644 --- a/build.gradle +++ b/build.gradle @@ -17,10 +17,8 @@ def textFiles = ['**/*.hac', '**/.html', '**/*.js', '**/*.md', '**/*.properties' allprojects { apply plugin: 'java' - compileJava { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 repositories { mavenCentral() From 9e870e6cd3cd189491d84af0c24367278b99f21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:23:03 +0200 Subject: [PATCH 024/115] Slightly modify the format of the build date --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7fbd71a4..050ca1c5 100644 --- a/build.gradle +++ b/build.gradle @@ -157,7 +157,7 @@ run { } task processSource(type: Sync) { - def date = new Date().format("MMMM dd, yyyy") + def date = new Date().format("d MMMM yyyy") def gitOutput = new ByteArrayOutputStream() exec { From 84abcde0370e9aa800bec7499c7fb95dce1c6f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:24:17 +0200 Subject: [PATCH 025/115] Update run configuration to always use the correct dependencies --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 050ca1c5..91a5ec0e 100644 --- a/build.gradle +++ b/build.gradle @@ -102,6 +102,8 @@ distributions { } application { + mainClass = 'helma.main.Server' + applicationDistribution.from(projectDir) { include 'modules/**' include 'LICENSE.md' @@ -152,8 +154,8 @@ installDist { } run { - classpath = files('launcher.jar') jvmArgs jettyLogLevel, suppressMacosDockIcon + classpath += fileTree(dir: 'lib/ext', include: '*.jar') } task processSource(type: Sync) { From ffb259a01c4626a30a9d3d5a3db505166fed7599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:37:16 +0200 Subject: [PATCH 026/115] Slightly modify the version string (still a date representation) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 91a5ec0e..0eef6f4d 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ allprojects { } } -version = new Date().format("yyyyMMdd") +version = new Date().format("yy.M.d") tasks.build.dependsOn javadoc, 'jsdoc', 'generateLicenseReport' tasks.compileJava.dependsOn 'processSource' From 45b19e32177b1fa8370093357af87d6a56da5039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:38:04 +0200 Subject: [PATCH 027/115] Reorder the tasks --- build.gradle | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 0eef6f4d..f1618a02 100644 --- a/build.gradle +++ b/build.gradle @@ -76,29 +76,9 @@ def rhinoJar = configurations.library.files.find { jar -> jar.name.startsWith('rhino') } -startScripts { - applicationName = 'helma' - classpath = files('../launcher.jar') - mainClass = 'helma.main.launcher.Main' - - defaultJvmOpts = [jettyLogLevel, suppressMacosDockIcon] - - doLast { - // Work-around to make the classpath above work (launcher.jar is located outside of `lib` dir) - // See https://discuss.gradle.org/t/classpath-in-application-plugin-is-building-always-relative-to-app-home-lib-directory/2012 - def unixScriptFile = file getUnixScript() - def windowsScriptFile = file getWindowsScript() - unixScriptFile.text = unixScriptFile.text.replace('$APP_HOME/lib', '$APP_HOME') - windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib', '%APP_HOME%') - } -} - -distributions { - main { - contents { - from project(':launcher').jar - } - } +run { + jvmArgs jettyLogLevel, suppressMacosDockIcon + classpath += fileTree(dir: 'lib/ext', include: '*.jar') } application { @@ -127,6 +107,31 @@ application { } } +startScripts { + applicationName = 'helma' + classpath = files('../launcher.jar') + mainClass = 'helma.main.launcher.Main' + + defaultJvmOpts = [jettyLogLevel, suppressMacosDockIcon] + + doLast { + // Work-around to make the classpath above work (launcher.jar is located outside of `lib` dir) + // See https://discuss.gradle.org/t/classpath-in-application-plugin-is-building-always-relative-to-app-home-lib-directory/2012 + def unixScriptFile = file getUnixScript() + def windowsScriptFile = file getWindowsScript() + unixScriptFile.text = unixScriptFile.text.replace('$APP_HOME/lib', '$APP_HOME') + windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib', '%APP_HOME%') + } +} + +distributions { + main { + contents { + from project(':launcher').jar + } + } +} + distTar { dependsOn ':generateLicenseReport', ':javadoc', ':jsdoc' @@ -153,11 +158,6 @@ installDist { } } -run { - jvmArgs jettyLogLevel, suppressMacosDockIcon - classpath += fileTree(dir: 'lib/ext', include: '*.jar') -} - task processSource(type: Sync) { def date = new Date().format("d MMMM yyyy") def gitOutput = new ByteArrayOutputStream() From 6401300189b40100d9e230adeff3cb7330409dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 13:02:11 +0200 Subject: [PATCH 028/115] Decouple update task from install Now that Gradle runs Helma with the configured dependencies, updating the installation directory has become less crucial --- README.md | 6 ++++-- build.gradle | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a134485..e93af8d1 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,12 @@ Helma is built with [Gradle](https://gradle.org), the build task depends on the ### Additional Prerequisites -* [Rsync](https://rsync.samba.org) version ≥ 3.1.0 * [Node.js](https://nodejs.org) LTS version +* [Rsync](https://rsync.samba.org) version ≥ 3.1.0 -Clone this repository to your machine and start the build process with `./gradlew install`. The build script is going to ask you if you want to update the installation, enter `yes` or `no`. +Clone this repository to your machine and run Helma with `./gradlew run`. + +To update the installation from a build, run `./gradlew update` and enter `yes` at the prompt. > ⚠️ > Please be aware that this step is going to overwrite files in the installation directory – escpecially at a later time when there might be substantial changes. Should this happen by accident you find the previous installation in the `backups` directory. diff --git a/build.gradle b/build.gradle index f1618a02..e2ee6c4c 100644 --- a/build.gradle +++ b/build.gradle @@ -152,10 +152,6 @@ distZip { installDist { dependsOn build - - if (!System.getenv('CI')) { - finalizedBy 'update' - } } task processSource(type: Sync) { @@ -183,6 +179,8 @@ task processSource(type: Sync) { } task update { + dependsOn installDist + def rsyncArgs = ['--archive', '--filter', '- backups'] def confirm = { From 3e5af064b0e502820dcf4dea1a89d1c9bf0d2b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 14:59:33 +0200 Subject: [PATCH 029/115] Add setup for Gradle debugging in VS Codium --- .vscode/launch.json | 128 ++++++++++++++++---------------------------- .vscode/tasks.json | 66 +++++++++++++++++++++++ build.gradle | 8 +++ 3 files changed, 119 insertions(+), 83 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 8310c621..d1cf813f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,84 +1,46 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Current File", - "request": "launch", - "mainClass": "${file}" - }, - { - "type": "java", - "name": "ImageInfo", - "request": "launch", - "mainClass": "helma.image.ImageInfo", - "projectName": "helma_" - }, - { - "type": "java", - "name": "CommandlineRunner", - "request": "launch", - "mainClass": "helma.main.CommandlineRunner", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Server", - "request": "launch", - "mainClass": "helma.main.Server", - "projectName": "helma_" - }, - { - "type": "java", - "name": "XmlConverter", - "request": "launch", - "mainClass": "helma.objectmodel.dom.XmlConverter", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Crypt", - "request": "launch", - "mainClass": "helma.util.Crypt", - "projectName": "helma_" - }, - { - "type": "java", - "name": "HtmlEncoder", - "request": "launch", - "mainClass": "helma.util.HtmlEncoder", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Logo", - "request": "launch", - "mainClass": "helma.util.Logo", - "projectName": "helma_" - }, - { - "type": "java", - "name": "MarkdownProcessor", - "request": "launch", - "mainClass": "helma.util.MarkdownProcessor", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Commandline", - "request": "launch", - "mainClass": "helma.main.launcher.Commandline", - "projectName": "launcher" - }, - { - "type": "java", - "name": "Main", - "request": "launch", - "mainClass": "helma.main.launcher.Main", - "projectName": "launcher" - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "Run with Gradle", + "request": "launch", + "mainClass": "helma.main.Server", + "projectName": "helma", + "preLaunchTask": "Run with Gradle", + "console": "internalConsole", + "stopOnEntry": false + }, + { + "name": "Debug with Gradle", + "type": "java", + "request": "attach", + "hostName": "localhost", + "port": 5005, + "preLaunchTask": "Debug with Gradle" + }, + { + "type": "java", + "name": "Commandline", + "request": "launch", + "mainClass": "helma.main.launcher.Commandline", + "projectName": "launcher" + }, + { + "type": "java", + "name": "Main", + "request": "launch", + "mainClass": "helma.main.launcher.Main", + "projectName": "launcher" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..78bedb1f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,66 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Run with Gradle", + "type": "shell", + "command": "./gradlew run", + "isBackground": true, + "group": { + "isDefault": true + }, + "problemMatcher": { + "owner": "java", + "fileLocation": "absolute", + "pattern": [ + { + // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) + "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", + "severity": 1, + "message": 2, + "file": 3, + "line": 4 + }, + { + // [2024/06/15 17:26:00] [INFO] [antville-1] INTERNAL:onStart done in 381 millis + "regexp": "^.+INTERNAL:onStart done in \\d+ millis", + "kind": "file", + "file": 0 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "^.+(INTERNAL):onStart done in \\d+ millis", + "endsPattern": "terminated with exit code" + } + } + }, + { + "label": "Debug with Gradle", + "type": "shell", + "command": "./gradlew debug", + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "fileLocation": "absolute", + "pattern": [ + { + // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) + "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", + "severity": 1, + "message": 2, + "file": 3, + "line": 4 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "Listening for transport dt_socket at address", + "endsPattern": "terminated with exit code" + } + } + } + ] +} diff --git a/build.gradle b/build.gradle index e2ee6c4c..84ef732e 100644 --- a/build.gradle +++ b/build.gradle @@ -290,3 +290,11 @@ task commandLine(type: JavaExec) { mainClass = 'helma.main.launcher.Commandline' args '-h', projectDir, function } + +tasks.register('debug', JavaExec) { + group = 'application' + main = 'helma.main.Server' + classpath = sourceSets.main.runtimeClasspath + jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005'] + classpath += fileTree(dir: 'lib/ext', include: '*.jar') +} From 51bc14c3a456c3ff3247cbaae4e619d4b1bd30a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 18:01:30 +0200 Subject: [PATCH 030/115] Remove over-complicated launch and tasks configuration in favor of Gradle plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting run/debug tasks with the plugin works out of the box; one just has to avoid the default “Run and Debug” button. --- .vscode/extensions.json | 3 +- .vscode/launch.json | 46 ---------------------------- .vscode/tasks.json | 66 ----------------------------------------- 3 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0d95f065..c52f6863 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,6 @@ { "recommendations": [ - "vscjava.vscode-java-pack" + "vscjava.vscode-java-pack", + "vscjava.vscode-gradle" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index d1cf813f..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Current File", - "request": "launch", - "mainClass": "${file}" - }, - { - "type": "java", - "name": "Run with Gradle", - "request": "launch", - "mainClass": "helma.main.Server", - "projectName": "helma", - "preLaunchTask": "Run with Gradle", - "console": "internalConsole", - "stopOnEntry": false - }, - { - "name": "Debug with Gradle", - "type": "java", - "request": "attach", - "hostName": "localhost", - "port": 5005, - "preLaunchTask": "Debug with Gradle" - }, - { - "type": "java", - "name": "Commandline", - "request": "launch", - "mainClass": "helma.main.launcher.Commandline", - "projectName": "launcher" - }, - { - "type": "java", - "name": "Main", - "request": "launch", - "mainClass": "helma.main.launcher.Main", - "projectName": "launcher" - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 78bedb1f..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "Run with Gradle", - "type": "shell", - "command": "./gradlew run", - "isBackground": true, - "group": { - "isDefault": true - }, - "problemMatcher": { - "owner": "java", - "fileLocation": "absolute", - "pattern": [ - { - // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) - "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", - "severity": 1, - "message": 2, - "file": 3, - "line": 4 - }, - { - // [2024/06/15 17:26:00] [INFO] [antville-1] INTERNAL:onStart done in 381 millis - "regexp": "^.+INTERNAL:onStart done in \\d+ millis", - "kind": "file", - "file": 0 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "^.+(INTERNAL):onStart done in \\d+ millis", - "endsPattern": "terminated with exit code" - } - } - }, - { - "label": "Debug with Gradle", - "type": "shell", - "command": "./gradlew debug", - "isBackground": true, - "problemMatcher": { - "owner": "custom", - "fileLocation": "absolute", - "pattern": [ - { - // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) - "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", - "severity": 1, - "message": 2, - "file": 3, - "line": 4 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "Listening for transport dt_socket at address", - "endsPattern": "terminated with exit code" - } - } - } - ] -} From 19259162209ddd8abe8ae009cc0e808570d09cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 18:27:30 +0200 Subject: [PATCH 031/115] Bump required minimum Java version to 17 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index b1aa2021..94a72550 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,8 @@ def textFiles = ['**/*.hac', '**/.html', '**/*.js', '**/*.md', '**/*.properties' allprojects { apply plugin: 'java' - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 repositories { mavenCentral() From 82c32bb4482a5c1c442fbb742294c6d02e4c55ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:23:03 +0200 Subject: [PATCH 032/115] Slightly modify the format of the build date --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7fbd71a4..4289728a 100644 --- a/build.gradle +++ b/build.gradle @@ -157,7 +157,7 @@ run { } task processSource(type: Sync) { - def date = new Date().format("MMMM dd, yyyy") + def date = new Date().format("d MMM yyyy") def gitOutput = new ByteArrayOutputStream() exec { From 3a9c14898bbf12c267d1e8b4e08ffe35951fbac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:24:17 +0200 Subject: [PATCH 033/115] Update run configuration to always use the correct dependencies --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4289728a..9274574b 100644 --- a/build.gradle +++ b/build.gradle @@ -102,6 +102,8 @@ distributions { } application { + mainClass = 'helma.main.Server' + applicationDistribution.from(projectDir) { include 'modules/**' include 'LICENSE.md' @@ -152,8 +154,8 @@ installDist { } run { - classpath = files('launcher.jar') jvmArgs jettyLogLevel, suppressMacosDockIcon + classpath += fileTree(dir: 'lib/ext', include: '*.jar') } task processSource(type: Sync) { From ed56cf72f7c1509e2a07503c1b418ce9c7b6b7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:37:16 +0200 Subject: [PATCH 034/115] Slightly modify the version string (still a date representation) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9274574b..026e1380 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ allprojects { } } -version = new Date().format("yyyyMMdd") +version = new Date().format("yy.M.d") tasks.build.dependsOn javadoc, 'jsdoc', 'generateLicenseReport' tasks.compileJava.dependsOn 'processSource' From 196794cd933151343b19fc16bbe75acbe82d4eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 12:38:04 +0200 Subject: [PATCH 035/115] Reorder the tasks --- build.gradle | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 026e1380..70590c86 100644 --- a/build.gradle +++ b/build.gradle @@ -76,29 +76,9 @@ def rhinoJar = configurations.library.files.find { jar -> jar.name.startsWith('rhino') } -startScripts { - applicationName = 'helma' - classpath = files('../launcher.jar') - mainClass = 'helma.main.launcher.Main' - - defaultJvmOpts = [jettyLogLevel, suppressMacosDockIcon] - - doLast { - // Work-around to make the classpath above work (launcher.jar is located outside of `lib` dir) - // See https://discuss.gradle.org/t/classpath-in-application-plugin-is-building-always-relative-to-app-home-lib-directory/2012 - def unixScriptFile = file getUnixScript() - def windowsScriptFile = file getWindowsScript() - unixScriptFile.text = unixScriptFile.text.replace('$APP_HOME/lib', '$APP_HOME') - windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib', '%APP_HOME%') - } -} - -distributions { - main { - contents { - from project(':launcher').jar - } - } +run { + jvmArgs jettyLogLevel, suppressMacosDockIcon + classpath += fileTree(dir: 'lib/ext', include: '*.jar') } application { @@ -127,6 +107,31 @@ application { } } +startScripts { + applicationName = 'helma' + classpath = files('../launcher.jar') + mainClass = 'helma.main.launcher.Main' + + defaultJvmOpts = [jettyLogLevel, suppressMacosDockIcon] + + doLast { + // Work-around to make the classpath above work (launcher.jar is located outside of `lib` dir) + // See https://discuss.gradle.org/t/classpath-in-application-plugin-is-building-always-relative-to-app-home-lib-directory/2012 + def unixScriptFile = file getUnixScript() + def windowsScriptFile = file getWindowsScript() + unixScriptFile.text = unixScriptFile.text.replace('$APP_HOME/lib', '$APP_HOME') + windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib', '%APP_HOME%') + } +} + +distributions { + main { + contents { + from project(':launcher').jar + } + } +} + distTar { dependsOn ':generateLicenseReport', ':javadoc', ':jsdoc' @@ -153,11 +158,6 @@ installDist { } } -run { - jvmArgs jettyLogLevel, suppressMacosDockIcon - classpath += fileTree(dir: 'lib/ext', include: '*.jar') -} - task processSource(type: Sync) { def date = new Date().format("d MMM yyyy") def gitOutput = new ByteArrayOutputStream() From 79b7e8092b6b41c0ba45efa48c6daf2df08f2d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 13:02:11 +0200 Subject: [PATCH 036/115] Decouple update task from install Now that Gradle runs Helma with the configured dependencies, updating the installation directory has become less crucial --- README.md | 6 ++++-- build.gradle | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a134485..e93af8d1 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,12 @@ Helma is built with [Gradle](https://gradle.org), the build task depends on the ### Additional Prerequisites -* [Rsync](https://rsync.samba.org) version ≥ 3.1.0 * [Node.js](https://nodejs.org) LTS version +* [Rsync](https://rsync.samba.org) version ≥ 3.1.0 -Clone this repository to your machine and start the build process with `./gradlew install`. The build script is going to ask you if you want to update the installation, enter `yes` or `no`. +Clone this repository to your machine and run Helma with `./gradlew run`. + +To update the installation from a build, run `./gradlew update` and enter `yes` at the prompt. > ⚠️ > Please be aware that this step is going to overwrite files in the installation directory – escpecially at a later time when there might be substantial changes. Should this happen by accident you find the previous installation in the `backups` directory. diff --git a/build.gradle b/build.gradle index 70590c86..6a6e36be 100644 --- a/build.gradle +++ b/build.gradle @@ -152,10 +152,6 @@ distZip { installDist { dependsOn build - - if (!System.getenv('CI')) { - finalizedBy 'update' - } } task processSource(type: Sync) { @@ -183,6 +179,8 @@ task processSource(type: Sync) { } task update { + dependsOn installDist + def rsyncArgs = ['--archive', '--filter', '- backups'] def confirm = { From 6b694a83ed535e1b9600bcb3babd2340921e52cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 14:59:33 +0200 Subject: [PATCH 037/115] Add setup for Gradle debugging in VS Codium --- .vscode/launch.json | 128 ++++++++++++++++---------------------------- .vscode/tasks.json | 66 +++++++++++++++++++++++ build.gradle | 8 +++ 3 files changed, 119 insertions(+), 83 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 8310c621..d1cf813f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,84 +1,46 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Current File", - "request": "launch", - "mainClass": "${file}" - }, - { - "type": "java", - "name": "ImageInfo", - "request": "launch", - "mainClass": "helma.image.ImageInfo", - "projectName": "helma_" - }, - { - "type": "java", - "name": "CommandlineRunner", - "request": "launch", - "mainClass": "helma.main.CommandlineRunner", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Server", - "request": "launch", - "mainClass": "helma.main.Server", - "projectName": "helma_" - }, - { - "type": "java", - "name": "XmlConverter", - "request": "launch", - "mainClass": "helma.objectmodel.dom.XmlConverter", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Crypt", - "request": "launch", - "mainClass": "helma.util.Crypt", - "projectName": "helma_" - }, - { - "type": "java", - "name": "HtmlEncoder", - "request": "launch", - "mainClass": "helma.util.HtmlEncoder", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Logo", - "request": "launch", - "mainClass": "helma.util.Logo", - "projectName": "helma_" - }, - { - "type": "java", - "name": "MarkdownProcessor", - "request": "launch", - "mainClass": "helma.util.MarkdownProcessor", - "projectName": "helma_" - }, - { - "type": "java", - "name": "Commandline", - "request": "launch", - "mainClass": "helma.main.launcher.Commandline", - "projectName": "launcher" - }, - { - "type": "java", - "name": "Main", - "request": "launch", - "mainClass": "helma.main.launcher.Main", - "projectName": "launcher" - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "Run with Gradle", + "request": "launch", + "mainClass": "helma.main.Server", + "projectName": "helma", + "preLaunchTask": "Run with Gradle", + "console": "internalConsole", + "stopOnEntry": false + }, + { + "name": "Debug with Gradle", + "type": "java", + "request": "attach", + "hostName": "localhost", + "port": 5005, + "preLaunchTask": "Debug with Gradle" + }, + { + "type": "java", + "name": "Commandline", + "request": "launch", + "mainClass": "helma.main.launcher.Commandline", + "projectName": "launcher" + }, + { + "type": "java", + "name": "Main", + "request": "launch", + "mainClass": "helma.main.launcher.Main", + "projectName": "launcher" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..78bedb1f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,66 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Run with Gradle", + "type": "shell", + "command": "./gradlew run", + "isBackground": true, + "group": { + "isDefault": true + }, + "problemMatcher": { + "owner": "java", + "fileLocation": "absolute", + "pattern": [ + { + // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) + "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", + "severity": 1, + "message": 2, + "file": 3, + "line": 4 + }, + { + // [2024/06/15 17:26:00] [INFO] [antville-1] INTERNAL:onStart done in 381 millis + "regexp": "^.+INTERNAL:onStart done in \\d+ millis", + "kind": "file", + "file": 0 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "^.+(INTERNAL):onStart done in \\d+ millis", + "endsPattern": "terminated with exit code" + } + } + }, + { + "label": "Debug with Gradle", + "type": "shell", + "command": "./gradlew debug", + "isBackground": true, + "problemMatcher": { + "owner": "custom", + "fileLocation": "absolute", + "pattern": [ + { + // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) + "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", + "severity": 1, + "message": 2, + "file": 3, + "line": 4 + } + ], + "background": { + "activeOnStart": true, + "beginsPattern": "Listening for transport dt_socket at address", + "endsPattern": "terminated with exit code" + } + } + } + ] +} diff --git a/build.gradle b/build.gradle index 6a6e36be..51f1e798 100644 --- a/build.gradle +++ b/build.gradle @@ -290,3 +290,11 @@ task commandLine(type: JavaExec) { mainClass = 'helma.main.launcher.Commandline' args '-h', projectDir, function } + +tasks.register('debug', JavaExec) { + group = 'application' + main = 'helma.main.Server' + classpath = sourceSets.main.runtimeClasspath + jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005'] + classpath += fileTree(dir: 'lib/ext', include: '*.jar') +} From c1ad40ef72270d24323505892ce003a01c5d7d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 18:01:30 +0200 Subject: [PATCH 038/115] Remove over-complicated launch and tasks configuration in favor of Gradle plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting run/debug tasks with the plugin works out of the box; one just has to avoid the default “Run and Debug” button. --- .vscode/extensions.json | 3 +- .vscode/launch.json | 46 ---------------------------- .vscode/tasks.json | 66 ----------------------------------------- 3 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0d95f065..c52f6863 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,6 @@ { "recommendations": [ - "vscjava.vscode-java-pack" + "vscjava.vscode-java-pack", + "vscjava.vscode-gradle" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index d1cf813f..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Current File", - "request": "launch", - "mainClass": "${file}" - }, - { - "type": "java", - "name": "Run with Gradle", - "request": "launch", - "mainClass": "helma.main.Server", - "projectName": "helma", - "preLaunchTask": "Run with Gradle", - "console": "internalConsole", - "stopOnEntry": false - }, - { - "name": "Debug with Gradle", - "type": "java", - "request": "attach", - "hostName": "localhost", - "port": 5005, - "preLaunchTask": "Debug with Gradle" - }, - { - "type": "java", - "name": "Commandline", - "request": "launch", - "mainClass": "helma.main.launcher.Commandline", - "projectName": "launcher" - }, - { - "type": "java", - "name": "Main", - "request": "launch", - "mainClass": "helma.main.launcher.Main", - "projectName": "launcher" - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 78bedb1f..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "Run with Gradle", - "type": "shell", - "command": "./gradlew run", - "isBackground": true, - "group": { - "isDefault": true - }, - "problemMatcher": { - "owner": "java", - "fileLocation": "absolute", - "pattern": [ - { - // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) - "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", - "severity": 1, - "message": 2, - "file": 3, - "line": 4 - }, - { - // [2024/06/15 17:26:00] [INFO] [antville-1] INTERNAL:onStart done in 381 millis - "regexp": "^.+INTERNAL:onStart done in \\d+ millis", - "kind": "file", - "file": 0 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "^.+(INTERNAL):onStart done in \\d+ millis", - "endsPattern": "terminated with exit code" - } - } - }, - { - "label": "Debug with Gradle", - "type": "shell", - "command": "./gradlew debug", - "isBackground": true, - "problemMatcher": { - "owner": "custom", - "fileLocation": "absolute", - "pattern": [ - { - // [2024/06/15 16:23:22] [ERROR] [antville-1] GET:main.css helma.scripting.ScriptingException: TypeError: Cannot find function getStaticFile in object HopObject Skin. (/home/tobi/Projects/helma/repo/./apps/antville/code/Site/Site.js#474) - "regexp": "^\\[.+\\] \\[(.+)\\] \\[.+\\] \\S+ \\s+: (.+) \\(([^#]+)#(\\d+)\\)$", - "severity": 1, - "message": 2, - "file": 3, - "line": 4 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "Listening for transport dt_socket at address", - "endsPattern": "terminated with exit code" - } - } - } - ] -} From 0f8bace3dd184ee5406c1ef13c502a9b80f5c8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 18:20:36 +0200 Subject: [PATCH 039/115] Keep the lib/ext directory around --- lib/ext/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/ext/.keep diff --git a/lib/ext/.keep b/lib/ext/.keep new file mode 100644 index 00000000..e69de29b From bd70d2fb625a5f83981ca1b680cc5423de37b9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 19:08:12 +0200 Subject: [PATCH 040/115] Disable automatic deployment --- .github/workflows/deploy.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fb6355e9..557fdb16 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,10 +1,6 @@ name: Deploy (Production) -on: - workflow_dispatch: {} - push: - branches: - - helma-🐜 +on: workflow_dispatch jobs: deploy: From 5de4616df076b03673836f42ab5e2c3a10e602b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 19:09:11 +0200 Subject: [PATCH 041/115] Use main website as environment --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 557fdb16..c01702e5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,8 +7,8 @@ jobs: runs-on: ubuntu-latest environment: - name: p3k.org - url: https://blog.p3k.org + name: weblogs.at + url: https://weblogs.at steps: - name: Set up SSH agent From efb7ad89b322d77ab623e1b1005e7f463564de60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 22:43:26 +0200 Subject: [PATCH 042/115] Add static fields for build date and commit hash --- build.gradle | 13 ++++--------- src/main/java/helma/main/Server.java | 8 +++++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 51f1e798..186076f6 100644 --- a/build.gradle +++ b/build.gradle @@ -155,26 +155,21 @@ installDist { } task processSource(type: Sync) { - def date = new Date().format("d MMM yyyy") def gitOutput = new ByteArrayOutputStream() exec { - commandLine 'git', 'describe' + commandLine 'git', 'rev-parse', '--short', 'HEAD' standardOutput = gitOutput errorOutput = new ByteArrayOutputStream() ignoreExitValue = true } - def description = date - def tag = gitOutput.toString().trim() - - // TODO: Implement extended description in Java code - if (tag) description = "$tag; $description" - from 'src' filter { - line -> line.replaceAll('__builddate__', date) + line -> line + .replaceAll('__builddate__', new Date().format("d MMM yyyy")) + .replaceAll('__commithash__', gitOutput.toString().trim()) } into "${project.buildDir}/src" } diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index 4966551c..b747f11e 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -36,7 +36,13 @@ import helma.util.ResourceProperties; */ public class Server implements Runnable { // version string - public static final String version = "🐜 (__builddate__)"; + public static final String version = "🐜"; + + // build date + public static final String buildDate = "__builddate__"; + + // commit hash + public static final String commitHash = "__commithash__"; // static server instance private static Server server; From 87675fd6cd674f8cb24813599e0d9e931a339af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 23:01:45 +0200 Subject: [PATCH 043/115] Fix deprecation warning for Java plugin conventions --- build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 186076f6..d609eb5f 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,10 @@ def textFiles = ['**/*.hac', '**/.html', '**/*.js', '**/*.md', '**/*.properties' allprojects { apply plugin: 'java' - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } repositories { mavenCentral() From 608fd695c443a9c422a25824b3921334894b81e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Jun 2024 23:06:35 +0200 Subject: [PATCH 044/115] Switch to tasks.register() to define custom tasks --- build.gradle | 14 +++++++------- modules/helma/build.gradle | 2 +- modules/jala/build.gradle | 2 +- modules/jala/util/HopKit/build.gradle | 2 +- modules/jala/util/Test/build.gradle | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index d609eb5f..452375fb 100644 --- a/build.gradle +++ b/build.gradle @@ -156,7 +156,7 @@ installDist { dependsOn build } -task processSource(type: Sync) { +tasks.register('processSource', Sync) { def gitOutput = new ByteArrayOutputStream() exec { @@ -175,7 +175,7 @@ task processSource(type: Sync) { } into "${project.buildDir}/src" } -task update { +tasks.register('update') { dependsOn installDist def rsyncArgs = ['--archive', '--filter', '- backups'] @@ -221,7 +221,7 @@ task update { } } -task jsdoc(type: Exec) { +tasks.register('jsdoc', Exec) { description 'Generates JSDoc API documentation for the included JavaScript modules.' group 'Documentation' @@ -235,7 +235,7 @@ task jsdoc(type: Exec) { args = ['jsdoc', '-d', "$destination"].plus(sources) } -task xgettext(type: JavaExec) { +tasks.register('xgettext', JavaExec) { description 'Extracts translatable message strings from source code.' group 'i18n' @@ -252,7 +252,7 @@ task xgettext(type: JavaExec) { ] } -task po2js(type: JavaExec) { +tasks.register('po2js', JavaExec) { description 'Converts translated message strings from PO format to JavaScript.' group 'i18n' @@ -267,7 +267,7 @@ task po2js(type: JavaExec) { ] } -task rhinoShell(type: JavaExec) { +tasks.register('rhinoShell', JavaExec) { description 'Runs the interactive Rhino JavaScript shell.' group 'Application' @@ -279,7 +279,7 @@ task rhinoShell(type: JavaExec) { // Call this task with a function definition using the `-P` parameter, e.g. // `./gradlew commandLine -Pfunction=manage.getAllApplications` -task commandLine(type: JavaExec) { +tasks.register('commandLine', JavaExec) { description 'Runs a function in a Helma application with `-Pfunction=app.functionName`.' group 'Application' diff --git a/modules/helma/build.gradle b/modules/helma/build.gradle index f78f66d4..401dd406 100644 --- a/modules/helma/build.gradle +++ b/modules/helma/build.gradle @@ -12,7 +12,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -task deps(type: Copy) { +tasks.register('deps', Copy) { from sourceSets.main.runtimeClasspath into '.' } diff --git a/modules/jala/build.gradle b/modules/jala/build.gradle index e1ef800f..3b9b6684 100644 --- a/modules/jala/build.gradle +++ b/modules/jala/build.gradle @@ -15,7 +15,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -task deps(type: Copy) { +tasks.register('deps', Copy) { from sourceSets.main.runtimeClasspath into 'lib' } diff --git a/modules/jala/util/HopKit/build.gradle b/modules/jala/util/HopKit/build.gradle index f6b40342..f8c9778e 100644 --- a/modules/jala/util/HopKit/build.gradle +++ b/modules/jala/util/HopKit/build.gradle @@ -10,7 +10,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -task deps(type: Copy) { +tasks.register('deps', Copy) { from sourceSets.main.runtimeClasspath into 'lib' } diff --git a/modules/jala/util/Test/build.gradle b/modules/jala/util/Test/build.gradle index 91015efc..7e596efa 100644 --- a/modules/jala/util/Test/build.gradle +++ b/modules/jala/util/Test/build.gradle @@ -10,7 +10,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -task deps(type: Copy) { +tasks.register('deps', Copy) { from sourceSets.main.runtimeClasspath into 'code' } From a54b27c4aa0246023cbbc4cb34105c8ac21b50ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jul 2024 02:34:32 +0000 Subject: [PATCH 045/115] Update dependency commons-codec:commons-codec to v1.17.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 452375fb..1c46b71e 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ configurations { dependencies { implementation 'com.google.code.gson:gson:2.11.0' - implementation 'commons-codec:commons-codec:1.17.0' + implementation 'commons-codec:commons-codec:1.17.1' implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-logging:commons-logging:1.3.2' implementation 'commons-net:commons-net:3.10.0' From a975930192bdfb4dd28ac67fcf96c1dac041b02f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 3 Aug 2024 22:55:47 +0000 Subject: [PATCH 046/115] Update gradle/actions action to v4 --- .github/workflows/release.yml | 2 +- .github/workflows/stage.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 35333503..59d8f365 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: java-version: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Build with Gradle run: ./gradlew assembleDist diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 692beac1..23080948 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -27,7 +27,7 @@ jobs: java-version: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Build with Gradle run: ./gradlew installDist From 44f23757498a5f6c150e94a93f00edeed82fb1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Thu, 8 Aug 2024 19:35:22 +0200 Subject: [PATCH 047/115] Update URL of stage environment --- .github/workflows/stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 692beac1..4f015093 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -8,7 +8,7 @@ jobs: environment: name: stage - url: https://antville-test.click + url: https://antville-test.online steps: - uses: actions/checkout@v4 From 3365a2ef5837ee929051a5474690ce5bfdc62263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Thu, 8 Aug 2024 23:00:08 +0200 Subject: [PATCH 048/115] Fix ExecReload setting in service configuration --- src/dist/extras/helma.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dist/extras/helma.service b/src/dist/extras/helma.service index 308093aa..7d42310b 100644 --- a/src/dist/extras/helma.service +++ b/src/dist/extras/helma.service @@ -18,7 +18,7 @@ ExecStart = /usr/bin/java -server \ -jar launcher.jar \ -w 8080 -x 8081 -ExecReload = touch apps.properties && touch server.properties +ExecReload = /bin/sh -c 'touch apps.properties && touch server.properties' ExecStop = /bin/kill -15 $MAINPID [Install] From 12e7f298ad63378a8dd77ba9ac1eac7bdeca35cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:27:04 +0000 Subject: [PATCH 049/115] Update plugin com.github.jk1.dependency-license-report to v2.9 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 452375fb..8dc95b84 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.jk1.dependency-license-report' version '2.7' + id 'com.github.jk1.dependency-license-report' version '2.9' } import org.apache.tools.ant.filters.FixCrLfFilter From 65ac2df0ba07d7d186a0bdfe07ede02ed84b4359 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:24:50 +0000 Subject: [PATCH 050/115] Update dependency commons-logging:commons-logging to v1.3.4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 452375fb..52bb8738 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.11.0' implementation 'commons-codec:commons-codec:1.17.0' implementation 'commons-fileupload:commons-fileupload:1.5' - implementation 'commons-logging:commons-logging:1.3.2' + implementation 'commons-logging:commons-logging:1.3.4' implementation 'commons-net:commons-net:3.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' From 3809198380a9806ce8f2a2ca4d84f56ed9167fbc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:04:35 +0000 Subject: [PATCH 051/115] Update Jetty packages to v9.4.56.v20240826 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 452375fb..48888e4f 100644 --- a/build.gradle +++ b/build.gradle @@ -66,8 +66,8 @@ dependencies { implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty:jetty-servlet:9.4.54.v20240208' - implementation 'org.eclipse.jetty:jetty-xml:9.4.54.v20240208' + implementation 'org.eclipse.jetty:jetty-servlet:9.4.56.v20240826' + implementation 'org.eclipse.jetty:jetty-xml:9.4.56.v20240826' implementation 'org.mozilla:rhino:1.7.13' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' From e93c501149ccfa30e1b4598744840a00467403fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:56:06 +0000 Subject: [PATCH 052/115] Update dependency gradle to v8.12 --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 6 ++++-- gradlew.bat | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..cea7a793 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..f3b75f3b 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e4..9b42019c 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From 4ebbcb01ae8d73be14ed97d3f1a8d1282b3b1c75 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 08:07:29 +0000 Subject: [PATCH 053/115] Update dependency org.mozilla:rhino to v1.8.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 452375fb..43519ce0 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.eclipse.jetty:jetty-servlet:9.4.54.v20240208' implementation 'org.eclipse.jetty:jetty-xml:9.4.54.v20240208' - implementation 'org.mozilla:rhino:1.7.13' + implementation 'org.mozilla:rhino:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' implementation 'xmlrpc:xmlrpc:2.0.1' From f7fe09a29454b0fbaaead1817d0f72360c7a6326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 09:53:53 +0100 Subject: [PATCH 054/115] Switch to rhino-all.jar, Helma needs the full Rhino experience --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 43519ce0..e920c689 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.eclipse.jetty:jetty-servlet:9.4.54.v20240208' implementation 'org.eclipse.jetty:jetty-xml:9.4.54.v20240208' - implementation 'org.mozilla:rhino:1.8.0' + implementation 'org.mozilla:rhino-all:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' implementation 'xmlrpc:xmlrpc:2.0.1' From d3098c892fa66bac39852f58546aa9f74c5ffffa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:12:13 +0000 Subject: [PATCH 055/115] Update dependency commons-net:commons-net to v3.11.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 26c32529..fed4da5c 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ dependencies { implementation 'commons-codec:commons-codec:1.17.1' implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-logging:commons-logging:1.3.4' - implementation 'commons-net:commons-net:3.10.0' + implementation 'commons-net:commons-net:3.11.1' implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' From 28887aaccde077a1e2c17f256100b30244d755be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:32:00 +0000 Subject: [PATCH 056/115] Update dependency org.mozilla:rhino to v1.8.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 38eb392b..6bb788b9 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' implementation 'org.eclipse.jetty:jetty-servlet:9.4.56.v20240826' implementation 'org.eclipse.jetty:jetty-xml:9.4.56.v20240826' - implementation 'org.mozilla:rhino:1.7.13' + implementation 'org.mozilla:rhino:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' implementation 'xmlrpc:xmlrpc:2.0.1' From cbb6599ce0e8c3689af8d990cdc9b710e9bab26b Mon Sep 17 00:00:00 2001 From: tobi Date: Fri, 3 Jan 2025 11:46:46 +0000 Subject: [PATCH 057/115] Add Renovate workflow --- .github/workflows/renovate.yml | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/renovate.yml diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml new file mode 100644 index 00000000..2fcf99f1 --- /dev/null +++ b/.github/workflows/renovate.yml @@ -0,0 +1,40 @@ +name: Run Renovate + +on: + workflow_dispatch + #schedule: + # - cron: "13 * * * *" + +jobs: + renovate: + runs-on: antville + + steps: + - uses: actions/checkout@v4 + + - name: Run Renovate + run: npx renovate + env: + # Renovate is using this token to retrieve release notes + GITHUB_COM_TOKEN: ${{ secrets.renovate_github_com_token }} + # See + LOG_LEVEL: info # debug | info | warn | error | fatal + RENOVATE_AUTODISCOVER: 'true' + RENOVATE_CONFIG_FILE: renovate.json + RENOVATE_ENDPOINT: ${{ github.api_url }} + RENOVATE_GIT_AUTHOR: Renovate Bot + #RENOVATE_GIT_IGNORED_AUTHORS: + # - 29139614+renovate[bot]@users.noreply.github.com + RENOVATE_IGNORE_PR_AUTHOR: 'true' + RENOVATE_LOG_FILE: renovate-log.ndjson + RENOVATE_LOG_FILE_LEVEL: debug + RENOVATE_PLATFORM: gitea + RENOVATE_REPOSITORY_CACHE: 'enabled' + # github.token is not working here, it lacks some permissions required by Renovate + RENOVATE_TOKEN: ${{ secrets.renovate_token }} #${{ github.token }} + + - name: Save log file + uses: actions/upload-artifact@v3 + with: + name: renovate-log.ndjson + path: renovate-log.ndjson From 3284a1ca19340b949b769fd6b17250264820856b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 3 Jan 2025 11:57:30 +0000 Subject: [PATCH 058/115] Update actions/upload-artifact action to v4 --- .github/workflows/renovate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 2fcf99f1..27f81ba1 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -34,7 +34,7 @@ jobs: RENOVATE_TOKEN: ${{ secrets.renovate_token }} #${{ github.token }} - name: Save log file - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: renovate-log.ndjson path: renovate-log.ndjson From c1e9371f6bc4614d5f1f5527f87719b44a05a463 Mon Sep 17 00:00:00 2001 From: tobi Date: Fri, 3 Jan 2025 11:59:50 +0000 Subject: [PATCH 059/115] Update .github/workflows/renovate.yml --- .github/workflows/renovate.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 2fcf99f1..f35a2569 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -1,9 +1,8 @@ name: Run Renovate on: - workflow_dispatch - #schedule: - # - cron: "13 * * * *" + schedule: + - cron: "13 * * * *" jobs: renovate: @@ -31,7 +30,7 @@ jobs: RENOVATE_PLATFORM: gitea RENOVATE_REPOSITORY_CACHE: 'enabled' # github.token is not working here, it lacks some permissions required by Renovate - RENOVATE_TOKEN: ${{ secrets.renovate_token }} #${{ github.token }} + RENOVATE_TOKEN: ${{ secrets.renovate_token }} - name: Save log file uses: actions/upload-artifact@v3 From c2b37a8243a6a52e8e0bffeb114198160bd205da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 13:35:33 +0100 Subject: [PATCH 060/115] Update workflows for Forgejo runner --- .github/workflows/deploy.yml | 9 +-------- .github/workflows/release.yml | 17 +++++------------ .github/workflows/stage.yml | 20 ++------------------ 3 files changed, 8 insertions(+), 38 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c01702e5..cdad2c55 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,19 +4,12 @@ on: workflow_dispatch jobs: deploy: - runs-on: ubuntu-latest + runs-on: antville environment: name: weblogs.at url: https://weblogs.at steps: - - name: Set up SSH agent - uses: antville/helma/.github/actions/ssh@helma-🐜 - with: - config: ${{ vars.SSH_CONFIG }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} - - name: Copy files to production server run: ssh staging-server deploy-helma diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59d8f365..b189f260 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ permissions: jobs: build: - runs-on: ubuntu-latest + runs-on: antville env: GH_TOKEN: ${{ github.token }} @@ -19,27 +19,20 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 21 - - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 - - name: Build with Gradle run: ./gradlew assembleDist - name: Create release + # FIXME: Currently only outputs gh command; adapt for Forgejo run: | - gh release create "$GITHUB_REF_NAME" \ + echo gh release create "$GITHUB_REF_NAME" \ --repo "$GITHUB_REPOSITORY" \ --title "$(date +'%d %b %Y')" \ --generate-notes - name: Upload assets + # FIXME: Currently only outputs gh command; adapt for Forgejo run: | - gh release upload "$GITHUB_REF_NAME" \ + echo gh release upload "$GITHUB_REF_NAME" \ build/distributions/helma-*.* \ --clobber diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index eac49cc3..17e693d4 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -4,31 +4,15 @@ on: workflow_dispatch jobs: stage: - runs-on: ubuntu-latest + runs-on: antville environment: name: stage - url: https://antville-test.online + url: ${{ vars.stage_url }} steps: - uses: actions/checkout@v4 - - name: Set up SSH agent - uses: ./.github/actions/ssh - with: - config: ${{ vars.SSH_CONFIG }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - known-hosts: ${{ vars.SSH_KNOWN_HOSTS }} - - - name: Set up Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 21 - - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 - - name: Build with Gradle run: ./gradlew installDist From 66fa98353ee5287aae50a6c864b248ed5f095c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 15:22:23 +0100 Subject: [PATCH 061/115] Add the actual version string to helma.main.Server again --- build.gradle | 1 + src/main/java/helma/main/Server.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 620f953f..abf4287f 100644 --- a/build.gradle +++ b/build.gradle @@ -172,6 +172,7 @@ tasks.register('processSource', Sync) { line -> line .replaceAll('__builddate__', new Date().format("d MMM yyyy")) .replaceAll('__commithash__', gitOutput.toString().trim()) + .replaceAll('__version__', version) } into "${project.buildDir}/src" } diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index b747f11e..90564689 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -36,7 +36,7 @@ import helma.util.ResourceProperties; */ public class Server implements Runnable { // version string - public static final String version = "🐜"; + public static final String version = "__version__"; // build date public static final String buildDate = "__builddate__"; From d10f8d6d90c492533677ffca2a15234905cb0485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 15:22:47 +0100 Subject: [PATCH 062/115] Replace elaborate checks for Java version with single one for Java 11 --- src/main/java/helma/main/Server.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index 90564689..6155de3b 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -151,13 +151,8 @@ public class Server implements Runnable { public static void checkJavaVersion() { String javaVersion = System.getProperty("java.version"); - if ((javaVersion == null) || javaVersion.startsWith("1.5") - || javaVersion.startsWith("1.4") - || javaVersion.startsWith("1.3") - || javaVersion.startsWith("1.2") - || javaVersion.startsWith("1.1") - || javaVersion.startsWith("1.0")) { - System.err.println("This version of Helma requires Java 1.6 or greater."); + if ((javaVersion == null) || !javaVersion.startsWith("11")) { + System.err.println("This version of Helma requires Java 11 or greater."); if (javaVersion == null) { // don't think this will ever happen, but you never know System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); From d18513fb764326d005de1362e7280c04dee76ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 15:50:47 +0100 Subject: [PATCH 063/115] Downgrade upload-artifact action again v4 causes an error --- .github/workflows/renovate.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index e2bab10d..6c163a9d 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -22,7 +22,7 @@ jobs: RENOVATE_CONFIG_FILE: renovate.json RENOVATE_ENDPOINT: ${{ github.api_url }} RENOVATE_GIT_AUTHOR: Renovate Bot - #RENOVATE_GIT_IGNORED_AUTHORS: + #RENOVATE_GIT_IGNORED_AUTHORS: # - 29139614+renovate[bot]@users.noreply.github.com RENOVATE_IGNORE_PR_AUTHOR: 'true' RENOVATE_LOG_FILE: renovate-log.ndjson @@ -33,7 +33,8 @@ jobs: RENOVATE_TOKEN: ${{ secrets.renovate_token }} - name: Save log file - uses: actions/upload-artifact@v4 + # FIXME: v4 of this action causes an error on Forgejo (“You must configure a GitHub token”) + uses: actions/upload-artifact@v3 with: name: renovate-log.ndjson path: renovate-log.ndjson From 6d355fc5bdc443f629c3fdc3998fbcd0d911b58e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 15:55:49 +0100 Subject: [PATCH 064/115] Allow manual trigger of Renovate workflow --- .github/workflows/renovate.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 6c163a9d..230c84e6 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -3,6 +3,7 @@ name: Run Renovate on: schedule: - cron: "13 * * * *" + workflow_dispatch: jobs: renovate: From 1341c241bdde482ddb64f4e853dbe506ca90d86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 15:58:31 +0100 Subject: [PATCH 065/115] Replace Renovate autodiscovery with explicitly setting the repository --- .github/workflows/renovate.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 230c84e6..64b55a82 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -19,7 +19,8 @@ jobs: GITHUB_COM_TOKEN: ${{ secrets.renovate_github_com_token }} # See LOG_LEVEL: info # debug | info | warn | error | fatal - RENOVATE_AUTODISCOVER: 'true' + # Autodiscover is better suited for an extra repo running Renovate on all desired repos + #RENOVATE_AUTODISCOVER: 'true' RENOVATE_CONFIG_FILE: renovate.json RENOVATE_ENDPOINT: ${{ github.api_url }} RENOVATE_GIT_AUTHOR: Renovate Bot @@ -29,6 +30,7 @@ jobs: RENOVATE_LOG_FILE: renovate-log.ndjson RENOVATE_LOG_FILE_LEVEL: debug RENOVATE_PLATFORM: gitea + RENOVATE_REPOSITORIES: ${{ github.repository }} RENOVATE_REPOSITORY_CACHE: 'enabled' # github.token is not working here, it lacks some permissions required by Renovate RENOVATE_TOKEN: ${{ secrets.renovate_token }} From 0fc7d9134858e27223dd32fc82067996754561e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 16:06:15 +0100 Subject: [PATCH 066/115] Always save the Renovate log --- .github/workflows/renovate.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 64b55a82..26dc20ad 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -38,6 +38,7 @@ jobs: - name: Save log file # FIXME: v4 of this action causes an error on Forgejo (“You must configure a GitHub token”) uses: actions/upload-artifact@v3 + if: always() with: name: renovate-log.ndjson path: renovate-log.ndjson From f7add5ec47643ce626986bc37bfc80fd21a9a5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 3 Jan 2025 16:20:01 +0100 Subject: [PATCH 067/115] Looks like setting the LOG_LEVEL variable in the env section does not work Setting it before the npx command does --- .github/workflows/renovate.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 26dc20ad..e470128c 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -13,12 +13,12 @@ jobs: - uses: actions/checkout@v4 - name: Run Renovate - run: npx renovate + # See + # debug | info | warn | error | fatal + run: LOG_LEVEL=info npx renovate env: # Renovate is using this token to retrieve release notes GITHUB_COM_TOKEN: ${{ secrets.renovate_github_com_token }} - # See - LOG_LEVEL: info # debug | info | warn | error | fatal # Autodiscover is better suited for an extra repo running Renovate on all desired repos #RENOVATE_AUTODISCOVER: 'true' RENOVATE_CONFIG_FILE: renovate.json From e2e67cf2cc6ff984da7c62ef9c8b9a45c7cec32c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Mon, 27 Jan 2025 18:13:44 +0000 Subject: [PATCH 068/115] Update dependency commons-codec:commons-codec to v1.18.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index abf4287f..bcae67c6 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ configurations { dependencies { implementation 'com.google.code.gson:gson:2.11.0' - implementation 'commons-codec:commons-codec:1.17.1' + implementation 'commons-codec:commons-codec:1.18.0' implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-logging:commons-logging:1.3.4' implementation 'commons-net:commons-net:3.11.1' From dd9e4733104efcaad8ac8fa8e355db175a44f991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sun, 9 Feb 2025 13:23:21 +0100 Subject: [PATCH 069/115] Fix botched test of required Java version --- src/main/java/helma/main/Server.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index 6155de3b..88d70db7 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -149,12 +149,13 @@ public class Server implements Runnable { * check if we are running on a Java 2 VM - otherwise exit with an error message */ public static void checkJavaVersion() { - String javaVersion = System.getProperty("java.version"); + String javaVersion = System.getProperty("java.version", "0"); + int majorVersion = Integer.parseInt(javaVersion.split("\\.")[0]); - if ((javaVersion == null) || !javaVersion.startsWith("11")) { + if (majorVersion < 11) { System.err.println("This version of Helma requires Java 11 or greater."); - if (javaVersion == null) { // don't think this will ever happen, but you never know + if (majorVersion == 0) { // don't think this will ever happen, but you never know System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); } else { System.err.println("Your Java Runtime is version " + javaVersion + From 45adacd5cddc89883eb895e8590195f6491a5cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 15:25:13 +0100 Subject: [PATCH 070/115] Use name and URL of actual production environment --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cdad2c55..5acc94a2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,8 +7,8 @@ jobs: runs-on: antville environment: - name: weblogs.at - url: https://weblogs.at + name: antville.org + url: https://antville.org steps: - name: Copy files to production server From 156db3ee986efd324b3e50577ec9beafd1107b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 15:25:36 +0100 Subject: [PATCH 071/115] Try Forgejo action to create a release --- .github/workflows/release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b189f260..3716dddf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ name: Release on: + workflow_dispatch: push: tags: - 'v*' @@ -22,6 +23,15 @@ jobs: - name: Build with Gradle run: ./gradlew assembleDist + - uses: actions/forgejo-release@v2 + with: + direction: upload + url: https://code.host.antville.org + token: ${{ github.token }} + release-dir: build/distributions + release-notes-assistant: true + verbose: true + - name: Create release # FIXME: Currently only outputs gh command; adapt for Forgejo run: | From ff4b4b0f0794be5df0f7058a3f5b7063c83d7f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 15:45:49 +0100 Subject: [PATCH 072/115] =?UTF-8?q?Set=20the=20release=20title=20to=20toda?= =?UTF-8?q?y=E2=80=99s=20date=20as=20formatted=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3716dddf..77e08fe3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,8 +3,7 @@ name: Release on: workflow_dispatch: push: - tags: - - 'v*' + tags: '2*' permissions: contents: write @@ -16,6 +15,7 @@ jobs: env: GH_TOKEN: ${{ github.token }} LC_TIME: en_US.UTF-8 + TODAY: $(date +'%d %b %Y') steps: - uses: actions/checkout@v4 @@ -28,6 +28,8 @@ jobs: direction: upload url: https://code.host.antville.org token: ${{ github.token }} + title: ${{ env.TODAY }} + #tag: $(date +'%Y.%m.%d') release-dir: build/distributions release-notes-assistant: true verbose: true From 70337bda407ddad9a28fb384953428ff0fed4e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 15:46:07 +0100 Subject: [PATCH 073/115] Add a custom name for the release workflow --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 77e08fe3..bbb377cf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,8 @@ jobs: - name: Build with Gradle run: ./gradlew assembleDist - - uses: actions/forgejo-release@v2 + - name: Create release + uses: actions/forgejo-release@v2 with: direction: upload url: https://code.host.antville.org From 5bfcd0b6ea1f1147e79d385f44405a45707bac53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 15:46:32 +0100 Subject: [PATCH 074/115] Distinguish the (currently bogus) GitHub release workflows by name --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bbb377cf..52994244 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,7 @@ jobs: release-notes-assistant: true verbose: true - - name: Create release + - name: Create release at GitHub # FIXME: Currently only outputs gh command; adapt for Forgejo run: | echo gh release create "$GITHUB_REF_NAME" \ @@ -43,7 +43,7 @@ jobs: --title "$(date +'%d %b %Y')" \ --generate-notes - - name: Upload assets + - name: Upload release assets to GitHub # FIXME: Currently only outputs gh command; adapt for Forgejo run: | echo gh release upload "$GITHUB_REF_NAME" \ From 94557dd28e481893b5f948bc6d101dd011ef5b91 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 24 Jan 2025 13:14:06 +0000 Subject: [PATCH 075/115] Update dependency gradle to v8.12.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793..e18bc253 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From d1ead6e081fb589693c10a43f17ea421f09ab634 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 10 Jan 2025 19:17:53 +0000 Subject: [PATCH 076/115] Update Jetty packages to v9.4.57.v20241219 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index abf4287f..24fdde85 100644 --- a/build.gradle +++ b/build.gradle @@ -66,8 +66,8 @@ dependencies { implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty:jetty-servlet:9.4.56.v20240826' - implementation 'org.eclipse.jetty:jetty-xml:9.4.56.v20240826' + implementation 'org.eclipse.jetty:jetty-servlet:9.4.57.v20241219' + implementation 'org.eclipse.jetty:jetty-xml:9.4.57.v20241219' implementation 'org.mozilla:rhino-all:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' From b1a14ad87baee8eaada5cdff88df59303175d49f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 8 Feb 2025 03:13:48 +0000 Subject: [PATCH 077/115] Update dependency commons-logging:commons-logging to v1.3.5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 24fdde85..8a00b21c 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.11.0' implementation 'commons-codec:commons-codec:1.17.1' implementation 'commons-fileupload:commons-fileupload:1.5' - implementation 'commons-logging:commons-logging:1.3.4' + implementation 'commons-logging:commons-logging:1.3.5' implementation 'commons-net:commons-net:3.11.1' implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'javax.servlet:javax.servlet-api:4.0.1' From 6f6ea55b7b9220a698d29a167d330e42a2237f42 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 30 Jan 2025 23:13:45 +0000 Subject: [PATCH 078/115] Update dependency com.google.code.gson:gson to v2.12.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8a00b21c..8c71d733 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ configurations { } dependencies { - implementation 'com.google.code.gson:gson:2.11.0' + implementation 'com.google.code.gson:gson:2.12.1' implementation 'commons-codec:commons-codec:1.17.1' implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-logging:commons-logging:1.3.5' From 1bb5a093dadf0c371aa0f227094cbc2a04bf044d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 15 Feb 2025 19:07:37 +0100 Subject: [PATCH 079/115] Re-enable creating the release at Github after install of gh client --- .github/workflows/release.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52994244..f7aa7874 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: runs-on: antville env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} LC_TIME: en_US.UTF-8 TODAY: $(date +'%d %b %Y') @@ -30,22 +30,19 @@ jobs: url: https://code.host.antville.org token: ${{ github.token }} title: ${{ env.TODAY }} - #tag: $(date +'%Y.%m.%d') release-dir: build/distributions release-notes-assistant: true verbose: true - name: Create release at GitHub - # FIXME: Currently only outputs gh command; adapt for Forgejo run: | - echo gh release create "$GITHUB_REF_NAME" \ + gh release create "$GITHUB_REF_NAME" \ --repo "$GITHUB_REPOSITORY" \ - --title "$(date +'%d %b %Y')" \ + --title "${{ env.TODAY }}" \ --generate-notes - name: Upload release assets to GitHub - # FIXME: Currently only outputs gh command; adapt for Forgejo run: | - echo gh release upload "$GITHUB_REF_NAME" \ - build/distributions/helma-*.* \ + gh release upload "$GITHUB_REF_NAME" build/distributions/helma-*.* \ + --repo "$GITHUB_REPOSITORY" \ --clobber From 8212600d409eb6eb275ba7be09760299ab84cfa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 21:42:33 +0100 Subject: [PATCH 080/115] Add deploy script usable with rsync and a restricted SSH key --- src/dist/extras/deploy.sh | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/dist/extras/deploy.sh diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh new file mode 100644 index 00000000..6ebd6bf2 --- /dev/null +++ b/src/dist/extras/deploy.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Use this script as forced command of an authorized SSH key: +# command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC… + +# Define HELMA_HOST and ANTVILLE_HOST in this file +# shellcheck source=/dev/null +. "$HOME"/deploy.env + +case "$SSH_ORIGINAL_COMMAND" in + ping) + echo pong + ;; + + deploy-helma) + rsync ./ "$HELMA_HOST":./ \ + --archive --compress --delete --verbose \ + --filter '+ /bin' \ + --filter '+ /extras' \ + --filter '+ /launcher.jar' \ + --filter '- /lib/ext' \ + --filter '+ /lib' \ + --filter '+ /modules' \ + --filter '- /*' + printf 'Restarting Helma on HELMA_host… ' + ssh "$HELMA_HOST" sudo /bin/systemctl restart helma + ;; + + deploy-antville) + rsync ./apps/antville/ "$ANTVILLE_HOST":./apps/antville/ \ + --archive --compress --delete --verbose \ + --filter '+ /claustra' \ + --filter '+ /code' \ + --filter '+ /compat' \ + --filter '+ /i18n' \ + --filter '+ /lib' \ + --filter '- /*' + rsync ./apps/antville/static/helma/ "$ANTVILLE_HOST":./apps/antville/static/helma/ \ + --archive --compress --verbose \ + --filter '+ /fonts' \ + --filter '+ /formica.html' \ + --filter '+ /img' \ + --filter '+ /scripts' \ + --filter '+ /styles' \ + --filter '- /*' + printf 'Restarting Helma on ANTVILLE_host… ' + ssh "$ANTVILLE_HOST" sudo /bin/systemctl restart helma + ;; + + restart) + printf 'Restarting Helma… ' + sudo /bin/systemctl restart helma + printf '%s\n' 'done.' + ;; + + *) + # Allow any rsync command but restrict it to the installation directory + rrsync -wo /home/helma + ;; +esac From 3a8997ca5c1ca4633178e39233c66080483c8335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 21:58:08 +0100 Subject: [PATCH 081/115] Initial commit --- .github/workflows/build.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..9bf8429b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Build + +on: + push: + paths: + - build.gradle + - settings.gradle + - src/** + - launcher/build.gradle + - launcher/src/** + workflow_dispatch: + +jobs: + build: + runs-on: antville + + strategy: + matrix: + java: [11, 17, 21] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ matrix.java }} + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Compile with Gradle + run: ./gradlew :compileJava From 84333d05cd78ed8f849fccf2f33e9f260e322751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:04:48 +0100 Subject: [PATCH 082/115] Use fully qualified URL for setup-java action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bf8429b..18fde086 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v4 + uses: https://github.com/actions/setup-java@v4 with: distribution: temurin java-version: ${{ matrix.java }} From 2ff29317e57dce8688ea3d3546b623baa34d6446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:09:55 +0100 Subject: [PATCH 083/115] Gradle is installed on the runner --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18fde086..846e2d6f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,8 +27,5 @@ jobs: distribution: temurin java-version: ${{ matrix.java }} - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 - - name: Compile with Gradle run: ./gradlew :compileJava From 6ebdd6aa31e9900af80567faee2b007114b68944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:12:30 +0100 Subject: [PATCH 084/115] Leave aside compiling for different Java versions for now --- .github/workflows/build.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 846e2d6f..47af9523 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,18 +14,8 @@ jobs: build: runs-on: antville - strategy: - matrix: - java: [11, 17, 21] - steps: - uses: actions/checkout@v4 - - name: Set up Java - uses: https://github.com/actions/setup-java@v4 - with: - distribution: temurin - java-version: ${{ matrix.java }} - - name: Compile with Gradle run: ./gradlew :compileJava From 808bc48ab948135234f301fb36daea04456f033a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:13:25 +0100 Subject: [PATCH 085/115] Run the build workflow when itself has changed --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47af9523..69bcdeab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ name: Build on: push: paths: + - .github/workflows/build.yml - build.gradle - settings.gradle - src/** From d9d3c9b863ac90b650a52e86d280f45e2e7b444e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 01:02:27 +0100 Subject: [PATCH 086/115] Add release notes generated with git-cliff --- .github/workflows/release.yml | 23 ++++++++++++---- cliff.toml | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 cliff.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7aa7874..ac8a3d1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,16 +9,27 @@ permissions: contents: write jobs: - build: + release: runs-on: antville env: GH_TOKEN: ${{ secrets.GH_TOKEN }} LC_TIME: en_US.UTF-8 - TODAY: $(date +'%d %b %Y') steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create release notes + id: create_release_notes + run: | + release_notes=$(npx git-cliff@latest --latest) + # Write the release notes as a heredoc to the workflow output + # ⚠️ No white space around `<<` is crucial! + echo "release_notes<<.eot0x03" >> $GITHUB_OUTPUT + echo "$release_notes" >> $GITHUB_OUTPUT + echo ".eot0x03" >> $GITHUB_OUTPUT - name: Build with Gradle run: ./gradlew assembleDist @@ -29,17 +40,17 @@ jobs: direction: upload url: https://code.host.antville.org token: ${{ github.token }} - title: ${{ env.TODAY }} + title: Helma ${{ github.ref_name }} release-dir: build/distributions - release-notes-assistant: true + release-notes: ${{ steps.create_release_notes.outputs.release_notes }} verbose: true - name: Create release at GitHub run: | gh release create "$GITHUB_REF_NAME" \ --repo "$GITHUB_REPOSITORY" \ - --title "${{ env.TODAY }}" \ - --generate-notes + --title "Helma ${{ github.ref_name }}" \ + --notes "${{ steps.create_release_notes.outputs.release_notes }}" - name: Upload release assets to GitHub run: | diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..7832044a --- /dev/null +++ b/cliff.toml @@ -0,0 +1,52 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +trim = true + +header = "## Changes" + +body = """ +{% for group, commits in commits | filter(attribute="merge_commit") | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + * [{{ commit.id | split(pat="") | slice(end=11) | join() }}]\ + (https://code.host.antville.org/antville/helma/commit/{{ commit.id }}) \ + {% if commit.breaking %}**Breaking:** {% endif %}\ + {{ commit.message | split(pat="\\n") | first | upper_first }}\ + {% endfor %} +{% endfor %} + +**Full Changelog:** [{{ previous.version }} → {{ version }}]\ +(https://code.host.antville.org/antville/helma/compare/\ +{{ previous.version | urlencode }}..{{ version | urlencode }})\n\n +""" + +footer = """ +Generated by [git-cliff](https://git-cliff.org/). +""" + +[git] +conventional_commits = false +filter_commits = false +filter_unconventional = false +protect_breaking_commits = false +sort_commits = "newest" +split_commits = false +topo_order = false + +commit_parsers = [ + { message = "^Apply \\d+ suggestion", skip = true }, + { message = "^Merge .*(branch|dependabot|dependency|renovate)", skip = true }, + { message = "^Lock file maintenance", skip = true }, + { message = "yarn\\.lock", skip = true }, + + { message = "^[Ff]ix", group = " 🐛 Bug Fixes" }, + { field = "author.name", pattern = "[Rr]enovate|[Dd]ependabot", group = " 📦 Dependency Updates" }, + { message = "^Merge pull request", group = " 🔀 Merges" }, + { message = ".*", group = " Uncategorized" }, +] From e3a77328375c82c597e3d89e624082fe073070e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:21:42 +0100 Subject: [PATCH 087/115] Escape HTML elements in commit messages --- cliff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cliff.toml b/cliff.toml index 7832044a..755c4ca2 100644 --- a/cliff.toml +++ b/cliff.toml @@ -17,7 +17,7 @@ body = """ * [{{ commit.id | split(pat="") | slice(end=11) | join() }}]\ (https://code.host.antville.org/antville/helma/commit/{{ commit.id }}) \ {% if commit.breaking %}**Breaking:** {% endif %}\ - {{ commit.message | split(pat="\\n") | first | upper_first }}\ + {{ commit.message | split(pat="\\n") | first | upper_first | escape }}\ {% endfor %} {% endfor %} From 8adbd235698eb0115834cfd4b8b949b59da8f041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:32:06 +0100 Subject: [PATCH 088/115] Bump year of copyright notice --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index df5926e7..65dfb884 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # License -Copyright (c) 1999-2008 Helma Project. All rights reserved. +Copyright (c) 1999-2025 Helma Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions From 38181e8e00ff646c97ce63b5ba166240847033a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:32:20 +0100 Subject: [PATCH 089/115] Update repo URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e93af8d1..f8155df0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## TL;DR - Make sure you have Java 11 or higher installed -- Download and unpack the [latest release](https://github.com/antville/helma/releases) +- Download and unpack the [latest release](https://code.host.antville.org/antville/helma/releases) - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Direct your web browser to From de2150693f955b6e2c9f81f2012f5dcb7dd4cf18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 21:42:33 +0100 Subject: [PATCH 090/115] Add deploy script usable with rsync and a restricted SSH key --- src/dist/extras/deploy.sh | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/dist/extras/deploy.sh diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh new file mode 100644 index 00000000..6ebd6bf2 --- /dev/null +++ b/src/dist/extras/deploy.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# Use this script as forced command of an authorized SSH key: +# command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC… + +# Define HELMA_HOST and ANTVILLE_HOST in this file +# shellcheck source=/dev/null +. "$HOME"/deploy.env + +case "$SSH_ORIGINAL_COMMAND" in + ping) + echo pong + ;; + + deploy-helma) + rsync ./ "$HELMA_HOST":./ \ + --archive --compress --delete --verbose \ + --filter '+ /bin' \ + --filter '+ /extras' \ + --filter '+ /launcher.jar' \ + --filter '- /lib/ext' \ + --filter '+ /lib' \ + --filter '+ /modules' \ + --filter '- /*' + printf 'Restarting Helma on HELMA_host… ' + ssh "$HELMA_HOST" sudo /bin/systemctl restart helma + ;; + + deploy-antville) + rsync ./apps/antville/ "$ANTVILLE_HOST":./apps/antville/ \ + --archive --compress --delete --verbose \ + --filter '+ /claustra' \ + --filter '+ /code' \ + --filter '+ /compat' \ + --filter '+ /i18n' \ + --filter '+ /lib' \ + --filter '- /*' + rsync ./apps/antville/static/helma/ "$ANTVILLE_HOST":./apps/antville/static/helma/ \ + --archive --compress --verbose \ + --filter '+ /fonts' \ + --filter '+ /formica.html' \ + --filter '+ /img' \ + --filter '+ /scripts' \ + --filter '+ /styles' \ + --filter '- /*' + printf 'Restarting Helma on ANTVILLE_host… ' + ssh "$ANTVILLE_HOST" sudo /bin/systemctl restart helma + ;; + + restart) + printf 'Restarting Helma… ' + sudo /bin/systemctl restart helma + printf '%s\n' 'done.' + ;; + + *) + # Allow any rsync command but restrict it to the installation directory + rrsync -wo /home/helma + ;; +esac From a3fbf72f3855cfa0c69919d126c9661f985e0f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 21:58:08 +0100 Subject: [PATCH 091/115] Initial commit --- .github/workflows/build.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..9bf8429b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Build + +on: + push: + paths: + - build.gradle + - settings.gradle + - src/** + - launcher/build.gradle + - launcher/src/** + workflow_dispatch: + +jobs: + build: + runs-on: antville + + strategy: + matrix: + java: [11, 17, 21] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ matrix.java }} + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 + + - name: Compile with Gradle + run: ./gradlew :compileJava From bc7894ecc19c54fe91967927c7c2e26180b2c3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:04:48 +0100 Subject: [PATCH 092/115] Use fully qualified URL for setup-java action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bf8429b..18fde086 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v4 + uses: https://github.com/actions/setup-java@v4 with: distribution: temurin java-version: ${{ matrix.java }} From 4c011f1e1baf35a273add96b4574064995ca59bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:09:55 +0100 Subject: [PATCH 093/115] Gradle is installed on the runner --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18fde086..846e2d6f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,8 +27,5 @@ jobs: distribution: temurin java-version: ${{ matrix.java }} - - name: Set up Gradle - uses: gradle/actions/setup-gradle@v3 - - name: Compile with Gradle run: ./gradlew :compileJava From 04b210b464dccb56edb598321ca594a78972913d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:12:30 +0100 Subject: [PATCH 094/115] Leave aside compiling for different Java versions for now --- .github/workflows/build.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 846e2d6f..47af9523 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,18 +14,8 @@ jobs: build: runs-on: antville - strategy: - matrix: - java: [11, 17, 21] - steps: - uses: actions/checkout@v4 - - name: Set up Java - uses: https://github.com/actions/setup-java@v4 - with: - distribution: temurin - java-version: ${{ matrix.java }} - - name: Compile with Gradle run: ./gradlew :compileJava From 9b5cc988ddf3ec06d5dd71d6b0053a6649ea9059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 28 Feb 2025 22:13:25 +0100 Subject: [PATCH 095/115] Run the build workflow when itself has changed --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47af9523..69bcdeab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ name: Build on: push: paths: + - .github/workflows/build.yml - build.gradle - settings.gradle - src/** From 6fc73d2320afcd4711b17ba9d7262e5df1ff00f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 01:02:27 +0100 Subject: [PATCH 096/115] Add release notes generated with git-cliff --- .github/workflows/release.yml | 23 ++++++++++++---- cliff.toml | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 cliff.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7aa7874..ac8a3d1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,16 +9,27 @@ permissions: contents: write jobs: - build: + release: runs-on: antville env: GH_TOKEN: ${{ secrets.GH_TOKEN }} LC_TIME: en_US.UTF-8 - TODAY: $(date +'%d %b %Y') steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create release notes + id: create_release_notes + run: | + release_notes=$(npx git-cliff@latest --latest) + # Write the release notes as a heredoc to the workflow output + # ⚠️ No white space around `<<` is crucial! + echo "release_notes<<.eot0x03" >> $GITHUB_OUTPUT + echo "$release_notes" >> $GITHUB_OUTPUT + echo ".eot0x03" >> $GITHUB_OUTPUT - name: Build with Gradle run: ./gradlew assembleDist @@ -29,17 +40,17 @@ jobs: direction: upload url: https://code.host.antville.org token: ${{ github.token }} - title: ${{ env.TODAY }} + title: Helma ${{ github.ref_name }} release-dir: build/distributions - release-notes-assistant: true + release-notes: ${{ steps.create_release_notes.outputs.release_notes }} verbose: true - name: Create release at GitHub run: | gh release create "$GITHUB_REF_NAME" \ --repo "$GITHUB_REPOSITORY" \ - --title "${{ env.TODAY }}" \ - --generate-notes + --title "Helma ${{ github.ref_name }}" \ + --notes "${{ steps.create_release_notes.outputs.release_notes }}" - name: Upload release assets to GitHub run: | diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..7832044a --- /dev/null +++ b/cliff.toml @@ -0,0 +1,52 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +trim = true + +header = "## Changes" + +body = """ +{% for group, commits in commits | filter(attribute="merge_commit") | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + * [{{ commit.id | split(pat="") | slice(end=11) | join() }}]\ + (https://code.host.antville.org/antville/helma/commit/{{ commit.id }}) \ + {% if commit.breaking %}**Breaking:** {% endif %}\ + {{ commit.message | split(pat="\\n") | first | upper_first }}\ + {% endfor %} +{% endfor %} + +**Full Changelog:** [{{ previous.version }} → {{ version }}]\ +(https://code.host.antville.org/antville/helma/compare/\ +{{ previous.version | urlencode }}..{{ version | urlencode }})\n\n +""" + +footer = """ +Generated by [git-cliff](https://git-cliff.org/). +""" + +[git] +conventional_commits = false +filter_commits = false +filter_unconventional = false +protect_breaking_commits = false +sort_commits = "newest" +split_commits = false +topo_order = false + +commit_parsers = [ + { message = "^Apply \\d+ suggestion", skip = true }, + { message = "^Merge .*(branch|dependabot|dependency|renovate)", skip = true }, + { message = "^Lock file maintenance", skip = true }, + { message = "yarn\\.lock", skip = true }, + + { message = "^[Ff]ix", group = " 🐛 Bug Fixes" }, + { field = "author.name", pattern = "[Rr]enovate|[Dd]ependabot", group = " 📦 Dependency Updates" }, + { message = "^Merge pull request", group = " 🔀 Merges" }, + { message = ".*", group = " Uncategorized" }, +] From fc084f6e525e41b20b0c4bbfe002972aa8d3c80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:21:42 +0100 Subject: [PATCH 097/115] Escape HTML elements in commit messages --- cliff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cliff.toml b/cliff.toml index 7832044a..755c4ca2 100644 --- a/cliff.toml +++ b/cliff.toml @@ -17,7 +17,7 @@ body = """ * [{{ commit.id | split(pat="") | slice(end=11) | join() }}]\ (https://code.host.antville.org/antville/helma/commit/{{ commit.id }}) \ {% if commit.breaking %}**Breaking:** {% endif %}\ - {{ commit.message | split(pat="\\n") | first | upper_first }}\ + {{ commit.message | split(pat="\\n") | first | upper_first | escape }}\ {% endfor %} {% endfor %} From b7543cf6157b3603bbdf79a61013a6c9d53adb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:32:06 +0100 Subject: [PATCH 098/115] Bump year of copyright notice --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index df5926e7..65dfb884 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # License -Copyright (c) 1999-2008 Helma Project. All rights reserved. +Copyright (c) 1999-2025 Helma Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions From c42c0a7a17758a06f4f36e83cbb959cbb2dd1b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sat, 1 Mar 2025 19:32:20 +0100 Subject: [PATCH 099/115] Update repo URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e93af8d1..f8155df0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## TL;DR - Make sure you have Java 11 or higher installed -- Download and unpack the [latest release](https://github.com/antville/helma/releases) +- Download and unpack the [latest release](https://code.host.antville.org/antville/helma/releases) - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Direct your web browser to From 99e8b204fd02c6278bb7f6f0fc0644828f6c3f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Mon, 7 Apr 2025 01:01:19 +0200 Subject: [PATCH 100/115] Bump Java version --- .java-version | 2 +- README.md | 2 +- src/main/java/helma/main/Server.java | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.java-version b/.java-version index 3b5b5d8f..98d9bcb7 100644 --- a/.java-version +++ b/.java-version @@ -1 +1 @@ -11.0 \ No newline at end of file +17 diff --git a/README.md b/README.md index f8155df0..f6438677 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## TL;DR -- Make sure you have Java 11 or higher installed +- Make sure you have Java 17 or higher installed - Download and unpack the [latest release](https://code.host.antville.org/antville/helma/releases) - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Direct your web browser to diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index 88d70db7..d951adae 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -21,6 +21,7 @@ import helma.framework.repository.FileResource; import helma.framework.core.*; import helma.objectmodel.db.DbSource; import helma.util.*; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlrpc.*; @@ -152,8 +153,8 @@ public class Server implements Runnable { String javaVersion = System.getProperty("java.version", "0"); int majorVersion = Integer.parseInt(javaVersion.split("\\.")[0]); - if (majorVersion < 11) { - System.err.println("This version of Helma requires Java 11 or greater."); + if (majorVersion < 17) { + System.err.println("This version of Helma requires Java 17 or greater."); if (majorVersion == 0) { // don't think this will ever happen, but you never know System.err.println("Your Java Runtime did not provide a version number. Please update to a more recent version."); From 2994a4becc41c97707bda88e08f64e3f8379da2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Mon, 7 Apr 2025 01:06:09 +0200 Subject: [PATCH 101/115] =?UTF-8?q?Disable=20Jetty=E2=80=99s=20session=20c?= =?UTF-8?q?ookies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This remediates the exception “Shared scheduler not started” and restores the functionality of enabling an app in apps.properties – see https://code.host.antville.org/antville/helma/pulls/103#issuecomment-1825 --- src/main/java/helma/main/ApplicationManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 7d31b764..02affa2d 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -502,7 +502,9 @@ public class ApplicationManager implements XmlRpcHandler { staticContext.start(); } - appContext = new ServletContextHandler(ServletContextHandler.SESSIONS); + // I hope I am correct assuming Helma does not need Jetty’s session management, but using + // `ServletContextHandler.SESSIONS` causes an exception: Shared scheduler not started + appContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); appContext.setContextPath(pathPattern); context.addHandler(appContext); @@ -544,9 +546,7 @@ public class ApplicationManager implements XmlRpcHandler { // Remap the context paths and start ApplicationManager.this.context.mapContexts(); - // FIXME: Causing java.lang.IllegalStateException: Shared scheduler not started - // Is it necessary, anway? - //this.appContext.start(); + this.appContext.start(); } // register as XML-RPC handler From 36a12effb2ada1f5efe8ab60c35a80dc9e97dac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Mon, 7 Apr 2025 16:56:05 +0200 Subject: [PATCH 102/115] Bump Jetty versions to 12.0.19 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 84d471ed..d5f86709 100644 --- a/build.gradle +++ b/build.gradle @@ -67,8 +67,8 @@ dependencies { implementation 'com.sun.mail:javax.mail:1.6.2' implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' implementation 'org.ccil.cowan.tagsoup:tagsoup:1.2.1' - implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.9' - implementation 'org.eclipse.jetty:jetty-xml:12.0.9' + implementation 'org.eclipse.jetty.ee9:jetty-ee9-servlet:12.0.19' + implementation 'org.eclipse.jetty:jetty-xml:12.0.19' implementation 'org.mozilla:rhino-all:1.8.0' implementation 'org.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' From 436862e87a941c4a6f0152d580e650ce1474b61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Mon, 7 Apr 2025 16:58:35 +0200 Subject: [PATCH 103/115] =?UTF-8?q?Remove=20setting=20of=20=E2=80=9Cempty?= =?UTF-8?q?=E2=80=9D=20base=20resource?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fingers crossed it won’t be missed --- src/main/java/helma/main/ApplicationManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 02affa2d..17915987 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -494,8 +494,6 @@ public class ApplicationManager implements XmlRpcHandler { ContextHandler staticContext = new ContextHandler(); staticContext.setContextPath(staticMountpoint); - // FIXME: Causing java.lang.IllegalArgumentException: Resource String is invalid - //staticContext.setBaseResourceAsString(""); staticContext.setHandler(rhandler); ApplicationManager.this.context.addHandler(staticContext); From 6723df912e671f5f7da4963c40358e2ae549c271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Mon, 7 Apr 2025 17:02:11 +0200 Subject: [PATCH 104/115] Resolve FIXME but without fixing the issue I tried to make this work but it might need a more thorough rewrite that I just cannot do. The worst that can happen is stopping and starting Helma apps adding redundant ServletContextHandlers to the ContextHandlerCollection until Helma is restarted. --- src/main/java/helma/main/ApplicationManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/helma/main/ApplicationManager.java b/src/main/java/helma/main/ApplicationManager.java index 17915987..e699a8d8 100644 --- a/src/main/java/helma/main/ApplicationManager.java +++ b/src/main/java/helma/main/ApplicationManager.java @@ -563,8 +563,8 @@ public class ApplicationManager implements XmlRpcHandler { // unbind from Jetty HTTP server if (ApplicationManager.this.jetty != null) { if (this.appContext != null) { - // FIXME: Causing incompatible types: ServletContextHandler cannot be converted to Handler - // Is it necessary, anyway? + // Adding appContext to the ContextHandlerCollection works (see above) but removing it causes an exception of + // incompatible types: ServletContextHandler cannot be converted to Handler //ApplicationManager.this.context.removeHandler(this.appContext); this.appContext.stop(); this.appContext.destroy(); From e6c974120bef0438facf6feef66ccd8c8c90191d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Tue, 8 Apr 2025 11:48:37 +0200 Subject: [PATCH 105/115] Update .gitigore file for VSC settings --- .gitignore | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e9557b6a..552a74e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,12 @@ -.gradle -.idea -.settings +.* + +.vscode/* +!.vscode +!.vscode/extensions.json +!.vscode/launch.json +!.vscode/settings.json +!.vscode/tasks.json + build /apps @@ -15,8 +21,8 @@ build /static /*.properties +!/gradle.properties + /launcher.jar /passwd /start.* - -!/gradle.properties From 8caf790529de288e92a3e5e194557aa2886b9ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Tue, 8 Apr 2025 11:50:21 +0200 Subject: [PATCH 106/115] Remove custom configuration of Gradle sourceSets Using the sources in build creates a lot of confusion in VSC --- build.gradle | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build.gradle b/build.gradle index 9bde766c..63d5400e 100644 --- a/build.gradle +++ b/build.gradle @@ -42,15 +42,6 @@ if (JavaVersion.current().isJava8Compatible()) { } } -sourceSets { - main { - java { - // Sources in `src` will be available here after processing - srcDirs = ["$buildDir/src/main/java"] - } - } -} - configurations { // Wrapping implementation because it does not allow access to its files // (i.e. cannot be resolved) From f786b40961fabc009eafa3a276c037563bdb104c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Tue, 8 Apr 2025 11:52:11 +0200 Subject: [PATCH 107/115] Rename the modules project to prevent VSC from renaming the main project to helma_ Does not work, unfortunately --- settings.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/settings.gradle b/settings.gradle index c6fe1184..5fd2dc60 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,3 +16,6 @@ project(':modules').projectDir = file('modules/helma') project(':jala').projectDir = file('modules/jala') project(':hopKit').projectDir = file('modules/jala/util/HopKit') project(':test').projectDir = file('modules/jala/util/Test') + +// Rename this project to prevent redundancy and renaming of main project (VSC does not care, though) +project(':modules').name = 'modules' From 96f2dce50fcc96764954bd291d093ea5daa0cbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Tue, 8 Apr 2025 12:05:54 +0200 Subject: [PATCH 108/115] Add launch configuration for debugging Helma --- .vscode/launch.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..b9116072 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "Debug", + "request": "launch", + "mainClass": "helma.main.Server", + "projectName": "helma_" + } + ] +} From 6b88318bcdbdb78427499ae36f984872059e11da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 11 Apr 2025 11:44:35 +0200 Subject: [PATCH 109/115] Fix regression of Java sources not being processed before compiling --- build.gradle | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 63d5400e..25eef9d1 100644 --- a/build.gradle +++ b/build.gradle @@ -147,9 +147,11 @@ installDist { dependsOn build } -tasks.register('processSource', Sync) { +def processSource = tasks.register('processSource', Sync) { def gitOutput = new ByteArrayOutputStream() + outputs.dir "${project.buildDir}/src" + exec { commandLine 'git', 'rev-parse', '--short', 'HEAD' standardOutput = gitOutput @@ -164,9 +166,11 @@ tasks.register('processSource', Sync) { .replaceAll('__builddate__', new Date().format("d MMM yyyy")) .replaceAll('__commithash__', gitOutput.toString().trim()) .replaceAll('__version__', version) - } into "${project.buildDir}/src" + } into outputs.files.singleFile } +tasks.compileJava.source = processSource.map { it.outputs.files } + tasks.register('update') { dependsOn installDist From c4abd27ac7be8446a0e7e08625092e555c5b0f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Thu, 10 Apr 2025 23:40:49 +0200 Subject: [PATCH 110/115] Make deploy script executable --- src/dist/extras/deploy.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 src/dist/extras/deploy.sh diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh old mode 100644 new mode 100755 From 27cdc5104bc773998cb5bb05198de45996e47d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Fri, 11 Apr 2025 20:51:55 +0200 Subject: [PATCH 111/115] Reorganize and refurbish .gitignore file --- .gitignore | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 552a74e2..7bf7bcbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ +# Generally ignore hidden files .* +# Manage some Codium configuration .vscode/* !.vscode !.vscode/extensions.json @@ -7,22 +9,22 @@ !.vscode/settings.json !.vscode/tasks.json -build - -/apps +# Ignore files created during build or run /bin /backups -/db +build /docs -/extras /lib /licenses /log + +# Ignore files managed in src/dist +/*.properties +/apps +/db +/extras +/launcher.jar /static -/*.properties +# Manage Gradle configuration !/gradle.properties - -/launcher.jar -/passwd -/start.* From 1001b3b5032ca19a28e6104a448043fb77803214 Mon Sep 17 00:00:00 2001 From: tobi Date: Sat, 24 May 2025 19:14:30 +0000 Subject: [PATCH 112/115] Replace hard-coded hostname with input --- .github/workflows/deploy.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5acc94a2..5a011f69 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,15 +1,18 @@ name: Deploy (Production) -on: workflow_dispatch +on: + workflow_dispatch: + inputs: + hostname: + description: Hostname + type: string + required: true + default: antville.org jobs: deploy: runs-on: antville - environment: - name: antville.org - url: https://antville.org - steps: - name: Copy files to production server - run: ssh staging-server deploy-helma + run: ssh ${{ inputs.hostname }} deploy-helma From f6668636a97de0f8e9450d6c9c8990796d7a045e Mon Sep 17 00:00:00 2001 From: tobi Date: Sat, 24 May 2025 19:25:08 +0000 Subject: [PATCH 113/115] Replace hard-coded hostname with input --- .github/workflows/stage.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml index 17e693d4..94e991cf 100644 --- a/.github/workflows/stage.yml +++ b/.github/workflows/stage.yml @@ -1,6 +1,13 @@ name: Deploy (Staging) -on: workflow_dispatch +on: + workflow_dispatch: + inputs: + hostname: + description: Hostname + type: string + required: true + default: antville.org jobs: stage: @@ -8,7 +15,7 @@ jobs: environment: name: stage - url: ${{ vars.stage_url }} + url: ${{ inputs.hostname }} steps: - uses: actions/checkout@v4 @@ -16,9 +23,9 @@ jobs: - name: Build with Gradle run: ./gradlew installDist - - name: Publish to staging server + - name: Copy build files to server run: | - rsync ./build/install/helma/ staging-server:./ \ + rsync ./build/install/helma/ ${{ inputs.hostname }}:./ \ --verbose --archive --delete --compress \ --filter '+ /bin' \ --filter '+ /extras' \ @@ -29,4 +36,4 @@ jobs: --filter '- /*' - name: Restart Helma - run: ssh staging-server restart + run: ssh ${{ inputs.hostname }} restart From 3f2bf9c3dc0a785d6d045d8a33bc4799c76ca34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobi=20Sch=C3=A4fer?= Date: Sun, 25 May 2025 17:00:10 +0200 Subject: [PATCH 114/115] Simplify repository workflows * Use deploy workflow for staging, too * Reduce deploy.sh script --- .github/workflows/deploy.yml | 31 +++++++++++++++++++++++----- .github/workflows/stage.yml | 39 ------------------------------------ src/dist/extras/deploy.sh | 39 ------------------------------------ 3 files changed, 26 insertions(+), 83 deletions(-) delete mode 100644 .github/workflows/stage.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5a011f69..9eeb14b0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,6 +1,6 @@ -name: Deploy (Production) +name: Deploy -on: +on: workflow_dispatch: inputs: hostname: @@ -10,9 +10,30 @@ on: default: antville.org jobs: - deploy: + stage: runs-on: antville + environment: + name: production + url: ${{ inputs.hostname }} + steps: - - name: Copy files to production server - run: ssh ${{ inputs.hostname }} deploy-helma + - uses: actions/checkout@v4 + + - name: Build with Gradle + run: ./gradlew installDist + + - name: Copy build files to server + run: | + rsync ./build/install/helma/ ${{ inputs.hostname }}:./ \ + --verbose --archive --delete --compress \ + --filter '+ /bin' \ + --filter '+ /extras' \ + --filter '+ /launcher.jar' \ + --filter '- /lib/ext' \ + --filter '+ /lib' \ + --filter '+ /modules' \ + --filter '- /*' + + - name: Restart Helma + run: ssh ${{ inputs.hostname }} restart diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml deleted file mode 100644 index 94e991cf..00000000 --- a/.github/workflows/stage.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Deploy (Staging) - -on: - workflow_dispatch: - inputs: - hostname: - description: Hostname - type: string - required: true - default: antville.org - -jobs: - stage: - runs-on: antville - - environment: - name: stage - url: ${{ inputs.hostname }} - - steps: - - uses: actions/checkout@v4 - - - name: Build with Gradle - run: ./gradlew installDist - - - name: Copy build files to server - run: | - rsync ./build/install/helma/ ${{ inputs.hostname }}:./ \ - --verbose --archive --delete --compress \ - --filter '+ /bin' \ - --filter '+ /extras' \ - --filter '+ /launcher.jar' \ - --filter '- /lib/ext' \ - --filter '+ /lib' \ - --filter '+ /modules' \ - --filter '- /*' - - - name: Restart Helma - run: ssh ${{ inputs.hostname }} restart diff --git a/src/dist/extras/deploy.sh b/src/dist/extras/deploy.sh index 6ebd6bf2..869cf945 100755 --- a/src/dist/extras/deploy.sh +++ b/src/dist/extras/deploy.sh @@ -3,50 +3,11 @@ # Use this script as forced command of an authorized SSH key: # command="/home/helma/extras/deploy.sh" ssh-ed25519 AAAAC3NzaC… -# Define HELMA_HOST and ANTVILLE_HOST in this file -# shellcheck source=/dev/null -. "$HOME"/deploy.env - case "$SSH_ORIGINAL_COMMAND" in ping) echo pong ;; - deploy-helma) - rsync ./ "$HELMA_HOST":./ \ - --archive --compress --delete --verbose \ - --filter '+ /bin' \ - --filter '+ /extras' \ - --filter '+ /launcher.jar' \ - --filter '- /lib/ext' \ - --filter '+ /lib' \ - --filter '+ /modules' \ - --filter '- /*' - printf 'Restarting Helma on HELMA_host… ' - ssh "$HELMA_HOST" sudo /bin/systemctl restart helma - ;; - - deploy-antville) - rsync ./apps/antville/ "$ANTVILLE_HOST":./apps/antville/ \ - --archive --compress --delete --verbose \ - --filter '+ /claustra' \ - --filter '+ /code' \ - --filter '+ /compat' \ - --filter '+ /i18n' \ - --filter '+ /lib' \ - --filter '- /*' - rsync ./apps/antville/static/helma/ "$ANTVILLE_HOST":./apps/antville/static/helma/ \ - --archive --compress --verbose \ - --filter '+ /fonts' \ - --filter '+ /formica.html' \ - --filter '+ /img' \ - --filter '+ /scripts' \ - --filter '+ /styles' \ - --filter '- /*' - printf 'Restarting Helma on ANTVILLE_host… ' - ssh "$ANTVILLE_HOST" sudo /bin/systemctl restart helma - ;; - restart) printf 'Restarting Helma… ' sudo /bin/systemctl restart helma From df28d406457290d9f02310e0a5177fe7cff9e77c Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 22 May 2025 14:14:07 +0000 Subject: [PATCH 115/115] Update dependency gradle to v8.14.1 --- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 6 +++--- gradlew.bat | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 34943 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

Gn4F+B~IivciU9^t0j-Mgao3 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 DDw4oP diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e18bc253..002b867c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f3b75f3b..23d15a93 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -205,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c..5eed7ee8 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell