Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Robo Composer Laravel Package

sweetchuck/robo-composer

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev sweetchuck/robo-composer
    
  2. Load the Task Trait: In your RoboFile.php, add the trait to your class:

    use Sweetchuck\Robo\Composer\ComposerTaskLoader;
    
  3. First Use Case: Run the composer:package-paths command to list all installed Composer packages and their paths:

    vendor/bin/robo composer:package-paths
    

Key Entry Points

  • taskComposerLockDiffer(): Compare two composer.lock files (useful for CI/CD pipelines or pre-deploy checks).
  • taskComposerPackagePaths(): Retrieve paths of installed packages (useful for debugging or custom scripts).

Implementation Patterns

Common Workflows

1. Comparing Lock Files in CI/CD

Use taskComposerLockDiffer() to detect changes between composer.lock in branches or environments:

/**
 * @command composer:ci-lock-check
 * @validateArgumentFileName oldLock,newLock
 */
public function ciLockCheck(string $oldLock, string $newLock) {
    return $this
        ->collectionBuilder()
        ->addTask($this->taskComposerLockDiffer()
            ->setLockA(json_decode(file_get_contents($oldLock), true))
            ->setLockB(json_decode(file_get_contents($newLock), true))
        )
        ->addCode(function (\Robo\State\Data $data): int {
            $diff = $data['composer.lockDiff'];
            if (!empty($diff)) {
                $this->output()->error('Lock file changes detected!');
                $this->output()->writeln(Yaml::dump($diff));
                return 1;
            }
            $this->output()->success('Lock files match.');
            return 0;
        });
}

Usage:

vendor/bin/robo composer:ci-lock-check <(git show 'origin/main:composer.lock') ./composer.lock

2. Dynamic Package Path Resolution

Use taskComposerPackagePaths() to fetch paths for custom logic (e.g., symlinking or backup scripts):

/**
 * @command composer:backup-package
 * @arg packageName
 */
public function backupPackage(string $packageName) {
    return $this
        ->collectionBuilder()
        ->addTask($this->taskComposerPackagePaths())
        ->addCode(function (\Robo\State\Data $data) use ($packageName): int {
            if (!isset($data['composer.packagePaths'][$packageName])) {
                $this->output()->error("Package '$packageName' not found.");
                return 1;
            }
            $path = $data['composer.packagePaths'][$packageName];
            $this->taskExecStack()->run("cp -r $path /backups/{$packageName}-$(date +%s)");
            return 0;
        });
}

3. Integration with Robo Collections

Chain tasks for multi-step operations (e.g., validate + backup):

public function validateAndBackup() {
    return $this->collectionBuilder()
        ->addTask($this->taskComposerLockDiffer()
            ->setLockA($this->getOldLock())
            ->setLockB($this->getNewLock())
        )
        ->addTask($this->backupPackage('symfony/console'))
        ->run();
}

Integration Tips

  1. Leverage Robo Hooks: Use @hook annotations to validate inputs before task execution (e.g., file existence checks).

    /**
     * @hook validateFileExists
     */
    public function validateFileExists(\Consolidation\AnnotatedCommand\CommandData $commandData) {
        $files = $commandData->annotationData()->getList(__FUNCTION__);
        foreach ($files as $file) {
            assert(file_exists($file), "File '$file' not found.");
        }
    }
    
  2. Customize Output: Format composer.lockDiff data for readability (e.g., using Symfony\Component\Yaml\Yaml or League\CLImate).

  3. Environment Awareness: Use getcwd() or config files to resolve paths dynamically:

    $lockPath = $this->getConfig('composer.lock_path') ?? 'composer.lock';
    

Gotchas and Tips

Pitfalls

  1. JSON Parsing Errors:

    • composer.lock files must be valid JSON. Use json_decode() with JSON_THROW_ON_ERROR for strict validation:
      $lock = json_decode(file_get_contents($lockFile), true, 512, JSON_THROW_ON_ERROR);
      
  2. Path Resolution Issues:

    • Avoid hardcoding paths. Use realpath() or getcwd() to handle relative paths:
      $absolutePath = realpath($relativePath) ?: throw new \RuntimeException("Path not found.");
      
  3. Task State Dependencies:

    • Ensure tasks are chained correctly in collections. Use ->run() explicitly for clarity:
      return $this->collectionBuilder()
          ->addTask($this->taskComposerPackagePaths())
          ->addCode(fn($data) => $this->processData($data))
          ->run(); // Explicit execution
      

Debugging Tips

  1. Inspect Task Data: Dump the $data object in addCode to verify outputs:

    ->addCode(function (\Robo\State\Data $data): int {
        $this->output()->writeln(print_r($data->all(), true));
        return 0;
    })
    
  2. Validate Lock File Structure: Use composer validate composer.lock as a sanity check before scripting.

  3. Handle Large Lock Files: For CI/CD, stream git show output to avoid memory issues:

    vendor/bin/robo composer:lock-diff <(git show 'HEAD^:composer.lock' | jq '.') ./composer.lock
    

Extension Points

  1. Custom Diff Logic: Extend the ComposerLockDiffer class to add custom comparison rules (e.g., ignore dev dependencies):

    class CustomLockDiffer extends \Sweetchuck\Robo\Composer\ComposerLockDiffer {
        protected function shouldComparePackage(array $package) {
            return !isset($package['require-dev']);
        }
    }
    

    Then use it via dependency injection or a wrapper task.

  2. Add New Tasks: The package is minimal; fork and extend it to add tasks like taskComposerUpdate or taskComposerAudit.

  3. Configuration: Load composer.json dynamically for runtime flexibility:

    $composerJson = json_decode(file_get_contents('composer.json'), true);
    $this->taskComposerLockDiffer()->setConfig($composerJson);
    

Config Quirks

  • No Built-in Config: The package relies on direct method calls (e.g., setLockA()). For reusable setups, wrap tasks in a service class.
  • Type Safety: Ensure setLockA()/setLockB() receive properly decoded JSON arrays, not raw strings.

Performance Notes

  • Avoid Repeated Parsing: Cache parsed composer.lock files in memory if used frequently:
    private $lockCache = [];
    protected function getParsedLock(string $path) {
        return $this->lockCache[$path] ??= json_decode(file_get_contents($path), true);
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor