diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dab3dab..11af821 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,13 +31,13 @@ jobs: run: ant -DluceeVersionQuery="6/all/jar" -Dexecute="/debug.cfm" - name: Run Lucee 6 Stable - run: ant -DluceeVersion="6.0.3.1" -Dexecute="/debug.cfm" -Dtruth="cfml rocks" -Dauthor="Zac Spitzer" + run: ant -DluceeVersion="6.2.2.91" -Dexecute="/debug.cfm" -Dtruth="cfml rocks" -Dauthor="Zac Spitzer" - name: Run Lucee 5 (using Lucee light, no extensions) run: ant -DluceeVersion="light-5.4.2.17" -Dexecute="/debug.cfm" - name: Run Lucee 6 (using Lucee zero, no extensions, no admin, no docs) - run: ant -DluceeVersion="zero-6.0.3.1" -Dexecute="/debug.cfm" + run: ant -DluceeVersion="zero-6.2.2.91" -Dexecute="/debug.cfm" - name: Run Latest Lucee 5 RC Light run: ant -DluceeVersionQuery="5/rc/light" -Dexecute="/debug.cfm" @@ -48,3 +48,9 @@ jobs: - name: Run Latest Stable Lucee 5, compile webroot (invalid code) continue-on-error: true run: ant -DluceeVersionQuery="5/stable/jar" -Dexecute="/index.cfm" -Dcompile="true" -Dwebroot="${{ github.workspace }}/sampleBad/" + + - name: Test concurrent execution with unique working directories + run: | + ant -DuniqueWorkingDir="true" -Dexecute="/debug.cfm" & + ant -DuniqueWorkingDir="true" -Dexecute="/debug.cfm" & + wait diff --git a/.github/workflows/webroot-matrix.yml b/.github/workflows/webroot-matrix.yml new file mode 100644 index 0000000..e8cd5de --- /dev/null +++ b/.github/workflows/webroot-matrix.yml @@ -0,0 +1,228 @@ +name: Webroot Handling Matrix +on: + push: + pull_request: + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + macos-bash: + name: MacOS Bash + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Run all webroot/execute combinations + shell: bash + env: + LUCEE_VERSION_QUERY: 7/all/zero + working-directory: ${{ github.workspace }}/tests/webroot + run: | + luceeVersionQuery="${LUCEE_VERSION_QUERY:-7/all/zero}" + pwd + webroots=( '.' "${{ github.workspace }}/tests/webroot" ) + executes=( 'index.cfm' 'test.cfm' 'sub/test.cfm' ) + failed=0 + for w in "${webroots[@]}"; do + for e in "${executes[@]}"; do + echo "ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery" + ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute="$e" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery="$luceeVersionQuery" + if [ $? -ne 0 ]; then + failed=1 + platform="macos-latest" + shell="bash" + echo -e "## Platform: $platform | Shell: $shell\n(pwd): $(pwd)\n### ant -buildfile build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery\nFAILED: $w / $e\n" >> "$GITHUB_STEP_SUMMARY" + fi + done + done + exit $failed + ubuntu-bash: + name: Ubuntu Bash + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Run all webroot/execute combinations + shell: bash + env: + LUCEE_VERSION_QUERY: 7/all/zero + working-directory: ${{ github.workspace }}/tests/webroot + run: | + luceeVersionQuery="${LUCEE_VERSION_QUERY:-7/all/zero}" + pwd + webroots=( '.' "${{ github.workspace }}/tests/webroot" ) + executes=( 'index.cfm' 'test.cfm' 'sub/test.cfm' ) + failed=0 + for w in "${webroots[@]}"; do + for e in "${executes[@]}"; do + echo "ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery" + ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute="$e" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery="$luceeVersionQuery" + if [ $? -ne 0 ]; then + failed=1 + platform="ubuntu-latest" + shell="bash" + echo -e "## Platform: $platform | Shell: $shell\n(pwd): $(pwd)\n### ant -buildfile build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery\nFAILED: $w / $e\n" >> "$GITHUB_STEP_SUMMARY" + fi + done + done + exit $failed + + windows-cmd: + name: Windows CMD + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Run all webroot/execute combinations + shell: cmd + env: + LUCEE_VERSION_QUERY: 7/all/zero + working-directory: ${{ github.workspace }}/tests/webroot + run: | + @echo off + setlocal enabledelayedexpansion + for %%w in (.) do ( + for %%e in (index.cfm test.cfm sub\test.cfm) do ( + echo %%w / %%e + ant -buildfile=..\..\build.xml "-Dwebroot=%%w" "-Dexecute=%%e" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=%LUCEE_VERSION_QUERY% + if errorlevel 1 ( + set cmd=ant -buildfile=build.xml -Dwebroot=%%w -Dexecute=%%e -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=%LUCEE_VERSION_QUERY% + echo FAILED: %%w / %%e: !cmd!>> %GITHUB_STEP_SUMMARY% + echo(>> %GITHUB_STEP_SUMMARY% + exit /b 1 + ) + ) + ) + for %%w in ("%GITHUB_WORKSPACE%\tests\webroot") do ( + for %%e in (index.cfm test.cfm sub/test.cfm) do ( + ant -buildfile=..\..\build.xml -Dwebroot=%%w -Dexecute=%%e -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=%LUCEE_VERSION_QUERY% + if errorlevel 1 ( + set cmd=ant -buildfile=build.xml -Dwebroot=%%w -Dexecute=%%e -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=%LUCEE_VERSION_QUERY% + echo FAILED: %%w / %%e: !cmd!>> %GITHUB_STEP_SUMMARY% + echo(>> %GITHUB_STEP_SUMMARY% + exit /b 1 + ) + ) + ) + + endlocal + windows-pwsh: + name: Windows PowerShell + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Run all webroot/execute combinations + shell: pwsh + env: + LUCEE_VERSION_QUERY: 7/all/zero + working-directory: ${{ github.workspace }}/tests/webroot + run: | + $webroots = @('.', "${{ github.workspace }}\tests\webroot") + pwd + $executes = @('index.cfm', 'test.cfm', 'sub/test.cfm') + foreach ($w in $webroots) { + foreach ($e in $executes) { + $luceeVersionQuery = $env:LUCEE_VERSION_QUERY + $cmd = "ant -buildfile=../../build.xml `"-Dwebroot=$w`" `"-Dexecute=$e`" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery" + Write-Host $cmd + $LASTEXITCODE = 0 + iex $cmd + if ($LASTEXITCODE -ne 0) { + $cmd = "ant -buildfile=../../build.xml `"-Dwebroot=$w`" `"-Dexecute=$e`" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery" + $platform = "windows-latest" + $shell = "pwsh" + $summary = @() + $summary += "## Platform: $platform | Shell: $shell" + $summary += "(pwd): $(pwd)" + $summary += "### $cmd" + $summary += "FAILED: $w / $e" + $summary -join "`n" | Out-File -Append -FilePath $env:GITHUB_STEP_SUMMARY + } + } + } + windows-bash: + name: Windows Bash + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + - name: Run all webroot/execute combinations + shell: bash + env: + LUCEE_VERSION_QUERY: 7/all/zero + working-directory: ${{ github.workspace }}/tests/webroot + run: | + luceeVersionQuery="${LUCEE_VERSION_QUERY:-7/all/zero}" + webroots=( '.' "${{ github.workspace }}/tests/webroot" ) + executes=( 'index.cfm' 'test.cfm' 'sub/test.cfm' ) + failed=0 + for w in "${webroots[@]}"; do + for e in "${executes[@]}"; do + echo "ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery" + ant -buildfile ../../build.xml -Dwebroot=$w -Dexecute="$e" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery="$luceeVersionQuery" + if [ $? -ne 0 ]; then + failed=1 + platform="windows-latest" + shell="bash" + echo -e "## Platform: $platform | Shell: $shell\n### ant -buildfile build.xml -Dwebroot=$w -Dexecute=\"$e\" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery\nFAILED: $w / $e\n" >> "$GITHUB_STEP_SUMMARY" + fi + done + done + exit $failed diff --git a/.gitignore b/.gitignore index 4e0eaf7..5691d01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ lucee-download-cache temp bin +logs +/temp-unique +/agent-tests +/.claude +/test-output diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6cb9e20 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,124 @@ +# Changelog + +All notable changes to the Lucee Script Runner project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- **Local JAR Support**: Added `luceeJar` parameter to test locally built Lucee JARs without publishing + - Accepts full path to a local JAR file + - Overrides both `luceeVersion` and `luceeVersionQuery` + - Perfect for Lucee core developers testing builds +- **Unique Working Directories**: Added `uniqueWorkingDir` parameter with three modes: + - `false` (default): Uses standard temp/lucee directory + - `true`: Auto-generates unique directory with timestamp and random ID + - Custom path: Uses specified directory path +- **Concurrent Execution Support**: Multiple script-runner instances can now run simultaneously without conflicts +- **Race Condition Detection**: Automatic detection and prevention of directory conflicts +- **Improved JFR Logging**: + - JFR files now output to organized `logs/` directory + - Descriptive filenames: `timestamp-lucee-version-webroot-script-javaversion.jfr` + - Added `logs/` to `.gitignore` +- **Enhanced Error Messages**: + - Git Bash path conversion detection with specific solutions + - Execute script validation with exact file path shown + - Windows trailing backslash validation +- **Cross-Platform Path Handling**: Robust path concatenation logic for Windows and Unix systems +- **Version Detection & Servlet API Handling**: + - Automatic detection of Lucee 5/6 vs 7+ to select correct servlet dependencies + - New `detect-version-type` target inspects version strings and JAR filenames + - Split Maven pom files: `pom-javax.xml` (Lucee 5/6) and `pom-jakarta.xml` (Lucee 7+) + - Seamless handling of javax to jakarta servlet API transition + - Build target reordering so version detection happens before dependency resolution +- **Java Agent Support**: + - `-DjavaAgent=` - Path to Java agent JAR (profilers, debuggers like luceedebug) + - `-DjavaAgentArgs=` - Arguments passed to the agent + - `-Djdwp=` - Enable JDWP debugging agent with suspend=n (default: false) + - `-DjdwpPort=` - JDWP port configuration (default: 9999) + - Automatic `--add-opens=java.base/java.lang=ALL-UNNAMED` when using agents +- **Advanced JVM Options**: + - `-DjvmArgs=` - Raw JVM arguments string for custom configurations + - `-DFlightRecordingSettings=` - JFR settings profile (default/profile/custom.jfc) + - `-DPrintInlining=` - JVM compilation diagnostics (PrintInlining, PrintCompilation, UnlockDiagnosticVMOptions) + - `-DPrintGCDetails=` - Detailed garbage collection logging + - `-DUseEpsilonGC=` - Epsilon no-op garbage collector with AlwaysPreTouch for testing +- **Version Query Format Enhancement**: + - `luceeVersion` now accepts version query format (e.g., `7.0/stable/light`) + - Maintains backward compatibility with `luceeVersionQuery` parameter + - Unified version handling logic across both parameters + +### Changed + +- **Updated Lucee Version**: Standardized all references to version 7.0.1.100 across codebase +- **JFR Filename Format**: Changed from `lucee-version.jar-javaversion.jfr` to descriptive format with timestamp and context +- **Documentation**: Updated README.md with comprehensive working directory behavior explanations +- **Build Process**: + - Uncommented `include template` execution path in build-run-cfml.xml + - Build target dependencies reordered: `detect-version-type` now runs before `setEnv` + - Enhanced conditional property checking for javaAgent, jvmProperties, jvmArgs + - Echo statements now show which servlet type is selected (javax vs jakarta) +- **Error Handling**: + - `_internalRequest` now captures and validates HTTP status codes + - Non-200 status codes throw descriptive errors with LDEV-6086 reference + - Better debugging information for script execution failures + +### Fixed + +- **File Path Validation Bug**: Fixed concatenation logic for execute script validation +- **Git Bash Path Conversion Issues**: Added detection and helpful error messages for MSYS path conversion problems +- **Build Script Path Resolution**: Fixed relative path issues when using unique working directories +- **Request Timeout Detection**: Internal requests now properly detect and report non-200 status codes (LDEV-6086) + +### Technical Details + +#### New Ant Properties + +- `uniqueWorkingDir`: Controls working directory behavior +- `webroot.name`: Extracted basename of webroot for JFR filenames +- `execute.clean`: Cleaned execute path (removes leading slashes) for JFR filenames +- `execute.fullpath`: Properly concatenated full path for file validation +- `javaAgent`: Path to Java agent JAR file +- `javaAgentArgs`: Arguments passed to Java agent +- `jdwp`: Enable JDWP debugging agent (suspend=n) +- `jdwpPort`: JDWP port configuration (default: 9999) +- `jvmArgs`: Raw JVM arguments string +- `FlightRecordingSettings`: JFR settings profile configuration +- `PrintInlining`: JVM compilation diagnostics flag +- `PrintGCDetails`: Garbage collection logging flag +- `UseEpsilonGC`: Epsilon no-op GC flag +- `pom.file`: Dynamically selected pom file (pom-javax.xml or pom-jakarta.xml) +- `version.major.extracted`: Extracted major version number for servlet API detection +- `usesJavax`: Boolean flag indicating if javax servlet API is used (vs jakarta) +- `servlet.type`: Servlet API type in use (javax or jakarta) + +#### Build Process Improvements + +- Added `set-unique-working-dir` target with timestamp generation and race condition checks +- Enhanced `run-cfml` target with improved validation and path handling +- Updated GitHub Actions workflow with concurrent execution tests +- New `detect-version-type` target for automatic servlet API detection: + - Parses version strings from `luceeVersion`, `luceeVersionQuery`, or `luceeJar` filename + - Extracts major version number using regex + - Selects appropriate pom file before dependency resolution + - Supports various version formats: `7.0.0.1`, `lucee-7.0.jar`, `7/snapshot/zero`, file paths +- Internal request result validation with status code checking + +#### Error Handling + +- Early validation of execute script existence under webroot +- Specific error messages for common Git Bash issues +- Clear guidance on workarounds and solutions +- HTTP status code validation for internal requests (detects timeouts and failures) + +### Migration Notes + +- Existing usage remains unchanged (fully backward compatible) +- New JFR files will appear in `logs/` directory instead of project root +- Git users should add `logs/` to their `.gitignore` if not already present +- Lucee 5/6 and 7+ now use different servlet dependencies automatically (javax vs jakarta) +- Version query format can now be used with `luceeVersion` parameter directly +- All new parameters are optional and have sensible defaults diff --git a/EXAMPLES.md b/EXAMPLES.md new file mode 100644 index 0000000..9f65925 --- /dev/null +++ b/EXAMPLES.md @@ -0,0 +1,304 @@ +# Script Runner Examples + +Practical examples and use cases for the Lucee Script Runner. + +## Table of Contents + +- [Quick Start Examples](#quick-start-examples) +- [Shell-Specific Usage](#shell-specific-usage) +- [Java Flight Recorder (JFR) Profiling](#java-flight-recorder-jfr-profiling) +- [Concurrent Execution](#concurrent-execution) +- [Working Directory Examples](#working-directory-examples) +- [Testing Extensions](#testing-extensions) +- [CI/CD Integration](#cicd-integration) + +## Quick Start Examples + +### Running from Different Locations + +```bash +# From the script-runner directory (simple) +ant -Dwebroot="/path/to/your/project" -Dexecute="yourscript.cfm" + +# From your project directory (recommended for external projects) +ant -buildfile="/path/to/script-runner/build.xml" -Dwebroot="." -Dexecute="yourscript.cfm" + +# From any directory with absolute paths +ant -buildfile="C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="test.cfm" + +# Execute a script below the webroot +ant -buildfile="C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="extended/index.cfm" +``` + +### Testing Lucee Extensions + +```bash +# Testing Lucee Spreadsheet from its directory +cd D:\work\lucee-spreadsheet +ant -buildfile=D:\work\script-runner\build.xml -Dwebroot=. -Dexecute=/test/index.cfm + +# Testing with specific Lucee version +ant -buildfile=D:\work\script-runner\build.xml -DluceeVersionQuery=6.2/stable/jar -Dwebroot=D:\work\lucee-spreadsheet -Dexecute=/test/index.cfm + +# Testing with a locally built Lucee JAR (for Lucee developers) +ant -buildfile=D:\work\script-runner\build.xml -DluceeJar="D:\work\lucee\loader\target\lucee.jar" -Dwebroot=D:\work\lucee-spreadsheet -Dexecute=/test/index.cfm + +# With unique working directory for concurrent runs +ant -buildfile=D:\work\script-runner\build.xml -DuniqueWorkingDir=true -Dwebroot=D:\work\lucee-spreadsheet -Dexecute=/test/index.cfm +``` + +## Shell-Specific Usage + +### PowerShell + +Use double quotes for paths with spaces. Single quotes also work (especially in scripts to avoid variable expansion). + +```powershell +# No spaces in paths +ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="test.cfm" + +# Paths with spaces +ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\my project" -Dexecute="test.cfm" -DuniqueWorkingDir=true + +# Using single quotes to avoid variable expansion in scripts +ant -buildfile='C:\tools\script-runner\build.xml' -Dwebroot='C:\work\project' -Dexecute='test.cfm' +``` + +### Command Prompt (Windows) + +Quotes are only needed if the path contains spaces. You can quote just the value or the entire parameter. + +```cmd +REM No spaces in paths (no quotes needed) +ant -buildfile=C:\tools\script-runner\build.xml -Dwebroot=C:\work\myproject -Dexecute=test.cfm -DuniqueWorkingDir=true + +REM Spaces in paths (quotes required) +ant -buildfile="C:\tools\script-runner\build.xml" -Dwebroot="C:\work\my project" -Dexecute="test.cfm" -DuniqueWorkingDir=true + +REM Or quote the entire parameter (especially useful in batch files) +ant "-buildfile=C:\Program Files\script-runner\build.xml" "-Dwebroot=C:\My Projects\test" -Dexecute=test.cfm +``` + +### Bash/WSL (Linux) + +Use forward slashes and Linux-style paths. Quotes only if the path has spaces. + +```bash +# No spaces in paths (no quotes needed) +ant -buildfile /mnt/d/work/script-runner/build.xml -Dwebroot=/mnt/d/work/myproject -Dexecute=test.cfm -DuniqueWorkingDir=true + +# Spaces in paths (quotes required) +ant -buildfile "/mnt/d/work/script-runner/build.xml" -Dwebroot="/mnt/d/work/my project" -Dexecute="test.cfm" -DuniqueWorkingDir=true +``` + +### Quick Reference Table + +| Shell | Example Command | +|--------------- |------------------------------------------------------------------------------------------------------------------| +| PowerShell | `ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\my project" -Dexecute="test.cfm" -DuniqueWorkingDir=true` | +| Command Prompt | `ant -buildfile=C:\tools\script-runner\build.xml -Dwebroot=C:\work\myproject -Dexecute=test.cfm -DuniqueWorkingDir=true` | +| Bash/WSL | `ant -buildfile /mnt/d/work/script-runner/build.xml -Dwebroot=/mnt/d/work/myproject -Dexecute=test.cfm -DuniqueWorkingDir=true` | + +**Key Points:** + +- **PowerShell:** Use double quotes for paths with spaces. Single quotes work too (good for avoiding variable expansion) +- **Command Prompt:** Quotes only if path has spaces. Can quote just the value or the whole parameter +- **Bash/WSL:** Use forward slashes. Quotes only if path has spaces. Don't use Windows backslashes or drive letters +- **Windows:** Never use trailing backslashes. Ever. +- **All shells:** Don't escape quotes unless you like pain +- **Debugging:** If Ant can't find your file, your path or quotes are wrong. Period. + +## Java Flight Recorder (JFR) Profiling + +Enable JFR to capture detailed performance data during script execution. + +### Basic JFR Usage + +```bash +ant -DFlightRecording=true -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +### What JFR Captures + +- Creates JFR recording files in `logs/{timestamp}-j{java.version}.jfr` +- Captures CPU usage, memory allocation, garbage collection, thread activity +- Settings: disk=true, dumponexit=true, maxsize=1024m, maxage=1d, settings=profile, path-to-gc-roots=true, stackdepth=128 + +### Custom JFR Output Path + +```bash +ant -DFlightRecording=true -DFlightRecordingFilename="D:/my-logs/custom.jfr" -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +### JFR API Access for Lucee + +If you need Lucee to access JFR APIs directly (not just record), add the JFR module exports: + +```bash +ant -DjfrExports=true -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +This adds `--add-exports=jdk.jfr/jdk.jfr=ALL-UNNAMED` and `--add-opens=jdk.jfr/jdk.jfr=ALL-UNNAMED` to allow Lucee code to use the JFR API. + +### Analyzing JFR Files + +```bash +# Print summary +jfr print logs/250101-120530-j21.jfr + +# Print specific events +jfr print --events CPULoad,GarbageCollection logs/250101-120530-j21.jfr + +# Convert to JSON +jfr print --json logs/250101-120530-j21.jfr > output.json +``` + +The `jfr` command-line tool is included in the JDK bin directory. For visual analysis, use JDK Mission Control (JMC) or import into profiling tools. + +## Concurrent Execution + +Multiple script-runner instances can be run simultaneously using unique working directories. + +### Running Tests in Parallel + +```bash +# Run multiple instances concurrently +ant -DuniqueWorkingDir="true" -Dexecute="test1.cfm" & +ant -DuniqueWorkingDir="true" -Dexecute="test2.cfm" & +ant -DuniqueWorkingDir="true" -Dexecute="test3.cfm" & +wait +``` + +Each instance will use a unique working directory named `temp-unique/{VERSION}-{TIMESTAMP}-{RANDOM}` (timestamp format: `yyMMdd-HHmmss`) to prevent conflicts. + +## Working Directory Examples + +### Default Mode (Single Instance) + +```bash +# Uses temp/lucee - fast, but single instance only +ant -DuniqueWorkingDir=false -Dwebroot=. -Dexecute=test.cfm +``` + +### Auto-Unique Mode (Concurrent Execution) + +```bash +# Uses temp-unique/{VERSION}-{TIMESTAMP}-{RANDOM} +ant -DuniqueWorkingDir=true -Dwebroot=. -Dexecute=test.cfm +``` + +### Custom Path Mode + +```bash +# Uses your specified directory +ant -DuniqueWorkingDir=C:/fast/work -Dwebroot=. -Dexecute=test.cfm +``` + +### Preserving Working Directory for Inspection + +```bash +# Don't cleanup before or after - useful for debugging +ant -DpreCleanup=false -DpostCleanup=false -Dwebroot=. -Dexecute=test.cfm +``` + +## Testing Extensions + +### Testing a Built Extension + +```bash +# Install extension from dist/ directory and run tests +ant -buildfile=script-runner/build.xml \ + -DluceeVersion="7.0.1.100" \ + -Dwebroot="$BITBUCKET_CLONE_DIR/lucee/test" \ + -DextensionDir="$BITBUCKET_CLONE_DIR/dist" \ + -Dexecute="bootstrap-tests.cfm" \ + -DtestAdditional="$BITBUCKET_CLONE_DIR/tests" +``` + +### Testing with Debug Mode + +```bash +# Enable Java debugger on port 5000 +ant -Ddebugger=true -Dwebroot=. -Dexecute=test.cfm +``` + +Then connect your IDE debugger to `localhost:5000`. + +## CI/CD Integration + +### GitHub Actions + +```yaml +- name: Checkout Lucee + uses: actions/checkout@v2 + with: + repository: lucee/lucee + path: lucee + +- name: Cache Maven packages + uses: actions/cache@v3 + with: + path: ~/.m2 + key: lucee-script-runner-maven-cache + +- name: Cache Lucee files + uses: actions/cache@v3 + with: + path: _actions/lucee/script-runner/main/lucee-download-cache + key: lucee-downloads + +- name: Run Lucee Test Suite + uses: lucee/script-runner@main + with: + webroot: ${{ github.workspace }}/lucee/test + execute: bootstrap-tests.cfm + luceeVersion: ${{ env.luceeVersion }} + luceeVersionQuery: 5.4/stable/light # (optional, overrides luceeVersion) + luceeJar: /path/to/local/lucee.jar # (optional, overrides both luceeVersion and luceeVersionQuery) + extensions: # (optional list of extension guids to install) + extensionDir: ${{ github.workspace }}/dist # (for testing building an extension with CI) + antFlags: -d or -v etc # (optional, good for debugging any ant issues) + compile: true # (optional, compiles all the cfml under the webroot) + luceeCFConfig: /path/to/.CFConfig.json # pass in additional configuration + debugger: true # (optional) runs with java debugging enabled on port 5000 + preCleanup: true # (purges Lucee working directory before starting) + postCleanup: true # (purges Lucee working directory after finishing) + uniqueWorkingDir: true # (optional) uses unique working directory for concurrent execution + env: + testLabels: pdf + testAdditional: ${{ github.workspace }}/tests +``` + +[GitHub Action Workflow Example](https://github.com/lucee/extension-pdf/blob/master/.github/workflows/main.yml) + +This will: + +- Checkout a copy of the Lucee codebase +- Install any extension(s) (`*.lex`) found in `${{ github.workspace }}/dist` +- Run all tests with the label of "pdf" +- Run any additional tests found in the `/tests` directory of the current repository + +### BitBucket Pipeline + +```yaml +image: atlassian/default-image:3 + +pipelines: + default: + - step: + name: Build and Test + caches: + - maven + script: + - ant -noinput -verbose -buildfile build.xml + artifacts: + - dist/** + - step: + name: Checkout Lucee Script-runner, Lucee and run tests + script: + - git clone https://github.com/lucee/script-runner + - git clone https://github.com/lucee/lucee + - export testLabels="PDF" + - echo $testLabels + - ant -buildfile script-runner/build.xml -DluceeVersion="light-7.0.1.100" -Dwebroot="$BITBUCKET_CLONE_DIR/lucee/test" -DextensionDir="$BITBUCKET_CLONE_DIR/dist" -Dexecute="bootstrap-tests.cfm" -DtestAdditional="$BITBUCKET_CLONE_DIR/tests" +``` diff --git a/README.md b/README.md index 751c5b3..5d5505e 100644 --- a/README.md +++ b/README.md @@ -6,42 +6,367 @@ Quickly run Lucee CFML applications headless (without a HTTP server) via the com Please report any issues, etc in the [Lucee Issue Tracker](https://luceeserver.atlassian.net/issues/?jql=labels%20%3D%20%22script-runner%22) +## Project Structure + +- `build.xml` - Main build file (always use this) +- `build-run-cfml.xml` - Internal file (do not run directly) +- `action.yml` - GitHub Action configuration +- `sample/` - Example CFML files for testing + ## Command line Usage +### Running from Different Directories + +The script-runner can be used from any directory by specifying the build file location: + +```bash +# From the script-runner directory (simple) +ant -Dwebroot="/path/to/your/project" -Dexecute="yourscript.cfm" + +# From your project directory (recommended for external projects) +ant -buildfile="/path/to/script-runner/build.xml" -Dwebroot="." -Dexecute="yourscript.cfm" + +# From any directory with absolute paths +ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="test.cfm" + +# execute a script below the webroot +ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="extended/index.cfm" +``` + +**Key Points:** + +- `-buildfile` specifies where script-runner is installed +- `-Dwebroot` is the directory containing your CFML code (can be relative to current directory) +- `-Dexecute` is the CFML script to run (relative to webroot, no leading slash required) +- **Note:** The script-runner always normalizes the webroot to an absolute path internally, regardless of whether you pass a relative or absolute path. All output and script execution will use this normalized absolute path. + +### Basic Usage + Default `ant` will run the `sample/index.cfm` file ![image](https://user-images.githubusercontent.com/426404/122402355-b0dbf980-cf7d-11eb-8837-37dec47d0713.png) -You can specify: +### Parameters + +#### Lucee Version + +Version Query Format: `(version)/(stable/rc/snapshot/lpha)/(jar/light/zero)`. + +Examples: + +- `7.0/stable/light` +- `0/stable/jar` +- `7.0.2/snapshot/zero` + +- `-DluceeJar=` - Path to custom Lucee JAR (optional, overrides both luceeVersion and luceeVersionQuery). Example: `/full-path/to/lucee.jar`, but make sure you use the exact filename for the jar. + +- `-DluceeVersion=` - Lucee version (default: `6.2.2.91`). Examples: `6.2.2.91`, `light-6.2.2.91`, `zero-6.2.2.91` or `7.0/stable/light` + +**New** LuceeVersion now also handles Version Query format, `luceeVersionQuery` is still supported for backwards compat + +- `-DluceeVersionQuery=` - Query-based version (optional, overrides luceeVersion). + +#### Paths and Execution + +- `-Dwebroot=` - Directory containing CFML code (default: `tests/`). On Windows, trailing backslashes (`\`) will be rejected with an error +- `-Dexecute=` - CFML script to run (default: `index.cfm`). Relative to webroot, no leading `/` needed +- `-DexecuteScriptByInclude=` - Use include instead of _internalRequest (default: false). Set to `true` to skip Application.cfc + +#### Extensions and Configuration + +- `-Dextensions=` - List of extension GUIDs to install (default: empty) +- `-DextensionDir=` - Directory containing manual extension files (`*.lex`) to install (default: empty) +- `-Dcompile=` - Compile all CFML under webroot (default: false). Set to `true` to enable +- `-DluceeCFConfig=` - Path to full .CFConfig.json file for additional Lucee configuration + +#### Working Directory + +Lucee deploys to a working directory, default is `temp/`. By default it clears the directory when it starts and finishes (unless it crashes and exits!). + +- `-DpreCleanup=` - Clear Lucee working directory before starting (default: true). Set to `false` to preserve +- `-DpostCleanup=` - Clear Lucee working directory after finishing (default: true). Set to `false` to preserve +- `-DuniqueWorkingDir=` - Working directory mode: + - `false` (default): Uses `temp/lucee`. One run at a time. Fast, but not for parallel jobs + - `true`: Uses `temp-unique/{VERSION}-{TIMESTAMP}-{RANDOM}` (timestamp: `yyMMdd-HHmmss`). Enables concurrent execution + - `/custom/path`: Uses your specified directory. You're on your own for cleanup and collisions + +These options are good for inspecting after a run, or setting up the `/lucee-server/context` dir with `password.txt` or `.CFConfig.json`. + +#### Debugging and Profiling + +- `-Ddebugger=` - Enable Java debugger on port 5000 with suspend=y (default: false) +- `-DFlightRecording=` - Enable Java Flight Recorder profiling (default: false). Saves `.jfr` files to `logs/` directory +- `-DFlightRecordingFilename=` - Custom output path for JFR recording file +- `-DFlightRecordingSettings=` - JFR settings profile (default: `profile`). Options: `default`, `profile`, or path to custom `.jfc` file +- `-DjfrExports=` - Add JFR module exports for Lucee JFR API access (default: false) + +#### Java Agent Support -- Lucee version `-DluceeVersion=` default `6.0.3.1`, (ie. 6.3.0.1, light-6.3.0.1, zero-6.3.0.1 ) -- Lucee version by query `-DluceeVersionQuery="5.4/stable/light` ( optional overrides luceeVersion, (version)/(stable/rc/snapshot)/(jar,light/zero) ) -- Webroot `-Dwebroot=` (default `tests/`) on Windows, avoid a trailing \ as that is treated as an escape character causes script runner to fail -- CFML Script to run, `-Dexecute=` (default `/index.cfm`) -- run script via include or _internalRequest (which runs the Application.cfc if present, default ) `-DexecuteScriptByInclude="true"` -- any extra extensions `-Dextensions=` (default ``) -- manual extension install (`*.lex`) from a directory `-DextensionDir=` (default ``) -- compile all cfml under webroot `-Dcompile="true"` -- pass in a full .CFConfig.json file `-DluceeCFConfig="/path/to/.CFConfig.json` -- use a java debugger `-Ddebugger="true"` opens a java debugging port 5000, with suspend=y -- preCleanup `-DpreCleanup="true"` purges the Lucee working dir before starting -- postCleanup `-DpostCleanup="true"` purges the Lucee working dir after finishing +- `-DjavaAgent=` - Path to a Java agent JAR file (e.g., profilers, debuggers like luceedebug) +- `-DjavaAgentArgs=` - Arguments passed to the agent (the part after `=` in `-javaagent:path=args`) +- `-Djdwp=` - Enable JDWP debugging agent with suspend=n (default: false). Required for agents like luceedebug +- `-DjdwpPort=` - JDWP port (default: 9999) -`ant -DluceeVersion="6.0.0.95-SNAPSHOT" -Dwebroot="C:\work\lucee-docs" -Dexecute="import.cfm" -Dlucee.extensions=""` +#### Advanced JVM Options + +- `-DjvmProperties=` - Path to Java properties file to load additional JVM properties +- `-DjvmArgs=` - Raw JVM arguments string (e.g., `"-Xmx64m -Xms32m"`) +- `-DPrintGCDetails=` - Enable detailed garbage collection logging (default: false) +- `-DUseEpsilonGC=` - Enable Epsilon no-op garbage collector for testing (default: false). Also enables AlwaysPreTouch +- `-DPrintInlining=` - Enable JVM compilation diagnostics (default: false). Enables PrintInlining, PrintCompilation, and UnlockDiagnosticVMOptions + +### Java Flight Recorder (JFR) Profiling + +Enable JFR to capture detailed performance data during script execution: + +- Java Flight Recorder `-DFlightRecording="true"` enables JFR profiling, saves .jfr files to `logs/` directory +- JFR module access `-DjfrExports="true"` adds `--add-exports` and `--add-opens` for `jdk.jfr` module (for Lucee JFR API access) +- Custom JFR filename `-DFlightRecordingFilename="/path/to/output.jfr"` specify custom output path for JFR recording + +```bash +ant -DFlightRecording=true -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +**What it does:** + +- Creates JFR recording files in `logs/{timestamp}-j{java.version}.jfr` +- Captures CPU usage, memory allocation, garbage collection, thread activity +- Settings: disk=true, dumponexit=true, maxsize=1024m, maxage=1d, settings=profile, path-to-gc-roots=true, stackdepth=128 + +**Custom JFR output path:** + +```bash +ant -DFlightRecording=true -DFlightRecordingFilename="D:/my-logs/custom.jfr" -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +**JFR API access for Lucee:** + +If you need Lucee to access JFR APIs directly (not just record), add the JFR module exports: + +```bash +ant -DjfrExports=true -Dwebroot="." -Dexecute="yourscript.cfm" +``` + +This adds `--add-exports=jdk.jfr/jdk.jfr=ALL-UNNAMED` and `--add-opens=jdk.jfr/jdk.jfr=ALL-UNNAMED` to allow Lucee code to use the JFR API. + +**Analyzing JFR files:** + +```bash +# Print summary +jfr print logs/250101-120530-j21.jfr + +# Print specific events +jfr print --events CPULoad,GarbageCollection logs/250101-120530-j21.jfr + +# Convert to JSON +jfr print --json logs/250101-120530-j21.jfr > output.json +``` + +The `jfr` command-line tool is included in the JDK bin directory. For visual analysis, use JDK Mission Control (JMC) or import into profiling tools. + +### Java Agent Example (luceedebug) + +To run with a Java agent like [luceedebug](https://github.com/softwareCobbler/luceedebug): + +```bash +ant -buildfile "D:\work\script-runner" ^ + -Djdwp="true" ^ + -DjdwpPort="9999" ^ + -DjavaAgent="D:\path\to\luceedebug-2.0.15.jar" ^ + -DjavaAgentArgs="jdwpHost=localhost,jdwpPort=9999,debugHost=0.0.0.0,debugPort=10000,jarPath=D:\path\to\luceedebug-2.0.15.jar" ^ + -Dwebroot="D:\my\cfml\app" ^ + -Dexecute="index.cfm" +``` + +**Note:** The agent's `jarPath` argument must match the `-DjavaAgent` path exactly. + +To profile luceedebug overhead with JFR: + +```bash +ant -buildfile "D:\work\script-runner" ^ + -Djdwp="true" ^ + -DjavaAgent="D:\path\to\luceedebug.jar" ^ + -DjavaAgentArgs="jdwpHost=localhost,jdwpPort=9999,debugHost=0.0.0.0,debugPort=10000,jarPath=D:\path\to\luceedebug.jar" ^ + -DFlightRecording="true" ^ + -DFlightRecordingFilename="D:\output\luceedebug-profile.jfr" ^ + -Dwebroot="." ^ + -Dexecute="benchmark.cfm" +``` -`ant -DluceeVersion="6.0.0.95-SNAPSHOT" -DextensionDir="C:\work\lucee-extensions\extension-hibernate\dist"` +### TL;DR: Quoting & Paths (Stop Overthinking It) + +**If your path has spaces, use quotes. If not, don’t.** + +**Quick Reference:** + +| Shell | Example Command | +|--------------- |------------------------------------------------------------------------------------------------------------------| +| PowerShell | `ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\my project" -Dexecute="test.cfm" -DuniqueWorkingDir=true` | +| Command Prompt | `ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="C:\work\myproject" -Dexecute="test.cfm" -DuniqueWorkingDir=true` | +| Bash/WSL | `ant -buildfile /mnt/d/work/script-runner/build.xml -Dwebroot=/mnt/d/work/myproject -Dexecute=test.cfm -DuniqueWorkingDir=true` | + +**PowerShell:** Use double quotes for paths with spaces. Single quotes also work (especially in scripts to avoid variable expansion). Don’t mix and match. + +**Command Prompt:** Quotes only if the path has spaces. You can quote just the value or the whole parameter (the latter is handy in batch files). + +**Bash/WSL:** Use forward slashes. Quotes only if the path has spaces. Don’t use Windows backslashes or drive letters. + +**Blunt Warnings:** +- Don’t use trailing backslashes on Windows. Ever. +- Don’t escape quotes unless you like pain. +- If Ant can’t find your file, your path or quotes are wrong. Period. + +--- + +### Quick Reference Examples + + +```bash +# Testing Lucee Spreadsheet from its directory +cd D:\work\lucee-spreadsheet +ant -buildfile "D:\work\script-runner\build.xml" -Dwebroot=. -Dexecute=/test/index.cfm + +# Testing with specific Lucee version +ant -buildfile "D:\work\script-runner\build.xml" -DluceeVersionQuery=6.2/stable/jar -Dwebroot="D:\work\lucee-spreadsheet" -Dexecute=/test/index.cfm + +# Testing with a locally built Lucee JAR (for Lucee developers) +ant -buildfile "D:\work\script-runner\build.xml" -DluceeJar="D:\work\lucee\loader\target\lucee.jar" -Dwebroot="D:\work\lucee-spreadsheet" -Dexecute=/test/index.cfm + +# With unique working directory for concurrent runs +ant -buildfile "D:\work\script-runner\build.xml" -DuniqueWorkingDir=true -Dwebroot="D:\work\lucee-spreadsheet" -Dexecute=/test/index.cfm +``` + +### Working Directory Behavior + +**Default Mode** (`uniqueWorkingDir=false` or not specified): + +- Uses a consistent local `temp/lucee` directory relative to script-runner location +- Same directory is reused across runs (cleaned with `preCleanup`/`postCleanup`) +- **Ideal for CI/CD**: Predictable location, faster subsequent runs due to caching +- **Single instance only**: Cannot run multiple concurrent instances + +**Auto-Unique Mode** (`uniqueWorkingDir=true`): + +- Creates unique directories: `temp-unique/{VERSION}-{TIMESTAMP}-{RANDOM}` (timestamp format: `yyMMdd-HHmmss`) +- Each run gets its own isolated working directory +- **Enables concurrent execution**: Multiple instances can run simultaneously +- **Useful for**: Parallel testing, concurrent builds, isolation requirements + +**Custom Path Mode** (`uniqueWorkingDir=/custom/path`): + +- Uses your specified directory as the working directory +- Full control over location (e.g., RAM disk, specific drive, shared folder) +- **Race protection**: Still checks for existing directory to prevent conflicts +- **Useful for**: Custom environments, performance optimization, specific storage requirements + +```bash +# Examples of the three modes: +ant -DuniqueWorkingDir=false # Uses: temp/lucee +ant -DuniqueWorkingDir=true # Uses: temp-unique/6.2.2.91-250913-142530-123 +ant -DuniqueWorkingDir=C:/fast/work # Uses: C:/fast/work +``` + +### Concurrent Execution + +Multiple script-runner instances can be run simultaneously using unique working directories: + +```bash +# Run multiple instances concurrently +ant -DuniqueWorkingDir="true" -Dexecute="test1.cfm" & +ant -DuniqueWorkingDir="true" -Dexecute="test2.cfm" & +ant -DuniqueWorkingDir="true" -Dexecute="test3.cfm" & +wait +``` + +Each instance will use a unique working directory named `temp-unique/{VERSION}-{TIMESTAMP}-{RANDOM}` (timestamp format: `yyMMdd-HHmmss`) to prevent conflicts. + +## Writing Output in Headless Mode + +When running CFML scripts in headless mode (without a web server), you should use `systemOutput()` instead of `writeOutput()` to see output in the console: + +```cfm +// ✅ Correct - outputs to console in headless mode +systemOutput("Processing started...", true); // true adds newline +systemOutput("Item #i# processed", true); + +// ❌ Wrong - writeOutput() won't display in console +writeOutput("This won't be visible"); + +// For debugging, you can also use: +systemOutput(serializeJSON(myData, "struct"), true); +``` + + +**Key Points:** + +- `systemOutput()` writes directly to the console (stdout) +- `writeOutput()` is for HTTP response output and won't show in headless mode +- The second parameter `true` adds a newline after the output +- Use `systemOutput()` for progress updates, debugging, and results + +## Troubleshooting + +### Common Issues on Windows + +**Problem**: "Could not locate build file" from other directories +**Solution**: Use absolute path to build.xml: + +```bash +# ✅ Correct - specify script-runner location +ant -buildfile "C:\tools\script-runner\build.xml" -Dwebroot="." -Dexecute="test.cfm" + +# ❌ Wrong - looking for build.xml in current directory +ant -Dwebroot="." -Dexecute="/test.cfm" + +``` + +**Problem**: "File not found" for CFML scripts +**Solution**: Check webroot and execute paths: + +```bash +# Verify your paths - execute is relative to webroot +ant -buildfile="/path/to/script-runner/build.xml" -Dwebroot="/your/project" -Dexecute="debug.cfm" +``` + +**Problem**: "No shell found" or quote/escape errors on Windows +**Solution**: Use proper quote formatting for Windows command line: + +```bash +# ✅ Correct - Windows Command Prompt (no quotes needed for paths without spaces) +ant -buildfile "d:\work\script-runner\build.xml" -Dwebroot="D:\work\project" -Dexecute="test.cfm" + +# ✅ Correct - Windows with spaces in paths +ant -buildfile "C:\Program Files\script-runner\build.xml" -Dwebroot="C:\My Projects\test" -Dexecute="test.cfm" + +# ✅ Correct - PowerShell (single quotes work too, avoid variable expansion) +ant -buildfile 'd:\work\script-runner\build.xml' -Dwebroot 'D:\work\project' -Dexecute 'test.cfm' + +# ❌ Wrong - excessive escaping or nested quotes +ant -buildfile=\"d:\work\script-runner\" -Dwebroot=\"D:\work\project\" +``` + + +**Important Windows Tips:** + +- When using `-buildfile` with a directory, add `\build.xml` explicitly +- Avoid escaped quotes (`\"`) - they're usually not needed +- Use forward slashes (`/`) or double backslashes (`\\`) in scripts to avoid escape issues +- In batch files, use `%%` instead of `%` for variables If no webroot is specfied, you can run the provided debug script, to see which extensions are available and all the env / sys properties -`ant -buildfile="C:\work\script-runner" -Dexecute="/debug.cfm"` +```bash +ant -buildfile "C:\work\script-runner\build.xml" -Dexecute="debug.cfm" -`ant -buildfile="C:\work\script-runner" -Dexecute="/debug.cfm" -DluceeVersion="light-6.0.0.95-SNAPSHOT"` (`light` has no bundled extensions, `zero` has no extension or admin) +# With light version (no bundled extensions) or zero version (no extension or admin) +ant -buildfile "C:\work\script-runner\build.xml" -Dexecute="debug.cfm" -DluceeVersion="light-6.2.2.91" +``` ## As a GitHub Action To use as a GitHub Action, to run the PDF tests after building the PDF Extension, just add the following YAML -``` +```yaml - name: Checkout Lucee uses: actions/checkout@v2 with: @@ -61,9 +386,10 @@ To use as a GitHub Action, to run the PDF tests after building the PDF Extension uses: lucee/script-runner@main with: webroot: ${{ github.workspace }}/lucee/test - execute: /bootstrap-tests.cfm + execute: bootstrap-tests.cfm luceeVersion: ${{ env.luceeVersion }} luceeVersionQuery: 5.4/stable/light (optional, overrides luceeVersion ) + luceeJar: /path/to/local/lucee.jar (optional, overrides both luceeVersion and luceeVersionQuery) extensions: (optional list of extension guids to install) extensionDir: ${{ github.workspace }}/dist (for testing building an extension with CI) antFlags: -d or -v etc (optional, good for debugging any ant issues) @@ -72,12 +398,26 @@ To use as a GitHub Action, to run the PDF tests after building the PDF Extension debugger: true (optional) runs with java debugging enabled on port 5000 preCleanup: true (purges Lucee working directory before starting) postCleanup: true (purges Lucee working directory after finishing) + uniqueWorkingDir: true (optional) uses unique working directory for concurrent execution + FlightRecording: true (optional) enables Java Flight Recorder profiling + FlightRecordingFilename: /path/to/output.jfr (optional) custom JFR output path + FlightRecordingSettings: profile (optional) JFR settings profile (default/profile/custom.jfc) + jfrExports: true (optional) adds JFR module exports for Lucee JFR API access + javaAgent: /path/to/agent.jar (optional) Java agent JAR path + javaAgentArgs: agent=args (optional) Java agent arguments + jdwp: true (optional) enables JDWP debugging agent (suspend=n) + jdwpPort: 9999 (optional) JDWP port (default: 9999) + jvmProperties: /path/to/jvm.properties (optional) Java properties file path + jvmArgs: "-Xmx64m -Xms32m" (optional) raw JVM arguments + PrintGCDetails: true (optional) enables detailed GC logging + UseEpsilonGC: true (optional) enables Epsilon no-op garbage collector + PrintInlining: true (optional) enables JVM compilation diagnostics env: testLabels: pdf testAdditional: ${{ github.workspace }}/tests ``` -https://github.com/lucee/extension-pdf/blob/master/.github/workflows/main.yml +[GitHub Action Workflow Example](https://github.com/lucee/extension-pdf/blob/master/.github/workflows/main.yml) This will do the following steps @@ -88,7 +428,7 @@ This will do the following steps ## As a BitBucket Pipeline -``` +```yaml image: atlassian/default-image:3 pipelines: @@ -108,5 +448,5 @@ pipelines: - git clone https://github.com/lucee/lucee - export testLabels="PDF" - echo $testLabels - - ant -buildfile script-runner/build.xml -DluceeVersion="light-6.0.0.152-SNAPSHOT" -Dwebroot="$BITBUCKET_CLONE_DIR/lucee/test" -DextensionDir="$BITBUCKET_CLONE_DIR/dist" -Dexecute="/bootstrap-tests.cfm" -DtestAdditional="$BITBUCKET_CLONE_DIR/tests" + - ant -buildfile script-runner/build.xml -DluceeVersion="light-6.2.2.91" -Dwebroot="$BITBUCKET_CLONE_DIR/lucee/test" -DextensionDir="$BITBUCKET_CLONE_DIR/dist" -Dexecute="bootstrap-tests.cfm" -DtestAdditional="$BITBUCKET_CLONE_DIR/tests" ``` diff --git a/action.yml b/action.yml index 8fc101b..852f3e2 100644 --- a/action.yml +++ b/action.yml @@ -2,10 +2,13 @@ name: 'Lucee Script Runner' description: 'Run Lucee via the command line' inputs: luceeVersion: - description: Lucee Version to run, i.e. "light-6.0.3.1", "5.4.6.9", "zero-6.0.3.1" + description: Lucee Version to run, i.e. "light-7.0.1.100", "5.4.6.9", "zero-6.2.4.24" or "7.0/snapshot/jar" required: true luceeVersionQuery: - description: Lucee Version Query to run (overrides luceeVersion, i.e. "5.4/stable/light", "6.1/snapshot/jar", "6/stable/zero" ) + description: Lucee Version Query to run (overrides luceeVersion, i.e. "5.4/stable/light", "7.0/snapshot/jar", "6/stable/zero" ) for backwards compat, use luceeVersion instead + default: "" + luceeJar: + description: Full path to a local Lucee JAR file (overrides both luceeVersion and luceeVersionQuery) default: "" webroot: description: webroot directory @@ -37,6 +40,9 @@ inputs: postCleanup: description: purge the directory Lucee is deployed into after finishing default: "true" + uniqueWorkingDir: + description: 'Working directory mode: "false" (default temp/lucee), "true" (auto-generate unique), or custom path (e.g., "/custom/work")' + default: "false" runs: using: "composite" steps: @@ -45,6 +51,7 @@ runs: pwd echo luceeVersion ${{ inputs.luceeVersion }} echo luceeVersionQuery ${{ inputs.luceeVersionQuery }} + echo luceeJar ${{ inputs.luceeJar }} echo webroot ${{ inputs.webroot }} echo execute ${{ inputs.execute }} echo extensions ${{ inputs.extensions }} @@ -52,17 +59,20 @@ runs: echo compile ${{ inputs.compile }} echo luceeCFConfig:${{inputs.luceeCFConfig}} ant -buildfile "${{ github.action_path }}/build.xml" ${{ inputs.antFlags }} -DluceeVersion="${{ inputs.luceeVersion }}" -DluceeVersionQuery="${{ inputs.luceeVersionQuery }}" \ + -DluceeJar="${{ inputs.luceeJar }}" \ -Dwebroot="${{ inputs.webroot }}" -Dexecute="${{ inputs.execute }}" \ -Dextensions="${{ inputs.extensions }}" -DextensionDir="${{ inputs.extensionDir }}" \ -Dcompile="${{ inputs.compile }}" -Ddebugger="${{ inputs.debugger }}" \ -DluceeCFConfig="${{inputs.luceeCFConfig}}" \ - -DpreCleanup="${{inputs.preCleanup}}" -DpostCleanup="${{inputs.postCleanup}}" + -DpreCleanup="${{inputs.preCleanup}}" -DpostCleanup="${{inputs.postCleanup}}" \ + -DuniqueWorkingDir="${{inputs.uniqueWorkingDir}}" shell: bash - if: runner.os == 'Windows' run: | pwd echo luceeVersion ${{ inputs.luceeVersion }} echo luceeVersionQuery ${{ inputs.luceeVersionQuery }} + echo luceeJar ${{ inputs.luceeJar }} echo webroot ${{ inputs.webroot }} echo execute ${{ inputs.execute }} echo extensions ${{ inputs.extensions }} @@ -71,8 +81,10 @@ runs: echo luceeCFConfig:${{inputs.luceeCFConfig}} ant -buildfile "${{ github.action_path }}/build.xml" ${{ inputs.antFlags }} ^ -DluceeVersion="${{ inputs.luceeVersion }}" -DluceeVersionQuery="${{ inputs.luceeVersionQuery }}" ^ + -DluceeJar="${{ inputs.luceeJar }}" ^ -Dwebroot="${{ inputs.webroot }}" -Dexecute="${{ inputs.execute }}" -Dextensions="${{ inputs.extensions }}" ^ -DextensionDir="${{ inputs.extensionDir }}" -Dcompile="${{ inputs.compile }}" ^ -Ddebugger="${{ inputs.debugger }}" -DluceeCFConfig="${{inputs.luceeCFConfig}}" ^ - -DpreCleanup="${{inputs.preCleanup}}" -DpostCleanup="${{inputs.postCleanup}}" + -DpreCleanup="${{inputs.preCleanup}}" -DpostCleanup="${{inputs.postCleanup}}" ^ + -DuniqueWorkingDir="${{inputs.uniqueWorkingDir}}" shell: cmd diff --git a/build-run-cfml.xml b/build-run-cfml.xml index 9a1e61c..dd5579a 100644 --- a/build-run-cfml.xml +++ b/build-run-cfml.xml @@ -1,5 +1,15 @@ + + + + + + + + + + @@ -165,10 +175,16 @@ if ( executeScriptByInclude eq "true"){ include template="#execute#"; } else { - _internalRequest( + result = _internalRequest( template = execute, url = passedVariables - ); // using internal request runs the Application.cfc, pass any simple variables in as URLs + ); // using internal request runs the Application.cfc, pass any simple variables in as URLs + + if (result.status_code != 200){ + failedRequest = "Error: Script threw [#result.status_code#], expected [200], possible request timeout? see LDEV-6086"; + systemOuput( failedRequest, true, true); + throw "Error: Script threw [#result.status_code#], expected [200], possible request timeout? see LDEV-6086"; + } } } catch (e){ request.errorThrown = true; diff --git a/build.xml b/build.xml index 33c9fb8..2c9d2ab 100644 --- a/build.xml +++ b/build.xml @@ -1,14 +1,19 @@ - + + + + + + + + + @@ -20,84 +25,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + @@ -105,16 +391,22 @@ --> - + + + + + + - + - - - - + + + + + @@ -126,16 +418,28 @@ --> + + + + - - - + - + + + + + + + + + ${errorOut} - + + diff --git a/pom-jakarta.xml b/pom-jakarta.xml new file mode 100644 index 0000000..919799e --- /dev/null +++ b/pom-jakarta.xml @@ -0,0 +1,126 @@ + + 4.0.0 + + org.lucee + lucee + 7.0.0.0 + jar + + Lucee Loader Build + Building the Lucee Loader JAR + http://maven.lucee.org/loader/ + + + UTF-8 + UTF-8 + 1.8 + 1.8 + ${maven.build.timestamp} + yyyy/MM/dd HH:mm:ss z + UTC + en,GB + lucee.runtime.script.Main + + + + + The GNU Lesser General Public License, Version 2.1 + http://www.gnu.org/licenses/lgpl-2.1.txt + repo + + + + + + micstriit + Michael Offner + michael@lucee.org + Lucee Association Switzerland + http://lucee.org + + Project-Administrator + Developer + + +1 + + + isapir + Igal Sapir + dev@21solutions.net + 21 Solutions + http://21solutions.net/ + + Developer + + -8 + + + zspitzer + Zac Spitzer + zac@lucee.org + Lucee Association Switzerland + http://lucee.org + + Developer + + -8 + + + + + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + compile + + + jakarta.servlet.jsp + jakarta.servlet.jsp-api + 3.1.0 + compile + + + jakarta.el + jakarta.el-api + 5.0.0 + compile + + + + + + repo + https://raw.githubusercontent.com/lucee/mvn/master/releases + + + snapi + https://oss.sonatype.org/content/repositories/snapshots + + + res + https://oss.sonatype.org/content/repositories/releases/ + + + + + https://github.com/lucee/Lucee + scm:git:git://github.com/lucee/Lucee.git + scm:git:git@github.com:lucee/Lucee.git + ${project.version} + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + diff --git a/pom-javax.xml b/pom-javax.xml new file mode 100644 index 0000000..1d738c1 --- /dev/null +++ b/pom-javax.xml @@ -0,0 +1,126 @@ + + 4.0.0 + + org.lucee + lucee + 6.2.2.91 + jar + + Lucee Loader Build + Building the Lucee Loader JAR + http://maven.lucee.org/loader/ + + + UTF-8 + UTF-8 + 1.8 + 1.8 + ${maven.build.timestamp} + yyyy/MM/dd HH:mm:ss z + UTC + en,GB + lucee.runtime.script.Main + + + + + The GNU Lesser General Public License, Version 2.1 + http://www.gnu.org/licenses/lgpl-2.1.txt + repo + + + + + + micstriit + Michael Offner + michael@lucee.org + Lucee Association Switzerland + http://lucee.org + + Project-Administrator + Developer + + +1 + + + isapir + Igal Sapir + dev@21solutions.net + 21 Solutions + http://21solutions.net/ + + Developer + + -8 + + + zspitzer + Zac Spitzer + zac@lucee.org + Lucee Association Switzerland + http://lucee.org + + Developer + + -8 + + + + + + + javax.servlet + javax.servlet-api + 3.1.0 + compile + + + javax.servlet.jsp + jsp-api + 2.2 + compile + + + javax.el + javax.el-api + 3.0.0 + compile + + + + + + repo + https://raw.githubusercontent.com/lucee/mvn/master/releases + + + snapi + https://oss.sonatype.org/content/repositories/snapshots + + + res + https://oss.sonatype.org/content/repositories/releases/ + + + + + https://github.com/lucee/Lucee + scm:git:git://github.com/lucee/Lucee.git + scm:git:git@github.com:lucee/Lucee.git + ${project.version} + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + diff --git a/pom.xml b/pom.xml index ffd4263..eb1fd83 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.lucee lucee - 6.0.0.105-SNAPSHOT + 6.2.2.91 jar Lucee Loader Build diff --git a/tests/webroot/README.md b/tests/webroot/README.md new file mode 100644 index 0000000..ade0f15 --- /dev/null +++ b/tests/webroot/README.md @@ -0,0 +1,14 @@ +# Webroot Test Scripts + +This folder contains test CFML scripts for verifying webroot and execute argument handling in the script-runner. + +## Rules and What We Are Testing + +- All scripts in this folder are used by automated tests to ensure that: + - The `-Dwebroot` argument (relative or absolute, quoted or unquoted) is always normalized and used correctly. + - The `-Dexecute` argument (relative to webroot, with or without subfolders) is resolved and executed as expected. +- The `index.cfm` and `test.cfm` scripts are for basic webroot resolution. +- The `sub/test.cfm` script is for testing relative execute paths within a subfolder. +- Output from these scripts is checked in CI to confirm correct path resolution and script execution. + +**Do not remove or rename these files unless you update the corresponding tests and workflows.** diff --git a/tests/webroot/index.cfm b/tests/webroot/index.cfm new file mode 100644 index 0000000..82e3b7d --- /dev/null +++ b/tests/webroot/index.cfm @@ -0,0 +1,3 @@ + +systemOutput("webroot test: #expandPath('./index.cfm')#", true); + diff --git a/tests/webroot/sub/test.cfm b/tests/webroot/sub/test.cfm new file mode 100644 index 0000000..b5f5e08 --- /dev/null +++ b/tests/webroot/sub/test.cfm @@ -0,0 +1,3 @@ + +systemOutput("webroot test: #expandPath('./sub/test.cfm')#", true); + diff --git a/tests/webroot/test.cfm b/tests/webroot/test.cfm new file mode 100644 index 0000000..12f7744 --- /dev/null +++ b/tests/webroot/test.cfm @@ -0,0 +1,3 @@ + +systemOutput("webroot test: #expandPath('./test.cfm')#", true); +