Skip to content

Commit 2efe970

Browse files
committed
Merge branch '7.0' into 7.1
Bump version to 7.1.0.201-SNAPSHOT.
2 parents 170661a + f4bf78b commit 2efe970

6 files changed

Lines changed: 169 additions & 15 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ target/*
1919
*.cfc.hbm.xml
2020
/cache
2121
WEB-INF
22-
22+
core/bin/
23+
loader/bin/
2324
.classpath
2425
*.eml
2526
*.iml

README.md

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,94 @@ Lucee simplifies technologies like webservices (REST, SOAP, HTTP), ORM (Hibernat
99

1010
Lucee provides a compatibility layer for Adobe ColdFusion © CFML using less resources and delivering better performance.
1111

12-
[What is new with Lucee 6](README-Lucee6.md)
12+
## What's New
13+
14+
- [Lucee 7.1](https://docs.lucee.org/guides/lucee-7-1.html)
15+
- [Lucee 7](https://docs.lucee.org/guides/lucee-7.html)
16+
- [Lucee 6.2](https://docs.lucee.org/guides/lucee-6.2.html)
17+
- [Lucee 5.3 "Kabang"](https://docs.lucee.org/guides/lucee-5.3-kabang.html)
18+
- [Lucee 5](https://docs.lucee.org/guides/lucee-5.html)
19+
- Lucee 8.0 (coming soon)
1320

1421
## Changelogs
1522

16-
- [Changelogs per Release](https://download.lucee.org/changelog/?version=6.2)
23+
- [Changelogs per Release](https://download.lucee.org/changelog/)
1724
- [New Tags & Functions, Arguments and Attributes](https://docs.lucee.org/reference/changelog.html)
1825

19-
### Breaking changes
26+
### Breaking Changes
27+
28+
See all breaking changes documentation at [docs.lucee.org/recipes](https://docs.lucee.org/recipes.html):
2029

21-
- [Breaking Changes Between Lucee 5.4 and 6.0](https://docs.lucee.org/recipes/breaking-changes-6-0.html)
22-
- [Breaking Changes Between Lucee 6.0 and 6.1](https://docs.lucee.org/recipes/breaking-changes-6-1.html)
23-
- [Breaking Changes Between Lucee 6.1 and 6.2](https://docs.lucee.org/recipes/breaking-changes-6-2.html)
2430
- [Breaking Changes Between Lucee 6.2 and 7.0](https://docs.lucee.org/recipes/breaking-changes-7.html)
31+
- [Breaking Changes Between Lucee 7.0 and 7.1](https://docs.lucee.org/recipes/breaking-changes-7-1.html)
32+
- [Breaking Changes Between Lucee 7.1 and 8.0](https://docs.lucee.org/recipes/breaking-changes-8-0.html) (coming soon)
2533

2634
## Installation
2735

28-
You can [build Lucee from source](https://docs.lucee.org/guides/working-with-source.html) or grab one of our distributions:
36+
You can [build Lucee from source](https://docs.lucee.org/guides/working-with-source.html) or download a distribution from [download.lucee.org](https://download.lucee.org/). We also provide [official Docker images and Dockerfiles](https://github.com/lucee/lucee-dockerfiles).
37+
38+
## LuCLI
39+
40+
[LuCLI](https://lucli.dev/) is a command-line interface for Lucee development and deployment. It provides server lifecycle management, CFML script execution, module system, dependency management, and AI integration — all from the terminal.
41+
42+
**Quick Start:**
43+
44+
```bash
45+
curl -LsSf https://lucli.dev/install.sh | sh
46+
# Windows:
47+
powershell -ExecutionPolicy Bypass -NoProfile -Command "irm https://lucli.dev/install.ps1 | iex"
48+
```
49+
50+
Requires Java 17+.
51+
52+
**Core Features:**
53+
54+
- **Server Management** — Start, stop, restart, and monitor Lucee servers with `lucli server` commands
55+
- **CFML Execution** — Run `.cfs` scripts, `.cfm` templates, or `.cfc` components directly from the CLI
56+
- **Project Configuration**`lucee.json` for per-project server settings (port, Lucee version, JVM memory, environment variables)
57+
- **Module System** — Create and install reusable CLI modules in `~/.lucli/modules/`
58+
- **Dependency Management** — Manage CFML libraries and Lucee extensions with automatic git/Maven resolution
59+
- **Secrets Management** — Store and inject encrypted secrets into your Lucee servers
60+
- **AI Integration** — Configure LLM endpoints and run AI prompts with skill support
61+
- **Daemon Mode** — Run LuCLI as a background service for programmatic access
62+
- **Batch Scripts** — Execute sequences of commands with `.lucli` batch files
63+
64+
**Example `lucee.json`:**
65+
66+
```json
67+
{
68+
"name": "my-project",
69+
"lucee": { "version": "6.2.2" },
70+
"port": 8080,
71+
"webroot": "./",
72+
"jvm": { "maxMemory": "512m" },
73+
"dependencies": {
74+
"cfwheels": { "type": "cfml", "source": "git", "url": "https://github.com/cfwheels/cfwheels" }
75+
}
76+
}
77+
```
78+
79+
**Documentation:** [lucli.dev/docs](https://lucli.dev/docs/) | **GitHub:** [cybersonic/LuCLI](https://github.com/cybersonic/LuCLI)
80+
81+
## AI Assistants & Developer Tools
82+
83+
### Lucee Skill for AI Assistants
84+
85+
A machine-readable skill so your AI assistant knows modern Lucee. Drop-in context for Cursor, Copilot, Warp, Claude, ChatGPT, and more. Always aligned with the latest docs.
86+
87+
- [skill.lucee-services.com/main.skill](https://skill.lucee-services.com/main.skill)
88+
- [docs.lucee.org/lucee.skill](https://docs.lucee.org/lucee.skill)
89+
90+
### Lucee MCP Server
2991

30-
- [Lucee Express](https://lucee.org/downloads.html) (just unzip and run; delete to clean up)
31-
- [Installers for Windows, Linux and OSX](https://lucee.org/downloads.html)
32-
- [Official Dockerfiles and Docker images](https://github.com/lucee/lucee-dockerfiles)
92+
Hosted by Lucee, gives your AI callable tools for Lucee documentation and CFML code analysis.
3393

34-
Alternatively try the super-useful [CommandBox](https://www.ortussolutions.com/products/commandbox) standalone developer tools for CFML powered by Lucee.
94+
**Tools:**
95+
- `search_lucee_docs` — search functions, tags, and recipes in the Lucee docs
96+
- `get_lucee_function` — full descriptor for a built-in function (arguments, types, examples)
97+
- `get_lucee_tag` — full descriptor for a tag (attributes, types, examples)
98+
- `parse_cfml_ast` — parse CFML source into an AST (tags, calls, control flow)
99+
- `query_cfml_ast` — query an AST by node type, name, or line number
35100

36101
## Building Lucee from Source
37102

core/src/main/java/lucee/runtime/schedule/ScheduledTaskThread.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public void _run() {
191191
break;
192192
}
193193
if (!task.isPaused()) {
194-
if (endDate < todayDate && endTime < todayTime) {
194+
if (hasEndDatePassed(endDate, endTime, todayDate, todayTime)) {
195195
log(Log.LEVEL_ERROR, String.format("End date %s has passed; now: %s", DateTimeUtil.format(endDate + endTime, null, timeZone),
196196
DateTimeUtil.format(todayDate + todayTime, null, timeZone)));
197197
break;
@@ -474,6 +474,13 @@ private static void revertDST(Calendar c, int hourExpected, int intervall, int a
474474
}
475475
}
476476

477+
public static boolean hasEndDatePassed(long endDate, long endTime, long todayDate, long todayTime) {
478+
// endDate is Long.MAX_VALUE when no end date was defined (see constructor) -> task never expires,
479+
// regardless of endTime; without this guard "endDate + endTime" overflows and wrongly looks like the past
480+
if (endDate == Long.MAX_VALUE) return false;
481+
return endDate + endTime < todayDate + todayTime;
482+
}
483+
477484
public static long getMilliSecondsInDay(Calendar c) {
478485
return (c.get(Calendar.HOUR_OF_DAY) * 3600000) + (c.get(Calendar.MINUTE) * 60000) + (c.get(Calendar.SECOND) * 1000) + (c.get(Calendar.MILLISECOND));
479486
}

loader/build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<project default="core" basedir="." name="Lucee"
33
xmlns:resolver="antlib:org.apache.maven.resolver.ant">
44

5-
<property name="version" value="7.1.0.200-SNAPSHOT"/>
5+
<property name="version" value="7.1.0.201-SNAPSHOT"/>
66

77
<taskdef uri="antlib:org.apache.maven.resolver.ant" resource="org/apache/maven/resolver/ant/antlib.xml">
88
<classpath>

loader/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<groupId>org.lucee</groupId>
55
<artifactId>lucee</artifactId>
6-
<version>7.1.0.200-SNAPSHOT</version>
6+
<version>7.1.0.201-SNAPSHOT</version>
77
<packaging>jar</packaging>
88

99
<name>Lucee Loader Build</name>

test/general/Scheduler.cfc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,87 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{
6060
expect(dateAdd("l",next,UNIX0)).toBe(createDateTime(2021,1,15,11,1,31,0,"CET"));
6161
});
6262
// public static long calculateNextExecutionEvery(DateTimeUtil util, long now, boolean notNow, TimeZone timeZone, long start, long endTime, int amount) {
63+
64+
it(title="LDEV-6426: an 'every N minutes' task with only an end time must stop firing after that time each day and resume the next day", body=function(){
65+
var util=DateTimeUtil.getInstance();
66+
var tz=TimeZone.getDefault();
67+
68+
var start=createDateTime(2020,11,1,9,0,0,0,"CET").getTime();
69+
// endTime as stored on the real task is milliseconds-in-day, not an absolute timestamp (see constructor)
70+
var endTime=util.getMilliSecondsInDay(tz, createDateTime(2021,1,1,17,0,0,0,"CET").getTime());
71+
72+
// already past today's 17:00 cutoff -> next run must be tomorrow's start time, not another run today
73+
var now=createDateTime(2021,1,15,17,1,0,0,"CET").getTime();
74+
75+
var next=ScheduledTaskThread.calculateNextExecutionEvery(util, now, true, tz, start, endTime, 300);
76+
expect(dateAdd("l",next,UNIX0)).toBe(createDateTime(2021,1,16,9,0,0,0,"CET"));
77+
});
78+
79+
it(title="LDEV-6426: task must stop after its end date even when no explicit end time was set", body=function(){
80+
var util=DateTimeUtil.getInstance();
81+
var tz=TimeZone.getDefault();
82+
var DAY=24*3600000;
83+
84+
// end date is yesterday (midnight), no explicit end time -> defaults to a full day duration (see ScheduledTaskThread constructor)
85+
var endDate=createDateTime(2021,1,14,0,0,0,0,"CET").getTime();
86+
var endTime=DAY;
87+
88+
// "now" has a small time-of-day component; the old buggy check (endDate < todayDate && endTime < todayTime)
89+
// never matched here because endTime (a full day) is never smaller than todayTime
90+
var now=createDateTime(2021,1,15,1,0,0,0,"CET").getTime();
91+
var todayTime=util.getMilliSecondsInDay(tz, now);
92+
var todayDate=now-todayTime;
93+
94+
expect(ScheduledTaskThread.hasEndDatePassed(endDate, endTime, todayDate, todayTime)).toBeTrue();
95+
});
96+
97+
it(title="LDEV-6426: task must keep running while still within its end date", body=function(){
98+
var util=DateTimeUtil.getInstance();
99+
var tz=TimeZone.getDefault();
100+
var DAY=24*3600000;
101+
102+
var endDate=createDateTime(2021,1,20,0,0,0,0,"CET").getTime();
103+
var endTime=DAY;
104+
105+
var now=createDateTime(2021,1,15,1,0,0,0,"CET").getTime();
106+
var todayTime=util.getMilliSecondsInDay(tz, now);
107+
var todayDate=now-todayTime;
108+
109+
expect(ScheduledTaskThread.hasEndDatePassed(endDate, endTime, todayDate, todayTime)).toBeFalse();
110+
});
111+
112+
it(title="LDEV-6426: task without any end date must never expire (no endDate, no endTime)", body=function(){
113+
var util=DateTimeUtil.getInstance();
114+
var tz=TimeZone.getDefault();
115+
var DAY=24*3600000;
116+
var MAX=createObject("java","java.lang.Long").MAX_VALUE;
117+
118+
// mirrors the constructor defaults when neither endDate nor endTime is provided
119+
var endDate=MAX;
120+
var endTime=DAY;
121+
122+
// far in the future, so a naive "endDate + endTime" overflow would wrongly report "passed"
123+
var now=createDateTime(2999,1,15,1,0,0,0,"CET").getTime();
124+
var todayTime=util.getMilliSecondsInDay(tz, now);
125+
var todayDate=now-todayTime;
126+
127+
expect(ScheduledTaskThread.hasEndDatePassed(endDate, endTime, todayDate, todayTime)).toBeFalse();
128+
});
129+
130+
it(title="LDEV-6426: task with only an end time (no endDate) must never expire", body=function(){
131+
var util=DateTimeUtil.getInstance();
132+
var tz=TimeZone.getDefault();
133+
var MAX=createObject("java","java.lang.Long").MAX_VALUE;
134+
135+
var endDate=MAX;
136+
var endTime=util.getMilliSecondsInDay(tz, createDateTime(2021,1,1,18,0,0,0,"CET").getTime());
137+
138+
var now=createDateTime(2999,1,15,1,0,0,0,"CET").getTime();
139+
var todayTime=util.getMilliSecondsInDay(tz, now);
140+
var todayDate=now-todayTime;
141+
142+
expect(ScheduledTaskThread.hasEndDatePassed(endDate, endTime, todayDate, todayTime)).toBeFalse();
143+
});
63144
});
64145
}
65146
}

0 commit comments

Comments
 (0)