[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[6.x] Pest time-balanced sharding - #15140

Merged
jasonvarga merged 6 commits into
6.xfrom
pest
Aug 10, 2026
Merged

[6.x] Pest time-balanced sharding#15140
jasonvarga merged 6 commits into
6.xfrom
pest

Conversation

@jasonvarga

@jasonvargajasonvarga commented Aug 8, 2026

Copy link
Copy Markdown
Member

Adds Pest as the CI test runner so we can shard the PHP suite across parallel jobs, using its time-balanced sharding to keep them even.

The suite is ~10,000 tests and the slowest job (Windows) had grown to nearly 13 minutes, which sets the floor for how long a PR sits waiting.

Tests themselves (after the overhead of setting up the jobs) goes from ~11m to ~3m.

A pull request workflow run goes from ~14m to ~4m.

Pest 4 is used because we still support Laravel 12. Luckily, the time-balanced sharding feature actually landed on Pest 4 - not Pest 5 like their marketing implies.

Pest is only the runner

Intentionally not rewriting any tests. Pest is just being used as the runner and for its sharding feature.

You can use vendor/bin/phpunit or vendor/bin/pest locally.

Ubuntu is split 4 ways, Windows 6

Windows runs the same tests in roughly twice the time, so splitting both evenly leaves Windows as the critical path with Ubuntu jobs sitting idle. Six shards brings Windows' test execution down to roughly the same as Ubuntu's, for two extra jobs.

Test fixes

Three pre-existing bugs surfaced while getting this green. They're follow-ups to #15143 — same class of problem, just not caught at the time — and are included here because sharding can't work without them:

  • Invalid data provider key.ProvidesExternalUrls::externalUrlProvider() keyed its data sets by URL, and '' is one of the internal URLs — an empty-string key, which PHPUnit rejects. This broke --list-tests outright, which is how shard assignment is discovered.
  • CP\ColorTest leaked state. It wrote theme colour preferences to resources/preferences.yaml and never cleaned up, so Preferences\EndpointsTest inherited a stray theme.colors block. Now cleaned up in tearDown(), matching DefaultPreferencesTest and PrecedenceTest.
  • View tag state leaked between tests. The increment and rotate tags keep counters in static properties that are only cleared when the ClearState listener fires on a response. A test that renders Antlers without a full request leaves them populated. StateTest picked up a counter of 31 from IncrementTest once sharding put them in the same job. TestCase::setUp() now resets view state.

Notes

jasonvargaand others added 3 commits August 10, 2026 08:36
The provider keyed data sets by URL, and an empty string is one of the
internal URLs, producing an empty-string key. PHPUnit rejects this when
listing tests, which broke any tooling relying on --list-tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setThemeColors() writes resource_path('preferences.yaml'), and while
setUp() deleted it, nothing cleaned up after the last test. The final
test's colors survived into unrelated tests that assert on preferences,
making the suite order dependent. Delete the file in tearDown() too,
matching DefaultPreferencesTest and PrecedenceTest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pest runs the existing PHPUnit test suite as-is, with no conversion to
Pest syntax. It's added for its sharding support, which PHPUnit has no
equivalent for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The test run is around 90% of each job's wall clock, so sharding is
close to linear. Four shards takes the workflow from ~12.8 to ~4
minutes. Windows needs its own include entry per shard, since an
include that overrides a matrix key creates a standalone combination
rather than merging, and so wouldn't inherit the shard dimension.
shards.json holds recorded timings so shards are balanced by duration
rather than test count. Regenerate it with --update-shards.
Adds a php-tests-result job that aggregates every shard, so branch
protection can require one check instead of one per matrix cell.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Windows tests take roughly twice as long as ubuntu's, so splitting both
of them four ways leaves Windows as the critical path. Six brings its
slowest job down to about the same as the slowest ubuntu one, which is
as far as it's worth going.
The increment and rotate tags keep their counters in static properties
that are only cleared when the ClearState listener fires on a response.
A test that renders Antlers without going through a full request leaves
them populated, and the next test in the same process inherits them.
StateTest picked up a counter of 31 from IncrementTest once sharding put
the two in the same job.
@jasonvarga
jasonvarga marked this pull request as ready for review August 10, 2026 14:51
@jasonvargajasonvarga changed the title [6.x] Pest[6.x] Pest time-balanced shardingAug 10, 2026
@jasonvarga
jasonvarga merged commit 05775d9 into 6.xAug 10, 2026
69 checks passed
@jasonvarga
jasonvarga deleted the pest branch August 10, 2026 15:14
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@jasonvarga@duncanmcclean