diff --git a/.github/actions/ssh/action.yml b/.github/actions/ssh/action.yml deleted file mode 100644 index 5c4886ab..00000000 --- a/.github/actions/ssh/action.yml +++ /dev/null @@ -1,42 +0,0 @@ -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/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index cdad2c55..00000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Deploy (Production) - -on: workflow_dispatch - -jobs: - deploy: - runs-on: antville - - environment: - name: weblogs.at - url: https://weblogs.at - - steps: - - 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 b189f260..35333503 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ permissions: jobs: build: - runs-on: antville + runs-on: ubuntu-latest env: GH_TOKEN: ${{ github.token }} @@ -19,20 +19,27 @@ 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@v3 + - name: Build with Gradle run: ./gradlew assembleDist - name: Create release - # 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')" \ --generate-notes - name: Upload assets - # FIXME: Currently only outputs gh command; adapt for Forgejo run: | - echo gh release upload "$GITHUB_REF_NAME" \ + gh release upload "$GITHUB_REF_NAME" \ build/distributions/helma-*.* \ --clobber diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml deleted file mode 100644 index 847df5c7..00000000 --- a/.github/workflows/renovate.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Run Renovate - -on: - schedule: - - cron: "13 * * * *" - workflow_dispatch: - -jobs: - renovate: - runs-on: antville - - steps: - - uses: actions/checkout@v4 - - - name: Run 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 }} - # 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_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 }} - - - 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 diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml deleted file mode 100644 index 17e693d4..00000000 --- a/.github/workflows/stage.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Deploy (Staging) - -on: workflow_dispatch - -jobs: - stage: - runs-on: antville - - environment: - name: stage - url: ${{ vars.stage_url }} - - steps: - - uses: actions/checkout@v4 - - - name: Build with Gradle - run: ./gradlew installDist - - - name: Publish to staging server - run: | - rsync ./build/install/helma/ staging-server:./ \ - --verbose --archive --delete --compress \ - --filter '+ /bin' \ - --filter '+ /extras' \ - --filter '+ /launcher.jar' \ - --filter '- /lib/ext' \ - --filter '+ /lib' \ - --filter '+ /modules' \ - --filter '- /*' - - - name: Restart Helma - run: ssh staging-server restart diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 00000000..254d9892 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,50 @@ +name: Staging + +on: + workflow_dispatch + +env: + SSH_AUTH_SOCK: /tmp/ssh-agent.sock + +jobs: + install: + runs-on: ubuntu-latest + + environment: + name: staging + url: https://antville-test.click + + 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 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:/ \ + --verbose --archive --delete --compress \ + --filter '+ launcher.jar' \ + --filter '+ lib' \ + --filter '+ *.jar' \ + --filter '- *' \ + + - name: Restart Helma + run: ssh antville.dev restart diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c52f6863..0d95f065 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,5 @@ { "recommendations": [ - "vscjava.vscode-java-pack", - "vscjava.vscode-gradle" + "vscjava.vscode-java-pack" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..8310c621 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,84 @@ +{ + // 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 diff --git a/README.md b/README.md index e93af8d1..4046dbc5 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://github.com/antville/helma/releases) - Invoke `./bin/helma`, resp. `./bin/helma.bat`, depending on your platform - Direct your web browser to @@ -21,9 +21,9 @@ Although Helma became a Grande Dame of server-side JavaScript already decades ag ## System Requirements -You need a Java virtual machine version 11 or higher to run Helma. +You need a Java virtual machine version 17 or higher to run Helma. -Please consult the documentation of your platform how to obtain and install Java. +Please consult the documentation of your platform on how to obtain and install Java. You also can directly download a [Java runtime or development kit](https://www.oracle.com/java/technologies/javase-downloads.html#javasejdk) from Oracle. @@ -33,12 +33,10 @@ Helma is built with [Gradle](https://gradle.org), the build task depends on the ### Additional Prerequisites -* [Node.js](https://nodejs.org) LTS version * [Rsync](https://rsync.samba.org) version ≥ 3.1.0 +* [Node.js](https://nodejs.org) LTS version -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. +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. diff --git a/build.gradle b/build.gradle index abf4287f..99434d44 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.jk1.dependency-license-report' version '2.9' + id 'com.github.jk1.dependency-license-report' version '2.7' } import org.apache.tools.ant.filters.FixCrLfFilter @@ -17,9 +17,9 @@ def textFiles = ['**/*.hac', '**/.html', '**/*.js', '**/*.md', '**/*.properties' allprojects { apply plugin: 'java' - java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + compileJava { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } repositories { @@ -27,7 +27,7 @@ allprojects { } } -version = new Date().format("yy.M.d") +version = new Date().format("yyyyMMdd") tasks.build.dependsOn javadoc, 'jsdoc', 'generateLicenseReport' tasks.compileJava.dependsOn 'processSource' @@ -59,16 +59,16 @@ 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.17.0' implementation 'commons-fileupload:commons-fileupload:1.5' - implementation 'commons-logging:commons-logging:1.3.4' - implementation 'commons-net:commons-net:3.11.1' + 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 '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-all:1.8.0' + 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.sejda.imageio:webp-imageio:0.1.6' implementation 'xerces:xercesImpl:2.12.2' implementation 'xmlrpc:xmlrpc:2.0.1' @@ -78,37 +78,6 @@ def rhinoJar = configurations.library.files.find { jar -> jar.name.startsWith('rhino') } -run { - jvmArgs jettyLogLevel, suppressMacosDockIcon - classpath += fileTree(dir: 'lib/ext', include: '*.jar') -} - -application { - mainClass = 'helma.main.Server' - - applicationDistribution.from(projectDir) { - include 'modules/**' - include 'LICENSE.md' - include 'README.md' - include 'start.*' - } - - applicationDistribution.from(javadoc.destinationDir) { - include '**' - into 'docs/javadoc' - } - - applicationDistribution.from("${project.buildDir}/docs/jsdoc") { - include '**' - into 'docs/jsdoc' - } - - applicationDistribution.from("${project.buildDir}/reports/dependency-license") { - include '**' - into 'licenses' - } -} - startScripts { applicationName = 'helma' classpath = files('../launcher.jar') @@ -134,6 +103,30 @@ distributions { } } +application { + applicationDistribution.from(projectDir) { + include 'modules/**' + include 'LICENSE.md' + include 'README.md' + include 'start.*' + } + + applicationDistribution.from(javadoc.destinationDir) { + include '**' + into 'docs/javadoc' + } + + applicationDistribution.from("${project.buildDir}/docs/jsdoc") { + include '**' + into 'docs/jsdoc' + } + + applicationDistribution.from("${project.buildDir}/reports/dependency-license") { + include '**' + into 'licenses' + } +} + distTar { dependsOn ':generateLicenseReport', ':javadoc', ':jsdoc' @@ -154,31 +147,42 @@ distZip { installDist { dependsOn build + + if (!System.getenv('CI')) { + finalizedBy 'update' + } } -tasks.register('processSource', Sync) { +run { + classpath = files('launcher.jar') + jvmArgs jettyLogLevel, suppressMacosDockIcon +} + +task processSource(type: Sync) { + def date = new Date().format("MMMM dd, yyyy") def gitOutput = new ByteArrayOutputStream() exec { - commandLine 'git', 'rev-parse', '--short', 'HEAD' + commandLine 'git', 'describe' 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__', new Date().format("d MMM yyyy")) - .replaceAll('__commithash__', gitOutput.toString().trim()) - .replaceAll('__version__', version) + line -> line.replaceAll('__builddate__', date) } into "${project.buildDir}/src" } -tasks.register('update') { - dependsOn installDist - +task update { def rsyncArgs = ['--archive', '--filter', '- backups'] def confirm = { @@ -222,7 +226,7 @@ tasks.register('update') { } } -tasks.register('jsdoc', Exec) { +task jsdoc(type: Exec) { description 'Generates JSDoc API documentation for the included JavaScript modules.' group 'Documentation' @@ -236,7 +240,7 @@ tasks.register('jsdoc', Exec) { args = ['jsdoc', '-d', "$destination"].plus(sources) } -tasks.register('xgettext', JavaExec) { +task xgettext(type: JavaExec) { description 'Extracts translatable message strings from source code.' group 'i18n' @@ -253,7 +257,7 @@ tasks.register('xgettext', JavaExec) { ] } -tasks.register('po2js', JavaExec) { +task po2js(type: JavaExec) { description 'Converts translated message strings from PO format to JavaScript.' group 'i18n' @@ -268,7 +272,7 @@ tasks.register('po2js', JavaExec) { ] } -tasks.register('rhinoShell', JavaExec) { +task rhinoShell(type: JavaExec) { description 'Runs the interactive Rhino JavaScript shell.' group 'Application' @@ -280,7 +284,7 @@ tasks.register('rhinoShell', JavaExec) { // Call this task with a function definition using the `-P` parameter, e.g. // `./gradlew commandLine -Pfunction=manage.getAllApplications` -tasks.register('commandLine', JavaExec) { +task commandLine(type: JavaExec) { description 'Runs a function in a Helma application with `-Pfunction=app.functionName`.' group 'Application' @@ -288,11 +292,3 @@ tasks.register('commandLine', 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') -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b95..e6441136 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793..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.12-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 f3b75f3b..1aa94a42 100755 --- a/gradlew +++ b/gradlew @@ -15,8 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# SPDX-License-Identifier: Apache-2.0 -# ############################################################################## # @@ -57,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/. @@ -86,7 +84,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 -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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 9b42019c..7101f8e4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,6 @@ @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 ########################################################################## diff --git a/lib/ext/.keep b/lib/ext/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/helma/build.gradle b/modules/helma/build.gradle index 401dd406..f78f66d4 100644 --- a/modules/helma/build.gradle +++ b/modules/helma/build.gradle @@ -12,7 +12,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -tasks.register('deps', Copy) { +task deps(type: Copy) { from sourceSets.main.runtimeClasspath into '.' } diff --git a/modules/jala/build.gradle b/modules/jala/build.gradle index 3b9b6684..e1ef800f 100644 --- a/modules/jala/build.gradle +++ b/modules/jala/build.gradle @@ -15,7 +15,7 @@ processResources.enabled = false processTestResources.enabled = false test.enabled = false -tasks.register('deps', Copy) { +task deps(type: Copy) { from sourceSets.main.runtimeClasspath into 'lib' } diff --git a/modules/jala/util/HopKit/build.gradle b/modules/jala/util/HopKit/build.gradle index f8c9778e..f6b40342 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 -tasks.register('deps', Copy) { +task deps(type: Copy) { from sourceSets.main.runtimeClasspath into 'lib' } diff --git a/modules/jala/util/Test/build.gradle b/modules/jala/util/Test/build.gradle index 7e596efa..91015efc 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 -tasks.register('deps', Copy) { +task deps(type: Copy) { from sourceSets.main.runtimeClasspath into 'code' } diff --git a/src/dist/extras/helma.service b/src/dist/extras/helma.service index 7d42310b..308093aa 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 = /bin/sh -c 'touch apps.properties && touch server.properties' +ExecReload = touch apps.properties && touch server.properties ExecStop = /bin/kill -15 $MAINPID [Install] diff --git a/src/main/java/helma/main/Server.java b/src/main/java/helma/main/Server.java index 6155de3b..4966551c 100644 --- a/src/main/java/helma/main/Server.java +++ b/src/main/java/helma/main/Server.java @@ -36,13 +36,7 @@ import helma.util.ResourceProperties; */ public class Server implements Runnable { // version string - public static final String version = "__version__"; - - // build date - public static final String buildDate = "__builddate__"; - - // commit hash - public static final String commitHash = "__commithash__"; + public static final String version = "🐜 (__builddate__)"; // static server instance private static Server server; @@ -151,8 +145,13 @@ public class Server implements Runnable { public static void checkJavaVersion() { String javaVersion = System.getProperty("java.version"); - if ((javaVersion == null) || !javaVersion.startsWith("11")) { - System.err.println("This version of Helma requires Java 11 or greater."); + 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) { // 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.");