From 740eb5b55804134c1977dd39cd8170e2fa615d35 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Fri, 1 May 2026 21:49:37 +0900 Subject: feat(core): reject root composer.json that requires its own name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors Composer\Package\Loader\RootPackageLoader::load(): if the root package's "name" appears as a key in its own "require" or "require-dev" map, fail loudly before reaching the resolver. Without this, Mozart would silently let the request hit Packagist (which has no entry for the root's vendor/name) and report a misleading "could not be found" error. Wired into install::execute (when a lock file is present) and update::execute (the no-lock fallback path). Carries the same wording as Composer's RuntimeException so a future EXPECT-OUTPUT comparison will match. Also extends the installer test harness: when a fixture sets EXPECT-EXCEPTION but no EXPECT-EXIT-CODE, assert that Mozart exits non-zero. Full exception-class matching remains a follow-up (see .ken/test_design.md ยง7.2). Closes the gap exercised by the install-self-from-root installer fixture. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/mozart/src/commands/install.rs | 1 + crates/mozart/src/commands/update.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'crates/mozart/src') diff --git a/crates/mozart/src/commands/install.rs b/crates/mozart/src/commands/install.rs index f920f02..b9ff1af 100644 --- a/crates/mozart/src/commands/install.rs +++ b/crates/mozart/src/commands/install.rs @@ -809,6 +809,7 @@ pub async fn execute( } let root_pkg = mozart_core::package::read_from_file(&composer_json_path)?; + root_pkg.validate_root_does_not_self_require()?; let missing = lock.get_missing_requirement_info(&root_pkg, dev_mode); if !missing.is_empty() { for line in &missing { diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs index da2fd95..3a468d4 100644 --- a/crates/mozart/src/commands/update.rs +++ b/crates/mozart/src/commands/update.rs @@ -747,6 +747,7 @@ pub async fn execute( )); } let composer_json = package::read_from_file(&composer_json_path)?; + composer_json.validate_root_does_not_self_require()?; let composer_json_content = std::fs::read_to_string(&composer_json_path)?; let lock_path = working_dir.join("composer.lock"); -- cgit v1.3.1