Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 79 additions & 17 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,101 @@ on:
workflow_dispatch:

jobs:
build-ubuntu:
versions:
name: Lucee ${{ matrix.lucee }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- { lucee: 5.4/stable/jar, java: 11 }
- { lucee: 6.2/stable/jar, java: 21 }
- { lucee: 6.2/snapshot/jar, java: 21 }
- { lucee: 7.0/stable/jar, java: 21 }
- { lucee: 7.0/snapshot/jar, java: 21 }
- { lucee: 7.1/snapshot/jar, java: 21 }
- { lucee: 8.0/snapshot/jar, java: 21 }

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- name: Set up Java ${{ matrix.java }}
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ matrix.java }}

- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/.m2
key: lucee-script-runner-maven-cache

# jar names include the full version, so a new snapshot is a new key, saved once
- name: Resolve Lucee jar
id: lucee
run: echo "jar=$(curl -sf https://update.lucee.org/rest/update/provider/latest/${{ matrix.lucee }}/filename | tr -d '"')" >> "$GITHUB_OUTPUT"

- name: Cache Lucee jar ${{ steps.lucee.outputs.jar }}
uses: actions/cache@v6
with:
path: lucee-download-cache/${{ steps.lucee.outputs.jar }}
key: lucee-jar-${{ steps.lucee.outputs.jar }}

- name: Run debug.cfm, passing variables
run: ant -DluceeVersionQuery="${{ matrix.lucee }}" -Dexecute="/debug.cfm" -Dtruth="cfml rocks" -Dauthor="Zac Spitzer"

- name: Compile webroot
run: ant -DluceeVersionQuery="${{ matrix.lucee }}" -Dexecute="/index.cfm" -Dcompile="true"

- name: Compile webroot with errors, expect the run to fail before executing
run: |
if ant -DluceeVersionQuery="${{ matrix.lucee }}" -Dexecute="/index.cfm" -Dcompile="true" \
-Dwebroot="${{ github.workspace }}/tests/compile-mixed" > compile-mixed.txt 2>&1; then
cat compile-mixed.txt
echo "::error::compile errors didn't fail the run"
exit 1
fi
cat compile-mixed.txt
grep -q "badpage.cfm" compile-mixed.txt || { echo "::error::badpage.cfm compile error not reported"; exit 1; }
grep -q "BadComponent.cfc" compile-mixed.txt || { echo "::error::BadComponent.cfc compile error not reported"; exit 1; }
if grep -q "compile-mixed index.cfm ran" compile-mixed.txt; then
echo "::error::index.cfm ran despite compile errors"
exit 1
fi

# Lucee writes its config back to the file it's given, so pass a copy
- name: LUCEE_BASE_CONFIG env var is applied
if: ${{ !startsWith( matrix.lucee, '5.' ) }}
run: |
cp tests/base-config/.CFConfig.json "$RUNNER_TEMP/base-config.json"
LUCEE_BASE_CONFIG="$RUNNER_TEMP/base-config.json" \
ant -DluceeVersionQuery="${{ matrix.lucee }}" -Dexecute="/index.cfm" -Dwebroot="${{ github.workspace }}/tests/base-config"

variants:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7

- name: Cache Maven packages
uses: actions/cache@v6
with:
path: ~/.m2
key: lucee-script-runner-maven-cache

# pinned versions only, so a fixed key is fine
- name: Cache Lucee files
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/work/script-runner/script-runner/lucee-download-cache/
key: lucee-downloads
path: lucee-download-cache/
key: lucee-downloads-variants

- name: Run default
run: ant

- name: Run Latest Lucee 6 (via version query)
run: ant -DluceeVersionQuery="6/all/jar" -Dexecute="/debug.cfm"

- name: Run Lucee 6 Stable
run: ant -DluceeVersion="6.2.2.91" -Dexecute="/debug.cfm" -Dtruth="cfml rocks" -Dauthor="Zac Spitzer"
run: ant -DluceeVersion="6.2.2.91" -Dexecute="/debug.cfm"

- name: Run Lucee 5 (using Lucee light, no extensions)
run: ant -DluceeVersion="light-5.4.2.17" -Dexecute="/debug.cfm"
Expand All @@ -42,13 +111,6 @@ jobs:
- name: Run Latest Lucee 5 RC Light
run: ant -DluceeVersionQuery="5/rc/light" -Dexecute="/debug.cfm"

