feat: implement the 4.x backlog — DI factories, route bindBy, auth facade, CLI diff/dry-run - #3454
Merged
Conversation
… deprecation Signed-off-by: Peter Amiri <peter@alurium.com>
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>
…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>
…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>
- 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>
Signed-off-by: Peter Amiri <peter@alurium.com>
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>
Signed-off-by: Peter Amiri <peter@alurium.com>
…tion Signed-off-by: Peter Amiri <peter@alurium.com>
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>
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>
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>
…paths Signed-off-by: Peter Amiri <peter@alurium.com>
…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>
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>
Signed-off-by: Peter Amiri <peter@alurium.com>
…gnostic 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the 4.x backlog (
docs/releases/wheels-4.x-backlog.md) — every item except i18n (deferred, separate product decision) and the upstream LuCLI items. All suites green: core 5,557 specs (0 fail / 0 error), CLI 1,274 specs (0 fail / 0 error).Framework
toFactory()—map("x").toFactory(function(ctx){...}); the closure receives the container, honors singleton/request-scoped flags, participates incontainsInstance/isFactory/snapshot-restore unwind.bindBy=—resources(name="posts", binding=true, bindBy="slug")resolves the:keysegment via the parameterizedfindOneBy<Property>()finder; orthogonal tobinding=(model selection).enableSession()— new global helper (vendor/wheels/global/auth.cfm) that collapses the two-file session-auth wiring into one idempotent call inconfig/services.cfm.wheels.Testemits a one-time$deprecatedwarning.h()/hAttr()are the escaping helpers.CLI
wheels migrate diff(dbmigrate diff) — AutoMigrator schema diffs via the bridge:--rename OLD:NEW/Model.OLD:NEW,--hints JSON,--threshold,--name,--write. MCPmigrateregistered;--action=form normalized.wheels generate --dry-run— prints would-be paths across all generators, writes nothing.--offline/WHEELS_OFFLINE=1; skips the update check, registry fails fast.mod.__arguments) now consumes thethis-scope shape,deploy()constructsDeployMainClilazily (secrets verbs no longer requireconfig/deploy.yml), and$deploySecretsVerbdefaultsprojectRootto the module cwd.Infra
wheels.json/box.jsonversion instead of showing0.0.0-dev.boot:config —Boot.cfc(limit10,wait5),Config.boot(), validator allowlist.wheels doctorchecks — legacywheels.Test/wheels.Testboxspecs, populatedplugins/, and rawparams.mass assignment (warn-only).Repo hygiene
allow_merge_commit=false); vestigialwheels-cli-lucliarchived; emptypackages/shells deleted;user-mailer.txt+ mailers README rewritten to the realsendEmail()pattern;config/services.cfmscaffold stub added.Still open (documented in the backlog)
wt-bcrypt), lands as a separate PR.Changelog fragments included for all user-facing additions.