{"id":28340462,"url":"https://github.com/kimyu-ng/junit_timing_splitter","last_synced_at":"2026-05-21T04:05:46.879Z","repository":{"id":279735494,"uuid":"892439192","full_name":"kimyu-ng/junit_timing_splitter","owner":"kimyu-ng","description":"Efficiently split Junit test timings into buckets and output results to JSON with JunitTimingSplitter. 🚀","archived":false,"fork":false,"pushed_at":"2025-02-27T05:17:30.000Z","size":12,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-23T18:52:14.486Z","etag":null,"topics":["ci","jest","junit","parallel","rspec"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kimyu-ng.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-11-22T05:37:23.000Z","updated_at":"2025-02-27T05:17:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"ed1403ba-85fb-4882-9fc2-d479902ed2cc","html_url":"https://github.com/kimyu-ng/junit_timing_splitter","commit_stats":null,"previous_names":["kimyu92/junit_timing_splitter","kimyu-ng/junit_timing_splitter"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kimyu-ng/junit_timing_splitter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kimyu-ng%2Fjunit_timing_splitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kimyu-ng%2Fjunit_timing_splitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kimyu-ng%2Fjunit_timing_splitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kimyu-ng%2Fjunit_timing_splitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kimyu-ng","download_url":"https://codeload.github.com/kimyu-ng/junit_timing_splitter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kimyu-ng%2Fjunit_timing_splitter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32660279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","jest","junit","parallel","rspec"],"created_at":"2025-05-27T03:16:30.607Z","updated_at":"2026-05-05T17:32:43.639Z","avatar_url":"https://github.com/kimyu-ng.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JunitTimingSplitter\n\n[![GemVersion](https://img.shields.io/gem/v/junit_timing_splitter.svg?style=flat)](https://rubygems.org/gems/junit_timing_splitter)\n![CI](https://github.com/kimyu92/junit_timing_splitter/workflows/CI/badge.svg)\n\n`JunitTimingSplitter` is a tool written in Ruby designed to parse JUnit XML result files and distribute tests into evenly balanced buckets based on their total execution time. This tool is especially beneficial for optimizing parallel test execution in CI pipelines, drawing inspiration from CircleCI's `--split-by=timings` feature.\n\n---\n\n## Features\n\n- Parse JUnit XML files (`*.xml`) to extract test file execution times.\n- Aggregate timings across multiple XML files.\n- Split tests into evenly distributed buckets based on execution time.\n- Analyze bucket distribution for load balancing.\n- Compatible with glob patterns to process multiple XML files.\n\n---\n\n## Installation\n\nAdd this gem to your `Gemfile`:\n\n```sh\ngem install junit_timing_splitter\n```\n\nor\n\n```ruby\n# Gemfile\ngem 'junit_timing_splitter', '~\u003e 1.0.0'\n```\n\nThen,\n\n```sh\nbundle install\n```\n\n## Usage\n1. Generate Junit XML Results\nAnalyze how test files will be distributed across N buckets:\n\n```sh\nbundle exec junit_timing_splitter split --files=\"test/fixtures/results_0[0|1].xml\" --buckets=2 --schema=\"output/buckets.json\"\n```\n\n```\nDetected 2 files\nDetected file: test/fixtures/results_00.xml\nDetected file: test/fixtures/results_01.xml\nBuckets written to buckets.json\n```\n\n2. Get Files for a Specific Bucket\n```sh\nbundle exec junit_timing_splitter show --schema=\"output/buckets.json\" --bucket=0\nbundle exec junit_timing_splitter show --schema=\"output/buckets.json\" --bucket=1\n```\n\n```\n# bucket=0\n./spec/models/simple_part1_spec.rb\n\n# bucket=1\n./spec/models/simple_part2_spec.rb\n```\n\n3. Find out the missing test cases from the existing schema\n\n```sh\nbundle exec junit_timing_splitter scan --schema=\"output/buckets.json\" --files=\"./spec/**/*.rb\"\n```\n\n```\n# if no missing file\nNo missing test files detected.\n\n# if missing exist\nMissing test files:\n\u003cabsolute path\u003e/spec/models/missing_test.rb\n```\n\n4. Merge the missing test cases from the existing schema\n```sh\nbundle exec junit_timing_splitter merge --schema=\"output/buckets.json\" --files=\"./spec/**/*_spec.rb\"\n```\n\n## Development\n\n```sh\n# rebuild\nrm junit_timing_splitter-1.1.0.gem \u0026\u0026 gem build JunitTimingSplitter.gemspec \u0026\u0026 gem install junit_timing_splitter-1.1.0.gem\n```\n\n```sh\n# testing\nruby test/test_junit_timing_splitter.rb --verbose\n\nRun options: --verbose --seed 58633\n\n# Running:\n\nTestJunitTimingSplitter#test_merge_missing_files = 0.00 s = .\nTestJunitTimingSplitter#test_simple_case = Detected 2 files\nDetected file: test/fixtures/results_00.xml\nDetected file: test/fixtures/results_01.xml\n0.00 s = .\nTestJunitTimingSplitter#test_scan_without_missing_files = 0.00 s = .\nTestJunitTimingSplitter#test_all_parsed_files = 0.00 s = .\nTestJunitTimingSplitter#test_imbalanced_case = Detected 2 files\nDetected file: test/fixtures/results_02.xml\nDetected file: test/fixtures/results_03.xml\n0.00 s = .\nTestJunitTimingSplitter#test_scan_missing_files = 0.00 s = .\nTestJunitTimingSplitter#test_files_for_bucket = 0.00 s = .\n\nFinished in 0.008489s, 824.5965 runs/s, 3416.1856 assertions/s.\n\n7 runs, 29 assertions, 0 failures, 0 errors, 0 skips\n```\n\n## License\nCopyright (c) 2024 Kim Yu Ng, released under the [MIT license](LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkimyu-ng%2Fjunit_timing_splitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkimyu-ng%2Fjunit_timing_splitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkimyu-ng%2Fjunit_timing_splitter/lists"}