- name: Run Latest Stable Lucee 5, compile webroot
run: ant -DluceeVersionQuery="5/stable/jar" -Dexecute="/index.cfm" -Dcompile="true"

- 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" &
Expand Down
37 changes: 19 additions & 18 deletions .github/workflows/webroot-matrix.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: Webroot Handling Matrix
on:
push:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -11,16 +9,16 @@ jobs:
name: MacOS Bash
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
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
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
Expand Down Expand Up @@ -52,16 +50,16 @@ jobs:
name: Ubuntu Bash
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
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
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
Expand Down Expand Up @@ -94,16 +92,16 @@ jobs:
name: Windows CMD
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
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
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
Expand Down Expand Up @@ -144,16 +142,16 @@ jobs:
name: Windows PowerShell
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
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
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
Expand All @@ -166,6 +164,7 @@ jobs:
$webroots = @('.', "${{ github.workspace }}\tests\webroot")
pwd
$executes = @('index.cfm', 'test.cfm', 'sub/test.cfm')
$failed = $false
foreach ($w in $webroots) {
foreach ($e in $executes) {
$luceeVersionQuery = $env:LUCEE_VERSION_QUERY
Expand All @@ -174,7 +173,8 @@ jobs:
$LASTEXITCODE = 0
iex $cmd
if ($LASTEXITCODE -ne 0) {
$cmd = "ant -buildfile=../../build.xml `"-Dwebroot=$w`" `"-Dexecute=$e`" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery"
$failed = $true
$cmd ="ant -buildfile=../../build.xml `"-Dwebroot=$w`" `"-Dexecute=$e`" -DpreCleanup=false -DpostCleanup=false -DluceeVersionQuery=$luceeVersionQuery"
$platform = "windows-latest"
$shell = "pwsh"
$summary = @()
Expand All @@ -186,20 +186,21 @@ jobs:
}
}
}
if ($failed) { exit 1 }
windows-bash:
name: Windows Bash
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v4
uses: actions/cache@v6
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
uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
Expand Down
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Examples:

- `-Dextensions=` - List of extensions to install (default: empty). Accepts GUIDs (all versions) or Maven GAV coordinates on Lucee 7.0+ (e.g. `org.lucee:hibernate-extension:5.6.15.12-SNAPSHOT`)
- `-DextensionDir=` - Directory containing manual extension files (`*.lex`) to install (default: empty)
- `-Dcompile=` - Compile all CFML under webroot (default: false). Set to `true` to enable
- `-Dcompile=` - Compile all CFML under webroot before executing the script (default: false). See [Compile Option](#compile-option) below
- `-DluceeCFConfig=` - Path to full .CFConfig.json file for additional Lucee configuration

#### Working Directory
Expand Down Expand Up @@ -115,6 +115,39 @@ These options are good for inspecting after a run, or setting up the `/lucee-ser
- `-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

### Compile Option

`-Dcompile=true` compiles every CFML file under the webroot **before** the main `-Dexecute` script runs. Internally it invokes the Lucee admin `compileMapping` action against the web mapping `/` with `stoponerror="false"`.

**What it's for:**

- **CI syntax check** — catches parse errors in files your test script doesn't touch. Without `-Dcompile`, a typo in a rarely-hit CFC only surfaces when that code path runs.
- **Pre-warm the class cache** — every `.cfm`/`.cfc` gets compiled to bytecode up front, so first-hit request latency isn't paying compile cost.
- **Smoke-test a codebase** against a new Lucee version without wiring up real tests.

**Behaviour:**

- Compiles everything reachable from the webroot's `/` mapping (recursive).
- `stoponerror="false"` — compilation carries on past a bad file, so every error is collected. If there were any, they are all reported together (`Compilation failed with N error(s)`, with file and line for each) and the run fails before `-Dexecute` runs. Any compile error means a non-zero exit code, even if the `-Dexecute` script itself is fine.
- Runs once, before `-Dexecute`. Doesn't recompile if files change mid-run (script-runner is one-shot anyway).

**Examples:**

```bash
# Compile + run index.cfm
ant -Dwebroot="D:\work\myproject" -Dexecute="index.cfm" -Dcompile=true

# compile a known-bad codebase: lists the compile errors, then fails without running index.cfm
ant -Dwebroot="./sampleBad" -Dexecute="index.cfm" -Dcompile=true
```

The script-runner's own CI compiles a clean webroot, and `tests/compile-mixed/` (a good `index.cfm` plus broken files under `sub/`) on every Lucee version in its matrix, asserting that both errors are reported and the run fails without executing `index.cfm`. See `.github/workflows/main.yml`.

**When not to use it:**

- Iterating locally on a single script — adds startup cost for no benefit.
- Webroots with large amounts of unrelated CFML (e.g. a full app when you only want to run one test) — you'll pay the full compile cost.

### Java Flight Recorder (JFR) Profiling

Enable JFR to capture detailed performance data during script execution:
Expand Down
24 changes: 20 additions & 4 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@
</not>
</and>
</condition>
<!-- since 7.0 (LDEV-5425) an empty sysprop counts as set and hides the LUCEE_EXTENSIONS / LUCEE_BASE_CONFIG env vars, so only pass them when set -->
<condition property="extensions.isset">
<and>
<isset property="extensions"/>
<not>
<equals arg1="${extensions}" arg2=""/>
</not>
</and>
</condition>
<condition property="luceeCFConfig.isset">
<and>
<isset property="luceeCFConfig"/>
<not>
<equals arg1="${luceeCFConfig}" arg2=""/>
</not>
</and>
</condition>
</target>

<target name="use-local-jar" if="use-local-jar">
Expand Down Expand Up @@ -396,7 +413,7 @@
<isset property="use-local-jar"/>
</condition>

<java classname="org.apache.tools.ant.launch.Launcher" dir="${tempDir}/lucee" fork="true" failonerror="true" errorproperty="errorOut" resultproperty="resultOut">
<java classname="org.apache.tools.ant.launch.Launcher" dir="${tempDir}/lucee" fork="true" failonerror="true">
<classpath path="${java.class.path}">
<pathelement location="${lucee.jar.path}"/>
<pathelement path="${runtime_classpath}"/>
Expand All @@ -410,13 +427,13 @@
<jvmarg value="-Dexecute=${execute}"/>
<jvmarg value="-DexecuteScriptByInclude=${executeScriptByInclude}"/>
<jvmarg value="-DextensionDir=${extensionDir}"/>
<jvmarg value="-Dlucee.extensions=${extensions}"/>
<jvmarg value="-Dlucee.extensions=${extensions}" if:set="extensions.isset"/>
<jvmarg value="-Dlucee.mapping.first=true"/>
<jvmarg value="-Dcompile=${compile}"/>
<!--
<jvmarg value="-Dlucee.cli.printExceptions=true"/>
-->
<jvmarg value="-Dlucee.base.config=${luceeCFConfig}"/>
<jvmarg value="-Dlucee.base.config=${luceeCFConfig}" if:set="luceeCFConfig.isset"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5000" if:true="${debugger}"/>
<jvmarg value="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=localhost:${jdwpPort}" if:true="${jdwp}"/>
<jvmarg value="--add-opens=java.base/java.lang=ALL-UNNAMED" if:set="javaAgent.isset"/>
Expand Down Expand Up @@ -449,7 +466,6 @@
<jvmarg value="-Dhttp.proxyPort=8188"/>
-->
</java>
<echo>${errorOut}</echo>
<delete dir="${tempDir}" if:true="${postCleanup}"/>
<echo message="JFR log: ${jfrLogname}" if:true="${FlightRecording}" />
<echo message="Finished!" />
Expand Down
3 changes: 3 additions & 0 deletions tests/base-config/.CFConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"timezone": "Pacific/Chatham"
}
7 changes: 7 additions & 0 deletions tests/base-config/index.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<cfscript>
// .CFConfig.json here sets the timezone, CI passes a copy via the LUCEE_BASE_CONFIG env var (Lucee writes its config back to that file)
tz = getTimeZone();
systemOutput( "timezone [#tz#]", true );
if ( tz != "Pacific/Chatham" )
throw( message="LUCEE_BASE_CONFIG wasn't applied, timezone is [#tz#], expected [Pacific/Chatham]" );
</cfscript>
3 changes: 3 additions & 0 deletions tests/compile-mixed/index.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<cfscript>
systemOutput( "compile-mixed index.cfm ran", true );
</cfscript>
3 changes: 3 additions & 0 deletions tests/compile-mixed/sub/BadComponent.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
component {
function broken( {
}
1 change: 1 addition & 0 deletions tests/compile-mixed/sub/badpage.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<cfoutput>#name</cfoutput>
Loading