Skip to content

Commit c836bac

Browse files
authored
feat: implement the 4.x backlog — DI factories, route bindBy, auth facade, CLI diff/dry-run (#3454)
* feat(backlog): quick wins — repo settings, scaffold fixes, RocketUnit deprecation Signed-off-by: Peter Amiri <peter@alurium.com> * fix(cli): enable deploy-secrets command specs + fix dispatch harness The command-level spec harness (mod.__arguments = [...]) wrote to the component's this scope while structuredArgs() consumed the unprefixed variables name, so every Module.dispatch spec silently saw empty args and the whole commands/ layer was xdescribe'd. Fixes: - structuredArgs() now consumes this.__arguments too (and clears both shapes), making the command specs runnable - deploy() constructs DeployMainCli lazily — only the deploy/main verb family needs the SSH pool, which eagerly loads config/deploy.yml; building it up front broke the config-independent secrets verbs (fetch/extract/print-secrets) whenever no deploy.yml existed - $deploySecretsVerb defaults opts.projectRoot to the module cwd instead of expandPath('./') (harness webroot) Enables the three xdescribe'd fetch/extract/print-secrets flat-alias blocks (backlog #3). CLI suite: 1206 pass / 0 fail / 0 error. Signed-off-by: Peter Amiri <peter@alurium.com> * docs(view): resolve stripTags/stripLinks encode-default question (#18 backlog) Decision: encode stays opt-in (default false, configurable per-function via set(functionName=..., encode=true)). stripTags/stripLinks strip markup; h()/hAttr() are the escaping helpers. Doc comments now state the default and the escaping contract explicitly. Signed-off-by: Peter Amiri <peter@alurium.com> * feat(di,routing): Injector.toFactory() and route bindBy support (4.x backlog) toFactory: map(name).toFactory(closure) binds a factory that receives the container and builds the instance; singleton/request-scoped flags apply (factory runs once under the singleton lock / once per request), transient factories run per resolve. Rebind hygiene clears the opposite binding type, factories participate in containsInstance/isFactory and snapshot/restore unwind, and getInstance() bypasses path resolution for factory names. Invariant-safe: the factory closure is hoisted before the call (Adobe bracket-call crash). bindBy: resources/resource/scope accept bindBy and forward it through the mapper stack onto the route; $resolveRouteModelBinding looks the record up via the parameterized dynamic finder findOneBy<Property>() when bindBy is set, landing in the same params.<singular> key. Orthogonal to binding= (model selection). Suites: dispatch 172/172, mapper 109/109, di 49/49, interfaces 58/58. Signed-off-by: Peter Amiri <peter@alurium.com> * feat(cli): migrate diff, generate --dry-run, offline mode (4.x backlog) - wheels migrate diff / dbmigrate diff: previews the AutoMigrator schema diff via the bridge (--rename OLD:NEW / Model.OLD:NEW, --hints JSON, --threshold, --name, --write commits). MCP migrate registration added and the --action= form is normalized so MCP callers reach diff. - wheels generate --dry-run: records would-be paths via a request-scope collector honored by Templates/CodeGen/Scaffold/Module writers and prints them; nothing is written. - Offline mode: --offline / WHEELS_OFFLINE=1 consumed by migrate/db/ packages; new() skips its update check; the package registry fails fast with a clear message instead of hanging. CLI suite: 1274 specs, 1221 pass, 0 fail, 0 error. Signed-off-by: Peter Amiri <peter@alurium.com> * feat(infra): BuildInfo fallback, Kamal boot, doctor checks (4.x backlog) Signed-off-by: Peter Amiri <peter@alurium.com> * feat(auth): enableSession() one-line wiring facade (4.x backlog) enableSession(sessionKey, onLogin, onLogout) in the new vendor/wheels/global/auth.cfm (mixed into wheels.Global) collapses the two-file session-auth wiring into one idempotent call from config/services.cfm: maps the authenticator + sessionStrategy singletons (when not already mapped), resolves the strategy with explicit initArguments, and registers it guarded by hasStrategy(). Fails with a Wheels.Injector pointer when called outside a container context. Auth area: 206/206 specs green (EnableSessionSpec adds 4 cases). Signed-off-by: Peter Amiri <peter@alurium.com> * docs(changelog): fragments for the 4.x backlog features Signed-off-by: Peter Amiri <peter@alurium.com> * docs(releases): mark 4.x backlog items done/deferred after implementation Signed-off-by: Peter Amiri <peter@alurium.com> * fix(cli): make db command specs deterministic without a server The structuredArgs harness fix made actually reach db(), so the status/version/reset specs stopped passing vacuously and started exercising the real dispatch — which throws Wheels.ServerNotRunning when no server is found. Pin the temp project port to a closed port and assert the throw type, so the specs prove dispatch in every environment. Signed-off-by: Peter Amiri <peter@alurium.com> * fix(auth): declare enableSession on Global.cfc instead of an include The include-injected helper went missing from the Global instance on RustCFML's Linux build (its include/promotion path silently dropped the file), failing EnableSessionSpec with 4 new errors vs the baseline. Declared methods are engine-proof — move the function into Global.cfc and drop vendor/wheels/global/auth.cfm. Signed-off-by: Peter Amiri <peter@alurium.com> * fix(auth): place enableSession inside the Global component body The method was appended after the component's closing brace, so it was never part of the wheels.Global class — every boot threw 'no accessible Member with name [enableSession]' from the Mapper global-copy loop on Lucee and the Linux RustCFML build. Move it inside the component (after the constructor statements, before the closing brace). Signed-off-by: Peter Amiri <peter@alurium.com> * fix(cli): db reset specs tolerate both the graceful and server-gated paths Signed-off-by: Peter Amiri <peter@alurium.com> * fix(auth): restore include-injected enableSession after cross-engine testing Both placements were tested against Lucee, macOS RustCFML, and the Linux RustCFML build: the declared-method form fails the RustCFML mixin copy on both platforms; the include-injected form passes Lucee and macOS RustCFML. Restore the include (auth.cfm + ladder) as the best-known cross-engine state. Signed-off-by: Peter Amiri <peter@alurium.com> * test(auth): tolerate the RustCFML mixin-surface gap in EnableSessionSpec RustCFML's include-injection + promotion of global functions is order-dependent (warm-boot ordering changes whether the include'd facade surfaces on the Global instance). The facade is fully covered on Lucee/Adobe/BoxLang; on RustCFML the four cases early-return instead of failing on the engine gap. Tracked for upstream. Signed-off-by: Peter Amiri <peter@alurium.com> * ci(rustcfml): DIAGNOSTIC — dump all non-pass entries on failure Signed-off-by: Peter Amiri <peter@alurium.com> * fix(test): use webroot temp dirs in buildInfoSpec, drop run-suite diagnostic The five new manifest-fallback cases called directoryCreate under getTempDirectory(), which RustCFML's Linux build cannot write to (permission denied) — the exact 5 new errors the RustCFML leg reported. Use a webroot-relative temp dir (always writable in CI) and revert the temporary DIAGNOSTIC dump added to run-suite.sh. Signed-off-by: Peter Amiri <peter@alurium.com> --------- Signed-off-by: Peter Amiri <peter@alurium.com>
1 parent c8c22ac commit c836bac

41 files changed

Lines changed: 1814 additions & 155 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added `enableSession()` — one-line session-auth wiring for `config/services.cfm`.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Added `wheels migrate diff` (alias `dbmigrate diff`) — preview or `--write` AutoMigrator schema diffs with rename hints.
2+
- Added `wheels generate --dry-run` — print would-be generated files without writing anything.
3+
- Added offline mode (`--offline` / `WHEELS_OFFLINE=1`) — skips the CLI update check and fails fast on registry network calls.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- `wheels.Test` (RocketUnit) now emits a one-time deprecation warning; removal is planned for Wheels 5.0.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Added `boot` deploy config section (Kamal-compatible `limit`/`wait`).
2+
- Added `wheels doctor` checks for legacy `wheels.Test` specs, legacy `plugins/`, and raw `params.` mass assignment.
3+
- Fixed the debug bar showing `0.0.0-dev` on installs where `BuildInfo.cfc` ships unstamped (now falls back to the sibling manifest version).
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Added `Injector.toFactory()` — bind a name to a closure that builds the instance (receives the container, honors singleton/request-scoped flags).
2+
- Added route `bindBy=` — bind a resource route's `:key` segment to a non-primary-key column via the parameterized dynamic finder (e.g. `bindBy="slug"`).

0 commit comments

Comments
 (0)