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

Junit Merger Laravel Package

sweetchuck/junit-merger

Merge multiple JUnit XML report files into a single combined report. Useful for aggregating test results from parallel jobs, multiple test suites, or split CI runs into one JUnit-compatible XML output.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Use Case Alignment: The junit-merger package is a point solution for consolidating JUnit XML test reports (e.g., from parallel test runs, microservices, or CI pipelines). It fits well in Laravel/PHP ecosystems where:
    • Tests are distributed across modules/services (e.g., Laravel Horizon workers, API tests, or feature-specific test suites).
    • CI/CD pipelines require aggregated test reports (e.g., GitHub Actions, GitLab CI, or Jenkins) for unified metrics.
    • Legacy systems generate JUnit XML but lack native merging capabilities.
  • Non-Functional Fit:
    • Lightweight: No heavy dependencies (PHP 8.0+ required, ~100 LOC in the core).
    • Stateless: Processes files at runtime; no database or persistent storage needed.
    • Output Standardization: Produces a single JUnit XML file compatible with tools like SonarQube, Allure, or CI dashboards.

Integration Feasibility

  • Laravel Compatibility:
    • Native PHP: Zero Laravel-specific dependencies; integrates via Composer.
    • Artisan/Console: Can be invoked via Laravel’s Artisan CLI or embedded in custom commands.
    • Event-Driven: Can hook into Laravel’s tests-passed or tests-failed events (if test reports are generated asynchronously).
  • Data Flow:
    • Input: Accepts local filesystem paths or streams (e.g., from S3, HTTP, or Laravel Storage).
    • Output: Writes merged XML to a specified path (can use Laravel’s storage() or public() paths).
  • Testing Integration:
    • Works with Laravel’s built-in phpunit or third-party test runners (e.g., PestPHP, which also generates JUnit XML).

Technical Risk

Risk Area Assessment Mitigation Strategy
XML Schema Validity Merging malformed JUnit XML may break output or cause parsing errors. Validate input files with SimpleXMLElement or DOMDocument before merging.
Parallel Test Data Race conditions if merging real-time streams (e.g., from live test suites). Use file locks (flock()) or queue delayed merging (e.g., Laravel Queues).
Test Metadata Loss Merging may duplicate or omit test IDs/time stamps if not handled carefully. Configure the merger to preserve unique identifiers (e.g., testcase attributes).
Performance Large XML files (>100MB) may cause memory issues. Stream processing with XMLReader or chunked merging.
Dependency Stability Low-star package with no dependents; risk of abandonment. Fork or wrap in a Laravel-specific package (e.g., spatie/junit-merger-laravel).

Key Questions

  1. Why Merge?
    • Are tests distributed across services (e.g., API + Queue + UI) requiring a single report?
    • Is this for CI/CD (e.g., GitHub Actions artifacts) or developer tooling (e.g., IDE plugins)?
  2. Data Sources:
    • Where are JUnit XML files generated? (e.g., storage/logs/tests/, remote storage, or dynamic paths).
    • Are files static (post-test) or streaming (real-time)?
  3. Output Requirements:
    • Does the merged XML need to include custom properties (e.g., package, timestamp)?
    • Are there compliance needs (e.g., SonarQube’s specific schema)?
  4. Failure Handling:
    • Should partial merges be allowed (e.g., skip corrupt files)?
    • How should conflicts (e.g., duplicate test IDs) be resolved?
  5. Scaling:
    • Will this run in CI (ephemeral) or production (persistent)?
    • Are there volume limits (e.g., 100+ files to merge)?

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Artisan Commands: Wrap the merger in a custom command (e.g., php artisan test:merge) for CLI-driven workflows.
    • Service Providers: Register the merger as a singleton for programmatic use (e.g., in test listeners).
    • Events: Trigger merging post-test via Laravel’s events:dispatch (e.g., TestRunCompleted).
    • Queues: Offload merging to a queue job (e.g., MergeJUnitReportsJob) for async processing.
  • Testing Tools:
    • PestPHP: Hook into Pest’s afterTests or use its --junit flag + post-processing.
    • PHPUnit: Use phpunit --testdox-html or --log-junit + custom script.
  • CI/CD:
    • GitHub Actions: Merge reports in a post-test step and upload as an artifact.
    • GitLab CI: Use after_script to merge and publish results.

Migration Path

  1. Phase 1: Proof of Concept
    • Install the package: composer require sweetchuck/junit-merger.
    • Test merging static files (e.g., tests/unit.xml + tests/feature.xmltests/merged.xml).
    • Validate output with phpunit --colors=never merged.xml.
  2. Phase 2: Laravel Integration
    • Create an Artisan command:
      // app/Console/Commands/MergeTestReports.php
      use Sweetchuck\JunitMerger\JunitMerger;
      
      public function handle() {
          $merger = new JunitMerger();
          $merged = $merger->merge([
              storage_path('logs/tests/unit.xml'),
              storage_path('logs/tests/feature.xml'),
          ]);
          file_put_contents(storage_path('logs/tests/merged.xml'), $merged);
      }
      
    • Schedule via php artisan schedule:run or trigger manually.
  3. Phase 3: Automation
    • Add to phpunit.xml post-test hook or CI pipeline:
      <phpunit>
          <listeners>
              <listener class="App\Listeners\MergeTestReportsListener" />
          </listeners>
      </phpunit>
      
    • For CI, use a step like:
      # .github/workflows/tests.yml
      - name: Merge JUnit reports
        run: php artisan test:merge
      - uses: actions/upload-artifact@v3
        with:
          name: test-results
          path: storage/logs/tests/merged.xml
      

Compatibility

  • Laravel Versions: PHP 8.0+ required; compatible with Laravel 9+ (no framework-specific code).
  • Test Runners:
    • PHPUnit: Works with any version generating JUnit XML.
    • PestPHP: Requires --junit flag (Pest 1.2+).
  • File Formats:
    • Input: Standard JUnit XML (no custom namespaces or attributes).
    • Output: Valid JUnit XML (tested with xmllint --schema junit.xsd merged.xml).

Sequencing

  1. Pre-Merge:
    • Ensure all test suites generate JUnit XML (configure in phpunit.xml or Pest config).
    • Standardize file paths (e.g., tests/{suite}.xml).
  2. Merge:
    • Run during CI post-test or locally via Artisan.
    • For async systems, use queues to avoid blocking.
  3. Post-Merge:
    • Validate merged XML (e.g., phpunit --colors=never merged.xml).
    • Publish to artifacts/storage for consumption (e.g., SonarQube, dashboards).

Operational Impact

Maintenance

  • Dependencies:
    • Single Composer package with no transitive dependencies (low risk).
    • Monitor for updates (check sweetchuck/junit-merger-cli for enhancements).
  • Customization:
    • Extend the merger by subclassing JunitMerger (e.g., add Laravel-specific logging).
    • Override conflict resolution logic (e.g., prefer newer test timestamps).
  • Documentation:
    • Add a README section for Laravel usage (e.g., Artisan command examples).
    • Document input/output paths and failure modes.

Support

  • Debugging:
    • Log merge operations (e.g., Log::info('Merging files: ' . implode(', ', $files))).
    • Validate input files with SimpleXMLElement before merging.
  • Common Issues:
    • Corrupt XML: Skip files with try-catch or validate with libxml_use_internal_errors().
    • Duplicate Tests: Use testcase attributes (e.g., name="TestClass::method" + time) to deduplicate.
    • Performance: For large files, implement chunked merging or streaming.

Scaling

  • Volume Handling:
    • Small-Scale: Direct filesystem merging (e.g., 10–50 files).
    • Large-Scale:
      • Use Laravel Queues to batch merge (e.g., 10 files per
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime