Skip to content

Conversation

@terabytesoftw
Copy link
Contributor

Pull Request

Q A
Is bugfix? ✔️
New feature?
Breaks BC?

@terabytesoftw terabytesoftw added the Estado: error Algo no funciona label Jan 23, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added comprehensive test coverage for platform requirement handling configurations.
  • Bug Fixes

    • Bug #117: Upgraded PHPStan static analysis to level 5 for stricter code quality standards.
  • Documentation

    • Updated quality badge in README to reflect PHPStan level 5.
  • Chores

    • Removed static analysis baseline configuration due to higher strictness level.
    • Improved code reliability through stricter type checking and validation across the codebase.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Raises PHPStan from level 2 to 5, removes the phpstan baseline ignore rules, and updates code and tests to satisfy stricter static analysis: tightened boolean/string checks, refined regexes, small API-safe refactors, and added ComposerFallback tests. No public API signature regressions.

Changes

Cohort / File(s) Summary
Config & Tooling
CHANGELOG.md, README.md, phpstan.neon, phpstan-baseline.neon
PHPStan level bumped to 5; phpstan-baseline.neon ignoreErrors removed; README badge and changelog entry updated.
Asset core
src/Asset/AbstractAssetManager.php, src/Asset/AssetManagerFinder.php
Tighter root-package-dir checks and return/result propagation; added @throws doc; removed runtime instance filtering in finder constructor.
Fallbacks / Composer
src/Fallback/ComposerFallback.php, src/Fallback/AssetFallback.php
Constructors switch to null-coalescing defaults; strict checks for boolean-like options (true, 1, '1'); normalized option handling and restore flow refactors.
JSON / Formatting utilities
src/Config/Config.php, src/Json/JsonFormatter.php
Use strict JSON_ERROR_NONE check and return decoded JSON directly; simplified regexes and match handling in JSON formatter; streamlined callbacks.
Semver & path utils
src/Converter/SemverUtil.php, src/Util/AssetUtil.php
Added protected static cleanWildcard(string): string and switched to \d in regexes; broadened root-package-json-dir append condition in path logic.
Core flow & CLI
src/Foxy.php, src/Solver/Solver.php, src/Util/ConsoleUtil.php
Tightened enabled/option checks to explicit true/1/'1'; refined guards for error handling and filename validation; explicit option retrieval and boolean casting.
Tests & Fixtures
tests/... (e.g., tests/FoxyTest.php, tests/Solver/SolverTest.php, tests/Fallback/ComposerFallbackTest.php, tests/Fixtures/*, tests/Util/*)
Test updates including constructor property promotion in a stub, docblock cleanups, removed conditional constructor branches, new ComposerFallback tests for ignore-platform-req(s), and some assertions replaced with expectNotToPerformAssertions().

Sequence Diagram(s)

(Skipped — changes are configuration, validation tightening, and test updates rather than a new multi-component sequential feature.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through files with careful paws,
Tightened types and fixed up flaws.
Baselines cleared, the checks now thrive,
Tests hum softly—code feels alive. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective of the PR: raising PHPStan from level 2 to level 5 across the codebase, though 'tests' is somewhat narrow given the extensive code changes beyond just tests.
Description check ✅ Passed The description provides a metadata table indicating this is a bugfix with no new features or BC breaks, which is relevant to understanding the PR's scope and intent.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db5ac2d and e24bd4c.

📒 Files selected for processing (1)
  • src/Fallback/ComposerFallback.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: User terabytesoftw prefers not to use aliases when importing classes in PHP. They are comfortable with either fully-qualified class names or direct imports without aliases.
Learnt from: terabytesoftw
Repo: php-forge/support PR: 12
File: src/TestSupport.php:0-0
Timestamp: 2025-08-18T20:13:33.518Z
Learning: User terabytesoftw prefers clean trait-based designs over maintaining backward compatibility wrappers when refactoring utility classes in the php-forge/support project.
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 65
File: .github/workflows/composer-require-checker.yml:80-83
Timestamp: 2025-09-28T15:12:48.345Z
Learning: The user terabytesoftw prefers using floating tags like v1 for third-party actions in GitHub workflows instead of pinning to specific commit SHAs, even when it's a security best practice to pin to immutable commits.
📚 Learning: 2025-09-29T14:58:04.095Z
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 67
File: .github/workflows/phpstan.yml:13-16
Timestamp: 2025-09-29T14:58:04.095Z
Learning: In the php-forge/actions repository, the maintainer prefers using "composer update" as the default command in CI workflows to ensure the latest dependencies are always installed, rather than using "composer install" for reproducibility.

Applied to files:

  • src/Fallback/ComposerFallback.php
📚 Learning: 2026-01-23T11:09:08.789Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: composer.json:68-77
Timestamp: 2026-01-23T11:09:08.789Z
Learning: In the php-forge organization repositories, terabytesoftw prefers using the main branch reference in composer.json sync-metadata scripts when downloading configuration files from external template repositories, rather than pinning to specific commit SHAs or tags, even though pinning provides more stability and prevents unexpected changes.

Applied to files:

  • src/Fallback/ComposerFallback.php
🧬 Code graph analysis (1)
src/Fallback/ComposerFallback.php (3)
src/Fallback/AssetFallback.php (1)
  • restore (28-55)
src/Config/Config.php (1)
  • get (37-55)
src/Util/ConsoleUtil.php (2)
  • ConsoleUtil (17-79)
  • getPreferredInstallOptions (48-78)
🪛 PHPMD (2.15.0)
src/Fallback/ComposerFallback.php

143-143: Avoid using static access to class '\Foxy\Util\ConsoleUtil' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)


176-182: The method restorePreviousLockFile uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)

(ElseExpression)


184-184: Avoid using static access to class '\Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
🔇 Additional comments (6)
src/Fallback/ComposerFallback.php (6)

41-41: Null-safe filesystem initialization looks correct.

Clearer and avoids unintended fallback on falsey values.


49-52: Strict fallback enablement check is consistent.

Matches the boolean-like gating used elsewhere and avoids accidental enablement.


125-129: Lock data now correctly treats dev-only packages as valid.

Good defensive handling for dev-only lockfiles.


143-168: Installer option normalization is clean and comprehensive.

Good consolidation of option precedence and clear dev/autoloader handling.


170-184: ignore-platform-req(s) precedence is well-defined.

The selection logic is clear and correctly feeds the platform filter.


185-188: Script execution toggle is now correctly derived.

Aligns installer script behavior with the no-scripts option.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (ae57c39) to head (e24bd4c).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff             @@
##                main      #117   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity       347       359   +12     
===========================================
  Files             26        26           
  Lines            799       821   +22     
===========================================
+ Hits             799       821   +22     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Config/Config.php (1)

127-137: Return type annotation is incorrect for all possible json_decode values.

The error handling with json_last_error() correctly detects invalid JSON, but the method's return type is declared as array when json_decode($value, true) can return mixed—including strings, integers, floats, booleans, or null for valid JSON that isn't an object or array. For example, valid JSON like "text", 123, true, or null will pass the error check but violate the array return type.

Either change the return type to mixed or add explicit validation to ensure the decoded value is an array before returning:

if (!is_array($value)) {
    throw new RuntimeException(sprintf('The "%s" environment variable must be a JSON object or array', $environmentVariable));
}
🤖 Fix all issues with AI agents
In `@src/Fallback/ComposerFallback.php`:
- Around line 180-184: The current code always disables scripts by calling
$dispatcher->setRunScripts(false) before $installer->run(); change this to
respect the user's option by computing $runScripts and setting
$dispatcher->setRunScripts($runScripts) before calling $installer->run(); if the
EventDispatcher API exposes a previous state getter (e.g. isRunScripts() or
getRunScripts()), capture the original state, set it to $runScripts for the run,
then restore the original state after $installer->run() to avoid side effects.

In `@src/Json/JsonFormatter.php`:
- Around line 112-114: The anonymous callback currently declares a string return
type but calls mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE')
which can return false; update the closure used in JsonFormatter.php to either
(a) remove the explicit ": string" return type, or (b) handle the false case
defensively by checking the mb_convert_encoding() result and returning a safe
fallback (e.g., empty string or throw) so the closure always yields a string;
reference the anonymous static function, mb_convert_encoding, and pack('H*',
$match[1]) when making the change.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae57c39 and 9fa4dd2.

📒 Files selected for processing (23)
  • CHANGELOG.md
  • README.md
  • phpstan-baseline.neon
  • phpstan.neon
  • src/Asset/AbstractAssetManager.php
  • src/Asset/AssetManagerFinder.php
  • src/Config/Config.php
  • src/Converter/SemverUtil.php
  • src/Fallback/AssetFallback.php
  • src/Fallback/ComposerFallback.php
  • src/Foxy.php
  • src/Json/JsonFormatter.php
  • src/Solver/Solver.php
  • src/Util/AssetUtil.php
  • src/Util/ConsoleUtil.php
  • tests/Config/ConfigTest.php
  • tests/Fixtures/Asset/StubAssetManager.php
  • tests/Fixtures/Util/AbstractProcessExecutorMock.php
  • tests/FoxyTest.php
  • tests/Solver/SolverTest.php
  • tests/Util/AssetUtilTest.php
  • tests/Util/ComposerUtilTest.php
  • tests/Util/ConsoleUtilTest.php
💤 Files with no reviewable changes (3)
  • phpstan-baseline.neon
  • tests/Util/AssetUtilTest.php
  • tests/Util/ConsoleUtilTest.php
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: User terabytesoftw prefers not to use aliases when importing classes in PHP. They are comfortable with either fully-qualified class names or direct imports without aliases.
Learnt from: terabytesoftw
Repo: php-forge/support PR: 12
File: src/TestSupport.php:0-0
Timestamp: 2025-08-18T20:13:33.518Z
Learning: User terabytesoftw prefers clean trait-based designs over maintaining backward compatibility wrappers when refactoring utility classes in the php-forge/support project.
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 65
File: .github/workflows/composer-require-checker.yml:80-83
Timestamp: 2025-09-28T15:12:48.345Z
Learning: The user terabytesoftw prefers using floating tags like v1 for third-party actions in GitHub workflows instead of pinning to specific commit SHAs, even when it's a security best practice to pin to immutable commits.
📚 Learning: 2026-01-22T11:42:32.878Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 111
File: tests/Fallback/AssetFallbackTest.php:98-98
Timestamp: 2026-01-22T11:42:32.878Z
Learning: When using xepozz/internal-mocker in PHP tests, the library's namespaced wrapper records and matches function calls with all default parameters filled in. To ensure proper matching, always specify every parameter in MockerState::addCondition(), including defaults. For example, a call to file_get_contents($path) is observed as file_get_contents($path, false, null, 0, null). Use the same complete argument list (including default values) when adding conditions for mocks in tests like tests/Fallback/AssetFallbackTest.php.

Applied to files:

  • tests/Config/ConfigTest.php
  • tests/Fixtures/Asset/StubAssetManager.php
  • tests/FoxyTest.php
  • tests/Fixtures/Util/AbstractProcessExecutorMock.php
  • tests/Util/ComposerUtilTest.php
  • tests/Solver/SolverTest.php
📚 Learning: 2026-01-23T11:22:00.118Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: In PHP tests (e.g., tests/Fallback/AssetFallbackTest.php) avoid using import aliases. Prefer either importing the full namespace without an alias or using fully-qualified class names directly. For example, avoid statements like 'use Some\Long\Namespace as Alias;' and either 'use Some\\Long\\Namespace;' or reference 'Some\\Long\\Namespace' in code. This guideline applies to PHP files under tests and improves readability and refactor safety.

Applied to files:

  • tests/Config/ConfigTest.php
  • tests/Fixtures/Asset/StubAssetManager.php
  • tests/FoxyTest.php
  • tests/Fixtures/Util/AbstractProcessExecutorMock.php
  • tests/Util/ComposerUtilTest.php
  • tests/Solver/SolverTest.php
📚 Learning: 2025-08-18T16:13:31.606Z
Learnt from: terabytesoftw
Repo: php-forge/support PR: 11
File: phpstan.neon:1-3
Timestamp: 2025-08-18T16:13:31.606Z
Learning: In the php-forge/support project, PHPStan is intended to be used as a PHAR installation rather than as a Composer dependency, even though the composer.json was updated to include phpstan/phpstan as a dependency.

Applied to files:

  • phpstan.neon
🧬 Code graph analysis (6)
src/Solver/Solver.php (3)
src/Config/Config.php (1)
  • get (37-55)
src/Asset/AssetManagerInterface.php (1)
  • AssetManagerInterface (11-87)
src/Solver/SolverInterface.php (1)
  • SolverInterface (10-26)
tests/Config/ConfigTest.php (1)
src/Exception/RuntimeException.php (1)
  • RuntimeException (7-7)
src/Foxy.php (1)
src/Config/Config.php (1)
  • get (37-55)
src/Config/Config.php (1)
src/Exception/RuntimeException.php (1)
  • RuntimeException (7-7)
src/Fallback/AssetFallback.php (3)
src/Fallback/ComposerFallback.php (1)
  • restore (47-66)
src/Fallback/FallbackInterface.php (1)
  • restore (12-12)
src/Config/Config.php (1)
  • get (37-55)
src/Fallback/ComposerFallback.php (3)
src/Fallback/AssetFallback.php (1)
  • restore (28-55)
src/Config/Config.php (1)
  • get (37-55)
src/Util/ConsoleUtil.php (2)
  • ConsoleUtil (17-79)
  • getPreferredInstallOptions (48-78)
🪛 PHPMD (2.15.0)
tests/Fixtures/Asset/StubAssetManager.php

21-21: Avoid variables with short names like $io. Configured minimum length is 3. (undefined)

(ShortVariable)


33-33: Avoid variables with short names like $fs. Configured minimum length is 3. (undefined)

(ShortVariable)

tests/FoxyTest.php

113-113: Avoid excessively long variable names like $assetManagersProperty. Keep variable name length under 20. (undefined)

(LongVariable)


114-114: Avoid excessively long variable names like $originalAssetManagers. Keep variable name length under 20. (undefined)

(LongVariable)

src/Fallback/ComposerFallback.php

138-138: Avoid using static access to class '\Foxy\Util\ConsoleUtil' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)


171-177: The method restorePreviousLockFile uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)

(ElseExpression)


179-179: Avoid using static access to class '\Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)

tests/Solver/SolverTest.php

138-138: Avoid variables with short names like $rm. Configured minimum length is 3. (undefined)

(ShortVariable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: linter / Super Linter
  • GitHub Check: phpunit / PHP 8.3-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.2-windows-2022
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.5-windows-2022
  • GitHub Check: phpunit / PHP 8.3-windows-2022
  • GitHub Check: phpunit / PHP 8.4-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.4-windows-2022
  • GitHub Check: phpunit / PHP 8.5-ubuntu-latest
  • GitHub Check: linter / Super Linter
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
🔇 Additional comments (33)
src/Json/JsonFormatter.php (5)

27-27: LGTM!

Good cleanup — \w already includes [a-zA-Z0-9_], so removing the redundant \d_ is correct. The unescaped ] is also valid outside a character class.


29-29: LGTM!

Simplified regex syntax — ( +) is equivalent to ([ ]+) for matching one or more spaces.


67-72: LGTM!

Safe simplification — preg_match_all always populates $matches[1] as an array (empty when no matches), so the direct return is correct.


79-89: LGTM!

More precise condition — checking isset($matches[1]) directly validates the capture group we use on line 85, which is cleaner than checking if the entire matches array is non-empty.


146-146: LGTM!

Consistent regex cleanup — the unescaped ] is valid outside a character class, matching the pattern style used in the constants above.

tests/Fixtures/Util/AbstractProcessExecutorMock.php (1)

19-23: Docblock now reflects nullable output parameter.

Good alignment with the method signature and expected values.

README.md (1)

123-127: Badge update looks good.

Quality badge now matches PHPStan level 5.

CHANGELOG.md (1)

3-19: Changelog entry is clear and consistent.

Thanks for recording the PHPStan level bump.

src/Asset/AssetManagerFinder.php (1)

21-25: Constructor delegation to addManager is fine.

Keeps the type check in one place.

src/Util/ConsoleUtil.php (1)

69-74: LGTM — explicit option handling is clearer.

tests/Fixtures/Asset/StubAssetManager.php (1)

18-33: LGTM — readonly promotion is clean for the fixture.

src/Asset/AbstractAssetManager.php (1)

63-66: LGTM — clearer guards and return value; command formatting is cleaner.

Also applies to: 126-144, 175-176, 195-203, 245-251

src/Converter/SemverUtil.php (1)

44-45: LGTM — cleanup is straightforward and consistent.

Also applies to: 73-87, 129-130

src/Fallback/ComposerFallback.php (1)

41-177: LGTM — option parsing refactor is clearer and more explicit.

src/Util/AssetUtil.php (1)

95-97: No guard needed—$installPath is already protected.

The concatenation at line 96 is already within the if (null !== $installPath) guard at line 86, so $installPath cannot be null when this code executes. The proposed fix is unnecessary.

Likely an incorrect or invalid review comment.

src/Foxy.php (1)

126-130: LGTM! Stricter enabled check is appropriate for PHPStan level 5.

The explicit type comparisons handle the various ways enabled can be configured (boolean, integer, or string from environment variables). This pattern is consistent with the same check in src/Solver/Solver.php and src/Fallback/AssetFallback.php.

Consider extracting this repeated pattern into a helper method if it appears in more places, but for now the duplication is acceptable.

src/Solver/Solver.php (3)

52-56: LGTM! Inverted enabled check correctly short-circuits when disabled.

The negated condition (!== true && !== 1 && !== '1') properly returns early when the feature is disabled, maintaining consistency with the same validation pattern used elsewhere in the codebase.


71-75: LGTM! Strict null check aligns with the typed property.

Using !== null is the correct approach given the FallbackInterface|null property type, and satisfies PHPStan's stricter type analysis.


98-101: LGTM! Robust filename validation.

The combined is_string($filename) && $filename !== '' check properly validates that the filename is both the expected type and non-empty before proceeding with file operations.

tests/Util/ComposerUtilTest.php (1)

31-43: LGTM! Clean use of expectNotToPerformAssertions().

Using expectNotToPerformAssertions() for the valid case is the idiomatic PHPUnit approach when the test's purpose is to verify that code executes without throwing an exception.

tests/Config/ConfigTest.php (3)

142-151: LGTM! Cleaner message comparison with precomputed strings.

Extracting the expected messages into variables improves readability and avoids repeated sprintf calls within the callback.


161-163: Edge case: envKey becomes empty string when '=' is not found.

If $env doesn't contain '=', then $envKeyPos is false and $envKey becomes ''. Calling putenv('') is a no-op, but this seems unintentional for the cleanup logic.

However, given the test data always includes '=' in env strings (e.g., 'FOXY__ENV_BOOLEAN=false'), this edge case won't occur in practice. The current implementation is acceptable.


211-213: LGTM! More specific exception type.

Using RuntimeException (from Foxy\Exception) is more appropriate than the generic Exception and aligns with the exception types used elsewhere in the codebase.

src/Fallback/AssetFallback.php (3)

25-25: LGTM! Correct use of null coalescing operator.

Changing from ?: to ?? is the right fix. The Elvis operator (?:) treats any falsy value (including a hypothetical Filesystem subclass evaluating to falsy) as triggering the default, whereas ?? only triggers on null, which matches the Filesystem|null parameter type.


30-34: LGTM! Consistent fallback-asset check pattern.

The strict comparison pattern matches ComposerFallback::restore() (shown in relevant snippets at lines 46-65) and maintains consistency across fallback implementations.


48-54: LGTM! Guard against writing empty content.

The additional $this->originalContent !== '' check prevents unnecessarily recreating an empty file when the original content was empty, which is a sensible defensive measure.

tests/FoxyTest.php (6)

42-50: LGTM! Clean test structure with expectNotToPerformAssertions().

Using expectNotToPerformAssertions() correctly expresses the test intent: verifying that activate() and init() execute without throwing exceptions.


86-99: LGTM! Test properly validates the install-on-event flow.

The test correctly sets up mock expectations and verifies the initOnInstall behavior when the package name matches.


111-131: Acceptable long variable names for clarity.

The static analysis hints flag $assetManagersProperty and $originalAssetManagers as exceeding 20 characters. However, these descriptive names improve readability in reflection-heavy code. The trade-off favors clarity over brevity here.


152-159: LGTM! Deactivate test correctly uses no-assertion expectation.

Since deactivate() is a no-op method, expectNotToPerformAssertions() is the appropriate way to validate it runs without error.


184-191: LGTM! Uninstall test follows the same pattern.

Consistent with the other no-op method tests.


193-224: LGTM! Localized mock improves test isolation.

Changing $this->composerConfig to a local $composerConfig variable is appropriate since it's only used within setUp() to configure the composer mock. This simplifies the test class by removing an unnecessary class property.

tests/Solver/SolverTest.php (1)

138-144: Clean simplification of RepositoryManager setup.

The removal of the conditional class_exists(HttpDownloader::class) check in favor of always using the 3-argument constructor is a good improvement that aligns with the current Composer 2.x API.

The static analysis tool (PHPMD) flagged $rm as a short variable name. While $rm is idiomatic in the Composer ecosystem, you could rename it to $repoManager for consistency with the project's naming conventions if desired.

[approve_code_changes, suggest_optional_refactor]

Optional: Rename to satisfy PHPMD
-        $rm = new RepositoryManager(
+        $repoManager = new RepositoryManager(
             $this->io,
             $this->composerConfig,
             new HttpDownloader($this->io, $this->composerConfig),
         );

-        $rm->setLocalRepository($this->localRepo);
+        $repoManager->setLocalRepository($this->localRepo);

-        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($rm);
+        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repoManager);

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tests/Fallback/ComposerFallbackTest.php`:
- Around line 68-139: Extract the duplicated setup in
testRestoreWithIgnorePlatformReqs and testRestoreWithIgnorePlatformReq into a
private helper like buildAndRunRestore(string $optionName, mixed $optionValue)
that creates composer.json/ composer.lock (using LockerUtil::getLocker), sets up
$this->input->getOption callback, config mocks (getEventDispatcher,
getRepositoryManager, getInstallationManager), stubs $this->composer->getLocker
and getConfig (with config->get returning vendor-dir), expects $this->io->write
and $this->installer->run, then calls $this->composerFallback->save() and
$this->composerFallback->restore(); update both tests to call this helper
passing only the option-specific args so they remain focused on differences.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fa4dd2 and 25a7ab5.

📒 Files selected for processing (1)
  • tests/Fallback/ComposerFallbackTest.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: User terabytesoftw prefers not to use aliases when importing classes in PHP. They are comfortable with either fully-qualified class names or direct imports without aliases.
Learnt from: terabytesoftw
Repo: php-forge/support PR: 12
File: src/TestSupport.php:0-0
Timestamp: 2025-08-18T20:13:33.518Z
Learning: User terabytesoftw prefers clean trait-based designs over maintaining backward compatibility wrappers when refactoring utility classes in the php-forge/support project.
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 65
File: .github/workflows/composer-require-checker.yml:80-83
Timestamp: 2025-09-28T15:12:48.345Z
Learning: The user terabytesoftw prefers using floating tags like v1 for third-party actions in GitHub workflows instead of pinning to specific commit SHAs, even when it's a security best practice to pin to immutable commits.
📚 Learning: 2026-01-22T11:42:32.878Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 111
File: tests/Fallback/AssetFallbackTest.php:98-98
Timestamp: 2026-01-22T11:42:32.878Z
Learning: When using xepozz/internal-mocker in PHP tests, the library's namespaced wrapper records and matches function calls with all default parameters filled in. To ensure proper matching, always specify every parameter in MockerState::addCondition(), including defaults. For example, a call to file_get_contents($path) is observed as file_get_contents($path, false, null, 0, null). Use the same complete argument list (including default values) when adding conditions for mocks in tests like tests/Fallback/AssetFallbackTest.php.

Applied to files:

  • tests/Fallback/ComposerFallbackTest.php
📚 Learning: 2026-01-23T11:22:00.118Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: In PHP tests (e.g., tests/Fallback/AssetFallbackTest.php) avoid using import aliases. Prefer either importing the full namespace without an alias or using fully-qualified class names directly. For example, avoid statements like 'use Some\Long\Namespace as Alias;' and either 'use Some\\Long\\Namespace;' or reference 'Some\\Long\\Namespace' in code. This guideline applies to PHP files under tests and improves readability and refactor safety.

Applied to files:

  • tests/Fallback/ComposerFallbackTest.php
🧬 Code graph analysis (1)
tests/Fallback/ComposerFallbackTest.php (2)
src/Util/LockerUtil.php (2)
  • LockerUtil (12-26)
  • getLocker (17-25)
src/Fallback/FallbackInterface.php (2)
  • save (17-17)
  • restore (12-12)
🪛 GitHub Actions: ecs
tests/Fallback/ComposerFallbackTest.php

[error] 1-1: PHPUnit test failures detected: mismatch in method names and data providers (getIgnorePlatformReqsData vs getIgnorePlatformReqData). Test expectations may be out of sync with code.

🪛 PHPMD (2.15.0)
tests/Fallback/ComposerFallbackTest.php

106-106: Avoid variables with short names like $ed. Configured minimum length is 3. (undefined)

(ShortVariable)


110-110: Avoid variables with short names like $rm. Configured minimum length is 3. (undefined)

(ShortVariable)


114-114: Avoid variables with short names like $im. Configured minimum length is 3. (undefined)

(ShortVariable)


119-119: Avoid using static access to class '\Foxy\Util\LockerUtil' in method 'testRestoreWithIgnorePlatformReqs'. (undefined)

(StaticAccess)


180-180: Avoid variables with short names like $ed. Configured minimum length is 3. (undefined)

(ShortVariable)


184-184: Avoid variables with short names like $rm. Configured minimum length is 3. (undefined)

(ShortVariable)


188-188: Avoid variables with short names like $im. Configured minimum length is 3. (undefined)

(ShortVariable)


193-193: Avoid using static access to class '\Foxy\Util\LockerUtil' in method 'testRestoreWithIgnorePlatformReq'. (undefined)

(StaticAccess)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: phpunit / PHP 8.1-windows-2022
  • GitHub Check: phpunit / PHP 8.5-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.4-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.2-windows-2022
  • GitHub Check: phpunit / PHP 8.3-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.5-windows-2022
  • GitHub Check: phpunit / PHP 8.4-windows-2022
  • GitHub Check: phpunit / PHP 8.2-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.3-windows-2022
  • GitHub Check: phpunit / PHP 8.1-ubuntu-latest
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: linter / Super Linter
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.3-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.4-windows-2022
  • GitHub Check: linter / Super Linter
🔇 Additional comments (2)
tests/Fallback/ComposerFallbackTest.php (2)

141-213: Good coverage of the ignore-platform-req fallback path.

Explicitly nulling ignore-platform-reqs before setting ignore-platform-req makes the precedence behavior clear and testable.


42-56: The data provider names and their @dataProvider annotations are correctly matched in the codebase. No mismatch exists.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

…oreWithIgnorePlatformReqs` by extracting common setup logic.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/Fallback/ComposerFallback.php`:
- Around line 124-126: The current check in ComposerFallback (using $lockData
and $hasPackage) only treats 'packages' as a valid lock presence; change the
logic to also consider 'packages-dev' so projects with only dev dependencies are
treated as locked. Update the $hasPackage computation in ComposerFallback.php to
return true when either isset($lockData['packages']) and non-empty OR
isset($lockData['packages-dev']) and non-empty (use the same is_array/empty
checks you already use) so the method that returns $isLocked && $hasPackage will
not erroneously remove vendor/ for dev-only lock files.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25a7ab5 and db5ac2d.

📒 Files selected for processing (2)
  • src/Fallback/ComposerFallback.php
  • tests/Fallback/ComposerFallbackTest.php
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: User terabytesoftw prefers not to use aliases when importing classes in PHP. They are comfortable with either fully-qualified class names or direct imports without aliases.
Learnt from: terabytesoftw
Repo: php-forge/support PR: 12
File: src/TestSupport.php:0-0
Timestamp: 2025-08-18T20:13:33.518Z
Learning: User terabytesoftw prefers clean trait-based designs over maintaining backward compatibility wrappers when refactoring utility classes in the php-forge/support project.
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 65
File: .github/workflows/composer-require-checker.yml:80-83
Timestamp: 2025-09-28T15:12:48.345Z
Learning: The user terabytesoftw prefers using floating tags like v1 for third-party actions in GitHub workflows instead of pinning to specific commit SHAs, even when it's a security best practice to pin to immutable commits.
📚 Learning: 2025-08-18T20:13:33.518Z
Learnt from: terabytesoftw
Repo: php-forge/support PR: 12
File: src/TestSupport.php:0-0
Timestamp: 2025-08-18T20:13:33.518Z
Learning: User terabytesoftw prefers clean trait-based designs over maintaining backward compatibility wrappers when refactoring utility classes in the php-forge/support project.

Applied to files:

  • tests/Fallback/ComposerFallbackTest.php
📚 Learning: 2026-01-22T11:42:32.878Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 111
File: tests/Fallback/AssetFallbackTest.php:98-98
Timestamp: 2026-01-22T11:42:32.878Z
Learning: When using xepozz/internal-mocker in PHP tests, the library's namespaced wrapper records and matches function calls with all default parameters filled in. To ensure proper matching, always specify every parameter in MockerState::addCondition(), including defaults. For example, a call to file_get_contents($path) is observed as file_get_contents($path, false, null, 0, null). Use the same complete argument list (including default values) when adding conditions for mocks in tests like tests/Fallback/AssetFallbackTest.php.

Applied to files:

  • tests/Fallback/ComposerFallbackTest.php
📚 Learning: 2026-01-23T11:22:00.118Z
Learnt from: terabytesoftw
Repo: php-forge/foxy PR: 115
File: tests/Fallback/AssetFallbackTest.php:158-189
Timestamp: 2026-01-23T11:22:00.118Z
Learning: In PHP tests (e.g., tests/Fallback/AssetFallbackTest.php) avoid using import aliases. Prefer either importing the full namespace without an alias or using fully-qualified class names directly. For example, avoid statements like 'use Some\Long\Namespace as Alias;' and either 'use Some\\Long\\Namespace;' or reference 'Some\\Long\\Namespace' in code. This guideline applies to PHP files under tests and improves readability and refactor safety.

Applied to files:

  • tests/Fallback/ComposerFallbackTest.php
📚 Learning: 2025-09-29T14:58:04.095Z
Learnt from: terabytesoftw
Repo: php-forge/actions PR: 67
File: .github/workflows/phpstan.yml:13-16
Timestamp: 2025-09-29T14:58:04.095Z
Learning: In the php-forge/actions repository, the maintainer prefers using "composer update" as the default command in CI workflows to ensure the latest dependencies are always installed, rather than using "composer install" for reproducibility.

Applied to files:

  • src/Fallback/ComposerFallback.php
🧬 Code graph analysis (2)
tests/Fallback/ComposerFallbackTest.php (7)
src/Fallback/ComposerFallback.php (2)
  • save (68-82)
  • restore (47-66)
src/Fallback/AssetFallback.php (2)
  • save (57-70)
  • restore (28-55)
src/Fallback/FallbackInterface.php (2)
  • save (17-17)
  • restore (12-12)
src/Util/LockerUtil.php (2)
  • LockerUtil (12-26)
  • getLocker (17-25)
src/Config/Config.php (1)
  • Config (21-207)
tests/Fallback/AssetFallbackTest.php (2)
  • testRestore (44-66)
  • AssetFallbackTest (21-190)
tests/FoxyTest.php (1)
  • FoxyTest (30-238)
src/Fallback/ComposerFallback.php (3)
src/Fallback/AssetFallback.php (1)
  • restore (28-55)
src/Util/ConsoleUtil.php (2)
  • ConsoleUtil (17-79)
  • getPreferredInstallOptions (48-78)
src/Asset/AbstractAssetManager.php (1)
  • run (116-176)
🪛 PHPMD (2.15.0)
tests/Fallback/ComposerFallbackTest.php

315-315: Avoid using static access to class '\Foxy\Util\LockerUtil' in method 'setupRestoreEnvironment'. (undefined)

(StaticAccess)

src/Fallback/ComposerFallback.php

138-138: Avoid using static access to class '\Foxy\Util\ConsoleUtil' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)


171-177: The method restorePreviousLockFile uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)

(ElseExpression)


179-179: Avoid using static access to class '\Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory' in method 'restorePreviousLockFile'. (undefined)

(StaticAccess)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: phpunit / PHP 8.5-windows-2022
  • GitHub Check: phpunit / PHP 8.2-windows-2022
  • GitHub Check: phpunit / PHP 8.1-windows-2022
  • GitHub Check: phpunit / PHP 8.3-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.4-windows-2022
  • GitHub Check: phpunit / PHP 8.3-windows-2022
  • GitHub Check: linter / Super Linter
  • GitHub Check: phpunit / PHP 8.1-ubuntu-latest
  • GitHub Check: phpunit / PHP 8.5-ubuntu-latest
  • GitHub Check: easy-coding-standard / PHP 8.5-ubuntu-latest
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: mutation / PHP 8.5-ubuntu-latest
  • GitHub Check: linter / Super Linter
  • GitHub Check: easy-coding-standard / PHP 8.5-ubuntu-latest
🔇 Additional comments (6)
src/Fallback/ComposerFallback.php (3)

41-41: Null-coalescing init looks correct.

The switch to ?? avoids treating falsy-but-valid Filesystem instances as null.


49-52: Strict truthy check is consistent.

This aligns fallback-composer handling with explicit boolean-like values.


138-183: Option normalization and platform-req handling look solid.

The unified boolean checks and the ignore-platform-req(s) resolution are clear and testable.

tests/Fallback/ComposerFallbackTest.php (3)

42-56: Data providers are clear and focused.

Nice separation of ignore-platform-req vs ignore-platform-reqs cases.


152-197: Tests are concise and cover both option paths.

Good use of providers to validate both option names and list/boolean values.


276-330: Shared setup helper improves readability.

Centralizing the restore environment setup makes the tests easier to maintain.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@terabytesoftw
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@terabytesoftw terabytesoftw merged commit 9151b2c into main Jan 24, 2026
48 checks passed
@terabytesoftw terabytesoftw deleted the fix_mini_11 branch January 24, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Estado: error Algo no funciona

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants