[openstreetmap/openstreetmap-website] Bump the dependencies group with 7 updates (PR #7377)
dependabot[bot]
notifications at github.com
Wed Sep 9 23:17:43 UTC 2026
Bumps the dependencies group with 7 updates:
| Package | From | To |
| --- | --- | --- |
| [activerecord-postgis](https://github.com/seuros/activerecord-postgis) | `0.5.1` | `0.6.0` |
| [bootsnap](https://github.com/rails/bootsnap) | `1.25.0` | `1.26.0` |
| [omniauth-google-oauth2](https://github.com/zquestz/omniauth-google-oauth2) | `1.2.2` | `1.2.3` |
| [opentelemetry-exporter-otlp](https://github.com/open-telemetry/opentelemetry-ruby) | `0.34.1` | `0.35.1` |
| [image_processing](https://github.com/janko/image_processing) | `2.0.3` | `2.1.0` |
| [overcommit](https://github.com/sds/overcommit) | `0.72.0` | `0.73.0` |
| [simplecov](https://github.com/simplecov-ruby/simplecov) | `1.1.1` | `1.2.0` |
Updates `activerecord-postgis` from 0.5.1 to 0.6.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/seuros/activerecord-postgis/releases">activerecord-postgis's releases</a>.</em></p>
<blockquote>
<h2>activerecord-postgis: v0.6.0</h2>
<h2><a href="https://github.com/seuros/activerecord-postgis/compare/activerecord-postgis/v0.5.1...activerecord-postgis/v0.6.0">0.6.0</a> (2026-08-31)</h2>
<h3>Features</h3>
<ul>
<li>use new PG type registration api (<a href="https://redirect.github.com/seuros/activerecord-postgis/issues/17">#17</a>) (<a href="https://github.com/seuros/activerecord-postgis/commit/2b8f67340124a5f218256bdc447ac6ae5b3d9752">2b8f673</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>support Rails 8.2 schema_ignored_tables (<a href="https://github.com/seuros/activerecord-postgis/commit/9e08e135bc9b9d745edd351461cbf1a24c328764">9e08e13</a>)</li>
<li>test ruby 4.0 (<a href="https://github.com/seuros/activerecord-postgis/commit/6de79842d9c7271f88e81d39cf73fd00541efea9">6de7984</a>)</li>
<li>use SpatialModel.arel_table in Arel visitor tests (<a href="https://github.com/seuros/activerecord-postgis/commit/b7afd42f1c432e9abe5b97983aca9735c1d499c3">b7afd42</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/seuros/activerecord-postgis/blob/master/CHANGELOG.md">activerecord-postgis's changelog</a>.</em></p>
<blockquote>
<h2><a href="https://github.com/seuros/activerecord-postgis/compare/activerecord-postgis/v0.5.1...activerecord-postgis/v0.6.0">0.6.0</a> (2026-08-31)</h2>
<h3>Features</h3>
<ul>
<li>use new PG type registration api (<a href="https://redirect.github.com/seuros/activerecord-postgis/issues/17">#17</a>) (<a href="https://github.com/seuros/activerecord-postgis/commit/2b8f67340124a5f218256bdc447ac6ae5b3d9752">2b8f673</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>support Rails 8.2 schema_ignored_tables (<a href="https://github.com/seuros/activerecord-postgis/commit/9e08e135bc9b9d745edd351461cbf1a24c328764">9e08e13</a>)</li>
<li>test ruby 4.0 (<a href="https://github.com/seuros/activerecord-postgis/commit/6de79842d9c7271f88e81d39cf73fd00541efea9">6de7984</a>)</li>
<li>use SpatialModel.arel_table in Arel visitor tests (<a href="https://github.com/seuros/activerecord-postgis/commit/b7afd42f1c432e9abe5b97983aca9735c1d499c3">b7afd42</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/3984fc19d530efcd10ffd10d59efd75ab09734ab"><code>3984fc1</code></a> chore(master): release activerecord-postgis 0.6.0 (<a href="https://redirect.github.com/seuros/activerecord-postgis/issues/18">#18</a>)</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/b7afd42f1c432e9abe5b97983aca9735c1d499c3"><code>b7afd42</code></a> fix: use SpatialModel.arel_table in Arel visitor tests</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/9e08e135bc9b9d745edd351461cbf1a24c328764"><code>9e08e13</code></a> fix: support Rails 8.2 schema_ignored_tables</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/6de79842d9c7271f88e81d39cf73fd00541efea9"><code>6de7984</code></a> fix: test ruby 4.0</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/15a28479267a42c51e55858750da132143043a17"><code>15a2847</code></a> docs: update README for Rails 8.1 and remove emojis</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/57f6c9eb401b04393089311d546b7b99c84190ec"><code>57f6c9e</code></a> chore: add rails_lens dev dependency and annotate models (<a href="https://redirect.github.com/seuros/activerecord-postgis/issues/19">#19</a>)</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/2b8f67340124a5f218256bdc447ac6ae5b3d9752"><code>2b8f673</code></a> feat: use new PG type registration api (<a href="https://redirect.github.com/seuros/activerecord-postgis/issues/17">#17</a>)</li>
<li><a href="https://github.com/seuros/activerecord-postgis/commit/59396721d0a9777a8c46eb59d8d70849c573bd70"><code>5939672</code></a> chore: switch Rails version from 8.1.0.beta1 to 8.1.1</li>
<li>See full diff in <a href="https://github.com/seuros/activerecord-postgis/compare/activerecord-postgis/v0.5.1...activerecord-postgis/v0.6.0">compare view</a></li>
</ul>
</details>
<br />
Updates `bootsnap` from 1.25.0 to 1.26.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/rails/bootsnap/releases">bootsnap's releases</a>.</em></p>
<blockquote>
<h2>v1.26.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Handle top level <code>Coverage</code> constant being defined, but without it being the true stdlib <code>coverage</code> module.</li>
<li>Fix <code>bootsnap precompile</code> that could generate a corrupted cache entry if an already cached YAML file was modified
without changing its size.</li>
<li>Workaround a potential Ruby SEGV if <code>Bootsnap.instrumentation</code> raised an error.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/rails/bootsnap/blob/main/CHANGELOG.md">bootsnap's changelog</a>.</em></p>
<blockquote>
<h1>1.26.0</h1>
<ul>
<li>Handle top level <code>Coverage</code> constant being defined, but without it being the true stdlib <code>coverage</code> module.</li>
<li>Fix <code>bootsnap precompile</code> that could generate a corrupted cache entry if an already cached YAML file was modified
without changing its size.</li>
<li>Workaround a potential Ruby SEGV if <code>Bootsnap.instrumentation</code> raised an error.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/rails/bootsnap/commit/67a7290e0318ad59e8c97bb81c816dcf23801f20"><code>67a7290</code></a> Release 1.26.0</li>
<li><a href="https://github.com/rails/bootsnap/commit/1881b9a26daa6c2d891f3864cc71ae159749ba4b"><code>1881b9a</code></a> Merge pull request <a href="https://redirect.github.com/rails/bootsnap/issues/573">#573</a> from byroot/same-size-miscompilation</li>
<li><a href="https://github.com/rails/bootsnap/commit/605bbeb9a531b6a6ff0e261bd677e9dd31997838"><code>605bbeb</code></a> Fix precompilation when regenerating an existing cache entry of the same size</li>
<li><a href="https://github.com/rails/bootsnap/commit/5fd59dace072f2d5e8bf5fac192dbccf1bf2662f"><code>5fd59da</code></a> Merge pull request <a href="https://redirect.github.com/rails/bootsnap/issues/569">#569</a> from OskarEichler/codex/accept-tempfile-fd-zero</li>
<li><a href="https://github.com/rails/bootsnap/commit/70550c774a93cc9382edc5785529ad97ae9acf8f"><code>70550c7</code></a> Merge pull request <a href="https://redirect.github.com/rails/bootsnap/issues/568">#568</a> from OskarEichler/codex/remove-umask-debug-output</li>
<li><a href="https://github.com/rails/bootsnap/commit/8aed2ed171cc25a4a337622d6e5a5b1af3e707be"><code>8aed2ed</code></a> Accept tempfile descriptor zero</li>
<li><a href="https://github.com/rails/bootsnap/commit/f7457ea0b2ef3f94237ef677f7f07a002961efd4"><code>f7457ea</code></a> Remove umask debug output</li>
<li><a href="https://github.com/rails/bootsnap/commit/9ee62a2f3ac544e0e6130620d90be7a64779db34"><code>9ee62a2</code></a> Merge pull request <a href="https://redirect.github.com/rails/bootsnap/issues/567">#567</a> from byroot/rename-mod</li>
<li><a href="https://github.com/rails/bootsnap/commit/7c8178ec5862db4099e4a29846ded0bc34bb0bbd"><code>7c8178e</code></a> Handle <code>write(2)</code> being interrupted.</li>
<li><a href="https://github.com/rails/bootsnap/commit/3e755ca99d0e2f4cacd4bf5d78b1bfa25dac9456"><code>3e755ca</code></a> atomic_write_cache_file: stop leaking FD on error</li>
<li>Additional commits viewable in <a href="https://github.com/rails/bootsnap/compare/v1.25.0...v1.26.0">compare view</a></li>
</ul>
</details>
<br />
Updates `omniauth-google-oauth2` from 1.2.2 to 1.2.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/zquestz/omniauth-google-oauth2/releases">omniauth-google-oauth2's releases</a>.</em></p>
<blockquote>
<h2>v1.2.3</h2>
<h3>Security</h3>
<ul>
<li>Verify caller-supplied ID tokens against Google's published signing keys before trusting them. An ID token sent alongside a direct <code>access_token</code> callback was previously decoded without checking its signature, so <code>extra.id_info</code> and <code>extra.id_token</code> could be populated from a forged token. <code>uid</code> and <code>info</code> were never affected, as they come from the userinfo endpoint. A caller-supplied ID token genuinely issued by Google for the same user and a trusted client continues to be accepted after verification.</li>
<li>Require a caller-supplied ID token to describe the same user as the access token it was sent with, by comparing the token's <code>sub</code> against the userinfo subject. A verified signature only proves Google issued the token, not that it belongs to the person the access token identifies, so without this a genuine ID token for one user could be paired with an access token for another and leave <code>uid</code> and <code>extra.id_info</code> describing different people. The <code>at_hash</code> claim is checked first as a fast path, and this subject check settles the cases <code>at_hash</code> cannot: tokens that omit the claim, and tokens whose <code>at_hash</code> is stale because the client refreshed its access token after sign-in. This check runs even when <code>skip_info</code> is set, as that option trims the auth hash rather than waiving verification.</li>
<li>The bundled example app no longer disables TLS certificate verification. Anyone who copied that line into an application should remove it: it turns off certificate checking for every Faraday-based request in the process, not just the ones this gem makes.</li>
</ul>
<h3>Added</h3>
<ul>
<li><code>reset_jwks_cache!</code> for clearing the cached Google signing keys between tests.</li>
<li><code>cached_jwks</code>, the class-level fetch-and-cache primitive behind it, which takes the fetch itself as a block.</li>
<li><code>JWKS_URL</code>, <code>JWKS_CACHE_TTL</code>, and <code>JWKS_RETRY_INTERVAL</code> constants, and a <code>JwksUnavailable</code> error.</li>
<li>An upper bound of <code>< 4</code> on the <code>jwt</code> dependency. This is precautionary rather than a response to a released version: it keeps a future major release from being picked up before it has been verified against this strategy.</li>
</ul>
<h3>Deprecated</h3>
<ul>
<li>Nothing.</li>
</ul>
<h3>Removed</h3>
<ul>
<li>The fallback that placed the opaque access token in <code>extra.id_token</code> when no ID token was present. <code>extra.id_token</code> is now absent in that case rather than holding a value that was never an ID token. This was only reachable with <code>skip_jwt</code> set; without it the fallback raised instead.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Ignore every credential field a caller supplies in a direct access-token callback apart from the access token itself and a verified ID token. <code>refresh_token</code> and token expiry in particular cannot be verified, so they are no longer carried through.</li>
<li>Avoid decoding opaque access tokens as JWTs when no ID token is available.</li>
<li>Fail with a normal authentication failure when a callback carries no usable credential, such as an ID token with no access token, a JSON body that is not an object, or an unparseable body. Previously these raised a <code>NoMethodError</code> or <code>TypeError</code> that OmniAuth turned into a failure whose message was the raw Ruby error, so applications received an unstable <code>message</code> parameter such as <code>undefined method 'expired?'</code> instead of <code>invalid_credentials</code>.</li>
<li>Serve the cached signing keys when Google's key endpoint is briefly unreachable, and back off before refetching, rather than retrying on every request, including when nothing is cached yet.</li>
<li>Reject a signing key response that is not an object with a <code>keys</code> array, rather than passing it on to be interpreted as some other kind of key.</li>
<li>Cap how often an ID token naming an unrecognised key can force a key refresh, so it cannot be used to drive unbounded outbound requests while holding the shared cache lock. Key rotation still resolves within <code>JWKS_RETRY_INTERVAL</code>.</li>
<li><code>jwt_leeway</code> now also applies when verifying caller-supplied ID tokens, matching how it already behaved for the <code>extra</code> block.</li>
<li>Support non-rewindable JSON request bodies under Rack 3.</li>
<li>Accept ID tokens issued to any configured <code>authorized_client_ids</code>, matching the audiences already accepted for access tokens.</li>
<li>Reuse successfully verified ID token claims when building <code>extra</code>, so each ID token is decoded and validated only once per request.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/zquestz/omniauth-google-oauth2/blob/master/CHANGELOG.md">omniauth-google-oauth2's changelog</a>.</em></p>
<blockquote>
<h2>1.2.3 - 2026-08-31</h2>
<h3>Security</h3>
<ul>
<li>Verify caller-supplied ID tokens against Google's published signing keys before trusting them. An ID token sent alongside a direct <code>access_token</code> callback was previously decoded without checking its signature, so <code>extra.id_info</code> and <code>extra.id_token</code> could be populated from a forged token. <code>uid</code> and <code>info</code> were never affected, as they come from the userinfo endpoint. A caller-supplied ID token genuinely issued by Google for the same user and a trusted client continues to be accepted after verification.</li>
<li>Require a caller-supplied ID token to describe the same user as the access token it was sent with, by comparing the token's <code>sub</code> against the userinfo subject. A verified signature only proves Google issued the token, not that it belongs to the person the access token identifies, so without this a genuine ID token for one user could be paired with an access token for another and leave <code>uid</code> and <code>extra.id_info</code> describing different people. The <code>at_hash</code> claim is checked first as a fast path, and this subject check settles the cases <code>at_hash</code> cannot: tokens that omit the claim, and tokens whose <code>at_hash</code> is stale because the client refreshed its access token after sign-in. This check runs even when <code>skip_info</code> is set, as that option trims the auth hash rather than waiving verification.</li>
<li>The bundled example app no longer disables TLS certificate verification. Anyone who copied that line into an application should remove it: it turns off certificate checking for every Faraday-based request in the process, not just the ones this gem makes.</li>
</ul>
<h3>Added</h3>
<ul>
<li><code>reset_jwks_cache!</code> for clearing the cached Google signing keys between tests.</li>
<li><code>cached_jwks</code>, the class-level fetch-and-cache primitive behind it, which takes the fetch itself as a block.</li>
<li><code>JWKS_URL</code>, <code>JWKS_CACHE_TTL</code>, and <code>JWKS_RETRY_INTERVAL</code> constants, and a <code>JwksUnavailable</code> error.</li>
<li>An upper bound of <code>< 4</code> on the <code>jwt</code> dependency. This is precautionary rather than a response to a released version: it keeps a future major release from being picked up before it has been verified against this strategy.</li>
</ul>
<h3>Deprecated</h3>
<ul>
<li>Nothing.</li>
</ul>
<h3>Removed</h3>
<ul>
<li>The fallback that placed the opaque access token in <code>extra.id_token</code> when no ID token was present. <code>extra.id_token</code> is now absent in that case rather than holding a value that was never an ID token. This was only reachable with <code>skip_jwt</code> set; without it the fallback raised instead.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Ignore every credential field a caller supplies in a direct access-token callback apart from the access token itself and a verified ID token. <code>refresh_token</code> and token expiry in particular cannot be verified, so they are no longer carried through.</li>
<li>Avoid decoding opaque access tokens as JWTs when no ID token is available.</li>
<li>Fail with a normal authentication failure when a callback carries no usable credential, such as an ID token with no access token, a JSON body that is not an object, or an unparseable body. Previously these raised a <code>NoMethodError</code> or <code>TypeError</code> that OmniAuth turned into a failure whose message was the raw Ruby error, so applications received an unstable <code>message</code> parameter such as <code>undefined method 'expired?'</code> instead of <code>invalid_credentials</code>.</li>
<li>Serve the cached signing keys when Google's key endpoint is briefly unreachable, and back off before refetching, rather than retrying on every request, including when nothing is cached yet.</li>
<li>Reject a signing key response that is not an object with a <code>keys</code> array, rather than passing it on to be interpreted as some other kind of key.</li>
<li>Cap how often an ID token naming an unrecognised key can force a key refresh, so it cannot be used to drive unbounded outbound requests while holding the shared cache lock. Key rotation still resolves within <code>JWKS_RETRY_INTERVAL</code>.</li>
<li><code>jwt_leeway</code> now also applies when verifying caller-supplied ID tokens, matching how it already behaved for the <code>extra</code> block.</li>
<li>Support non-rewindable JSON request bodies under Rack 3.</li>
<li>Accept ID tokens issued to any configured <code>authorized_client_ids</code>, matching the audiences already accepted for access tokens.</li>
<li>Reuse successfully verified ID token claims when building <code>extra</code>, so each ID token is decoded and validated only once per request.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/c2fa91f53806725f3afd459b6e58e3020f1e3a0a"><code>c2fa91f</code></a> Fix token info cache keying and log injection, and require core ID token claims</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/c6af73e631b0201913bff13e5276784c06797d63"><code>c6af73e</code></a> Reduce redundant JWKS cache timestamp calculations</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/778c9906f3b46f488ca935293b30cc6dc0a45c43"><code>778c990</code></a> Tiny README.md correction</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/eae8feb8994c3ebbcfacc90e83020966cbbc7cb2"><code>eae8feb</code></a> Clarify CHANGELOG.md</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/ef303e62e40a0ed3e979b938cd03d428ea227747"><code>ef303e6</code></a> Accept ID tokens from authorized client IDs and fix Ruby 2.5 compatibility</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/e5be50ed4b98980bbe449bbd5f165e04477012e5"><code>e5be50e</code></a> Verify caller-supplied ID tokens against Google's signing keys and bind them ...</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/650aab99f7611e14d1414aeeac99fb769448408b"><code>650aab9</code></a> Update example to show AJAX payloads</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/0b87f3f2c7a8f9438ae8c676fcdfbdaacc87f66d"><code>0b87f3f</code></a> Fix ID token spoofing in direct access-token callbacks</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/41796b62f47192e2b51b46525132932248992347"><code>41796b6</code></a> specify that jwt must be less than version 4 (<a href="https://redirect.github.com/zquestz/omniauth-google-oauth2/issues/476">#476</a>)</li>
<li><a href="https://github.com/zquestz/omniauth-google-oauth2/commit/55590719512739ee8300b9a8c7a2ab7a4651145e"><code>5559071</code></a> Better CHANGELOG.md</li>
<li>See full diff in <a href="https://github.com/zquestz/omniauth-google-oauth2/compare/v1.2.2...v1.2.3">compare view</a></li>
</ul>
</details>
<br />
Updates `opentelemetry-exporter-otlp` from 0.34.1 to 0.35.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/open-telemetry/opentelemetry-ruby/releases">opentelemetry-exporter-otlp's releases</a>.</em></p>
<blockquote>
<h2>opentelemetry-exporter-otlp 0.35.1</h2>
<h3>v0.35.1 / 2026-09-01</h3>
<ul>
<li>REVERT: Use common conversion including supporting flags (<a href="https://redirect.github.com/open-telemetry/opentelemetry-ruby/issues/2328">#2328</a>)</li>
</ul>
<h2>opentelemetry-exporter-otlp 0.35.0</h2>
<h3>v0.35.0 / 2026-09-01</h3>
<ul>
<li>ADDED: Use common conversion including supporting flags (<a href="https://redirect.github.com/open-telemetry/opentelemetry-ruby/issues/2250">#2250</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/open-telemetry/opentelemetry-ruby/compare/opentelemetry-exporter-otlp/v0.34.1...opentelemetry-exporter-otlp/v0.35.1">compare view</a></li>
</ul>
</details>
<br />
Updates `image_processing` from 2.0.3 to 2.1.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/janko/image_processing/blob/master/CHANGELOG.md">image_processing's changelog</a>.</em></p>
<blockquote>
<h2>2.1.0 (2026-09-01)</h2>
<ul>
<li>[minimagick] Add <code>inherit_fds:</code> so a loader can name an already-open input (thanks to <a href="https://github.com/flavorjones"><code>@flavorjones</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/janko/image_processing/commit/3d990c3cd3f478eda5a9373d48f6f0c39e615b72"><code>3d990c3</code></a> Set version to 2.1.0</li>
<li><a href="https://github.com/janko/image_processing/commit/722d900ea46e8a701e7513e1ec45cdf434229eae"><code>722d900</code></a> Add <code>inherit_fds:</code> so a loader can name an already-open input (<a href="https://redirect.github.com/janko/image_processing/issues/147">#147</a>)</li>
<li>See full diff in <a href="https://github.com/janko/image_processing/compare/v2.0.3...v2.1.0">compare view</a></li>
</ul>
</details>
<br />
Updates `overcommit` from 0.72.0 to 0.73.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/sds/overcommit/releases">overcommit's releases</a>.</em></p>
<blockquote>
<h2>0.73.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add pre commit hook for herb-lint by <a href="https://github.com/tomhughes"><code>@tomhughes</code></a> in <a href="https://redirect.github.com/sds/overcommit/pull/892">sds/overcommit#892</a></li>
<li>Add filetypes to oxc tools by <a href="https://github.com/benmelz"><code>@benmelz</code></a> in <a href="https://redirect.github.com/sds/overcommit/pull/893">sds/overcommit#893</a></li>
<li>Instruct oxfmt not to fail if no files are matched by <a href="https://github.com/benmelz"><code>@benmelz</code></a> in <a href="https://redirect.github.com/sds/overcommit/pull/894">sds/overcommit#894</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tomhughes"><code>@tomhughes</code></a> made their first contribution in <a href="https://redirect.github.com/sds/overcommit/pull/892">sds/overcommit#892</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/sds/overcommit/compare/v0.72.0...v0.73.0">https://github.com/sds/overcommit/compare/v0.72.0...v0.73.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/sds/overcommit/blob/main/CHANGELOG.md">overcommit's changelog</a>.</em></p>
<blockquote>
<h2>0.73.0</h2>
<ul>
<li>Add pre-commit hook for <a href="https://herb-tools.dev/projects/linter">herb-lint</a></li>
<li>Add default file types to oxc hooks</li>
<li>Fix <code>oxfmt</code> to not fail if no files are matched</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/sds/overcommit/commit/c06c0f5c47cdcabc782e45d8696b88b02b51514b"><code>c06c0f5</code></a> Cut version 0.73.0 (<a href="https://redirect.github.com/sds/overcommit/issues/896">#896</a>)</li>
<li><a href="https://github.com/sds/overcommit/commit/150bd0bd0efda465f79078e4771c6b76ed36520b"><code>150bd0b</code></a> Add automated release flow (<a href="https://redirect.github.com/sds/overcommit/issues/895">#895</a>)</li>
<li><a href="https://github.com/sds/overcommit/commit/3b651f9adc58b55eea9b81e9da0549157702b917"><code>3b651f9</code></a> Instruct oxfmt not to fail if no files are matched (<a href="https://redirect.github.com/sds/overcommit/issues/894">#894</a>)</li>
<li><a href="https://github.com/sds/overcommit/commit/857a2720bda369d2233619b105738e53aa9f47bb"><code>857a272</code></a> Add filetypes to oxc tools (<a href="https://redirect.github.com/sds/overcommit/issues/893">#893</a>)</li>
<li><a href="https://github.com/sds/overcommit/commit/fee0cd74b26eb81f64b43b7fab17bbb541575cc4"><code>fee0cd7</code></a> Add pre commit hook for herb-lint (<a href="https://redirect.github.com/sds/overcommit/issues/892">#892</a>)</li>
<li>See full diff in <a href="https://github.com/sds/overcommit/compare/v0.72.0...v0.73.0">compare view</a></li>
</ul>
</details>
<br />
Updates `simplecov` from 1.1.1 to 1.2.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/simplecov-ruby/simplecov/releases">simplecov's releases</a>.</em></p>
<blockquote>
<h2>v1.2.0</h2>
<p>SimpleCov 1.2 adds change-focused coverage, per-test attribution, production coverage, and a substantially expanded
CLI while keeping the existing configuration API working through deprecation aliases.</p>
<h2>Highlights</h2>
<ul>
<li><code>track_tests</code>, <code>simplecov tests</code>, and <code>simplecov affected</code> connect covered lines to the tests that exercised them; the HTML report displays the same attribution and <code>simplecov watch</code> uses it for focused reruns.</li>
<li><code>simplecov patch</code>, per-file baselines, missed-count caps, and coverage history make coverage gates useful for both new changes and legacy codebases.</li>
<li><code>SimpleCov::Production</code> records low-overhead production line coverage, while <code>simplecov dead-code</code> and the bundled reports cross it with test coverage.</li>
<li>ActionView templates can be measured with <code>cover_views</code>, including ERB, Haml, and Slim source highlighting.</li>
<li>The CLI gains annotated source, report freshness, history, badges, shell completions, a man page, and richer machine-readable output.</li>
</ul>
<h2>Upgrade notes</h2>
<ul>
<li>The minimum supported Ruby remains 3.2; JRuby 10 remains supported for line coverage.</li>
<li>Successful runs now maintain the bounded <code>coverage/.history.json</code> file by default. Set <code>history_limit 0</code> to disable it.</li>
<li>Existing configuration continues to work, but criterion-specific filters and threshold scopes now prefer <code>coverage(:criterion) { ignore ... }</code> and <code>minimum ..., per: ...</code>. The legacy forms warn with their exact replacements, and <code>deprecations :raise</code> can enforce a completed migration.</li>
<li><code>coverage.json</code> advances additively to schema 1.3 for test-context, history, baseline-error, and production data. Previously published versioned schemas remain frozen for pinned consumers.</li>
</ul>
<h2>Enhancements</h2>
<ul>
<li>
<p>The HTML report's source view renders the <code>track_tests</code> recording. A covered line no recorded test executed drains from green to a slate tint, with a "Covered outside tests" legend chip, so coverage produced only by load time, suite setup, or helpers stops passing for tested code at a glance. Every executed line carries a tests badge naming its count, and clicking it opens an inline panel listing the covering tests, the same ids in the same order <code>simplecov tests file:line</code> prints, each one selectable with a click for handing to a runner. Drained lines explain themselves in the same panel instead of listing nothing. The file header's Line coverage row splits its fraction by the same attribution ("Line coverage: 100.00% 21/30 relevant lines covered by tests, 9/30 relevant lines covered outside tests"), the legend's covered chip splits to match (green "Covered by tests" beside the slate "Covered outside tests"), keyboard access rides on real buttons with the report's focus ring, and the panel closes on Escape without closing the source dialog. The file list draws the same distinction: each line coverage bar splits its fill into the share recorded tests produced (in the usual band colour) and a slate share covered only outside them, in the file rows and the live-filtered totals row alike, and sorting by line coverage breaks ties on the by-tests share, so of two files at 100% the one whose coverage rests on its tests ranks above the one warmed by load time. All of it appears only when the report was generated with <code>track_tests</code> enabled, so other reports render exactly as before.</p>
</li>
<li>
<p><code>simplecov patch</code> reports coverage of just the lines a change touched, the question <code>diff</code> does not answer. Where <code>diff</code> compares two reports and asks whether the overall number moved — which a large or legacy project cannot shift in one pull request — <code>patch</code> reads <code>git diff --unified=0 --merge-base <base></code>, intersects the added and modified line numbers with the current report, and prints line coverage — and, when the report measured branches or methods, branch and method coverage over the branches and methods those lines carry — for only that change, so a project sitting at 40% can still insist that everything it adds is tested. <code>--minimum N</code> exits non-zero below a floor (every measured criterion must clear it), composing with CI as a per-change gate alongside the existing thresholds; <code>--base</code> selects the ref to diff against (defaulting to the branch origin's HEAD points at, else <code>main</code>; in CI, the target branch or its merge-base); <code>--find-renames</code> follows a moved file instead of counting it as all-new; and <code>--json</code> emits the rows the other read-only commands do. Only files the report already carries are scored, and a line <code>LinesClassifier</code> deems never relevant stays out of the denominator the same way it stays out of a file's total, so a comment-only or whitespace change reads as nothing to cover rather than as a gap. A brand-new file that was never <code>git add</code>ed appears in no diff yet is still the change's work, so untracked files are scored too, every report-known line of them as new. The diff is anchored at the repository root rather than the working directory, so a run from a subdirectory reports the same change, and changed files resolve against the report by exact path, so a lookalike entry elsewhere in the report can never be scored in a changed file's place. A changed line beyond what the report knows for its file draws a staleness warning instead of silently scoring nothing, a git failure reports git's own words rather than a guess, and a path that matches more than one report entry names its candidates, in <code>coverage</code> and <code>tests</code> too, instead of a bare "no entry". Almost none of this is new machinery: the report already knows which lines are relevant and which were hit, leaving a hunk-header parser and path resolution against the report's root. Prior art is <code>diff-cover</code>, Codecov's patch status, and the <code>undercover</code> gem, which does this for Ruby but needs its own formatter and a git dependency to get there. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1262">#1262</a>.</p>
</li>
<li>
<p><code>track_tests</code> recording got a cost model and the levers to control it. Recording now settles at segment boundaries: consecutive tests share their boundary coverage snapshot (one snapshot closes one test's segment and opens the next, attributing any in-between code to the later test), which halves the per-test sampling cost outright, and the project-root check is memoized per file. On top of that, <code>track_tests granularity: :file</code> records one context per test file instead of per test, so the suite pays one snapshot per change of file in run order rather than one per test, and test selection needs no more than file identity anyway. On a real 1,756-test Minitest suite measuring line, branch, and method coverage, the two changes together cut tracking overhead from 52 seconds to 28 at the default granularity and to 13 at <code>:file</code>. The remaining floor is Ruby's own <code>Coverage.peek_result</code> copy, which scales with the criteria the run measures: a millisecond or two under line coverage alone, an order of magnitude more with branch and method tables, which the docs now spell out.</p>
</li>
<li>
<p><code>simplecov tests</code> answers which tests cover a file or line, from the terminal. Bare, it lists every test recorded under <code>track_tests</code>. With a path it narrows to the tests touching that file, and with <code>path:line</code> to one line. Text output is one test id per line and nothing else on stdout, sorted, so the list can feed a runner directly (<code>simplecov tests lib/foo.rb:42 | xargs bundle exec rspec</code>), with empty answers noted on stderr instead. <code>--json</code> emits a JSON array, and <code>--input</code> picks the report like the other read-only subcommands. It reads the <code>contexts</code> data in <code>coverage.json</code>, so it works on any report generated after <code>track_tests</code> was enabled, and explains what to enable when the recording is missing.</p>
</li>
<li>
<p><code>simplecov tests --redundant</code> lists the tests whose covered lines other tests also cover, the tests contributing no coverage of their own, computed from the same <code>track_tests</code> recording with no new measurement. The flag composes with the narrowing, so <code>simplecov tests --redundant lib/foo.rb</code> lists the redundant tests among those touching the file. The listed ids are candidates for review rather than a delete list: assertions and mutation-killing power are invisible to coverage, and two tests covering exactly the same lines subsume each other, so both are listed and deleting both would lose the lines. An empty answer over a real recording is good news and says so on stderr.</p>
</li>
<li>
<p><code>simplecov affected</code> selects the tests that touch changed code. It diffs the working tree against the merge base of a git ref (<code>--base</code>, defaulting to the branch origin's HEAD points at, else <code>main</code>) and HEAD, so uncommitted work counts as part of the change while commits that landed on the base after the branch point do not, includes untracked files, and prints the test files whose recorded tests touch the changed files, so the local inner loop can run <code>simplecov affected --run bundle exec rspec</code> instead of the whole suite. Everything after <code>--run</code> is the runner command, the selection is appended to it, and the exit status is the command's own. The set intersection is the easy half. The hard half is knowing when to distrust the map, because a test map is stale the moment something changes that no test mentions by name, so any changed file outside the tracked set fails open to the full suite, out loud: a changed <code>Gemfile.lock</code>, <code>.simplecov</code>, spec helper, runner configuration, or any file the report has no data for is named on stderr as the trigger, while stdout prints nothing, which a bare runner reads as run everything. Changed or brand-new test files always select themselves, recorded or not, a test file deleted by the change drops out of the answer, and a recorded test whose file no longer exists anywhere else reads as staleness rather than being silently skipped. <code>--json</code> emits the selection with its <code>full_suite</code> verdict and triggers for tooling, and <code>--input</code> picks the report like the other read-only subcommands. Like <code>patch</code>, the diff is anchored at the repository root, so a run from a subdirectory selects over the whole change, with <code>--run</code> starting the runner at that root, and changed files resolve against the report by exact path, so a lookalike entry elsewhere in the report can never stand in for a changed file the report does not carry. Built for the local inner loop first, because a wrong answer in CI is a green build on a broken change. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1264">#1264</a>. <code>track_tests</code> in a <code>SimpleCov.start</code> block samples coverage around every RSpec example and Minitest test, and stores the map in <code>.resultset.json</code> under a versioned <code>contexts</code> key beside the merged coverage, exposed as <code>SimpleCov::Result#contexts</code> with a <code>covering(path, line)</code> lookup. The data layer speaks of contexts rather than tests because the mechanism is general and matches the vocabulary a future Coverage library feature would use, while under <code>track_tests</code> every context is one test. Test ids are interned and each test's covered lines are packed into per-file bitmaps, which keeps the naive tests-times-lines storage in hand. Merges union the maps when every merged result recorded one and drop them out loud otherwise, across suites, concurrent runners, parallel workers, and <code>simplecov collate</code> alike, since a partial map would present one worker's tests as the whole run's. The Minitest wrapper installs through the minitest 5 plugin, and under minitest 6, whose autorun no longer discovers plugins, the moment <code>Minitest::Test</code> is defined. Other runners wrap their own units of work with <code>SimpleCov.track_test</code>. Tests running concurrently in threads inside one process cannot be told apart, because coverage counters are process-global, so such a process warns and stores no map rather than a misattributed one, while process-parallel workers each record their own. The serialized map carries a format version, so a future format reads as absent instead of being misread. The map also flows into <code>coverage.json</code>, the durable artifact downstream tools build on, as a document-level <code>contexts</code> array plus per-file hex bitmaps, under coverage.json schema 1.1 (<code>schemas/coverage-v1.1.schema.json</code>, with 1.0 staying frozen for pinned integrations, and the new keys optional so documents without recordings stay minimal). Opt-in because sampling around every test costs run time and the map costs space. Needs regular line coverage, so <code>:oneshot_line</code> is rejected at startup, because a line reports only its first hit ever and every later test's delta would miss it. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1263">#1263</a>.</p>
</li>
<li>
<p>ActionView templates can be part of the report. <code>cover_views</code> in a <code>SimpleCov.start</code> block turns on eval coverage, which is what measures a template the suite renders, and compiles the templates it never renders so they appear at 0% rather than not at all. Rendering already produced usable data, because ActionView compiles each template with <code>module_eval(source, identifier, offset)</code> where the identifier is the template's own path and the offset cancels the <code>def</code> line its wrapper adds, so the generated code is attributed back to the <code>.erb</code> file at the template's own line numbers and nothing needs remapping. The gap was the other half: a template no test renders is never compiled, so <code>Coverage</code> never hears about it, and the views with no coverage were exactly the ones the report omitted. <code>cover_views</code> defaults to a Rails app's views, takes globs of its own for templates that live elsewhere, and honors <code>skip</code> like any other file in the report. The <code>rails</code> profile gains a matching <code>Views</code> group, which stays empty in a project that has not opted in. Needs CRuby 3.2 or later, which is what eval coverage needs. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1265">#1265</a>.</p>
</li>
<li>
<p>The source view highlights each file by its own language rather than assuming Ruby. A <code>.erb</code> template used to be handed to the Ruby grammar, which declines to match markup and left the view almost entirely unhighlighted, so templates now go through an ERB grammar that marks up the tags and highlights what is between them as Ruby. It is a small grammar of SimpleCov's own rather than the one highlight.js ships, whose markup is delegated to a full XML grammar that carries a literal <code></script</code> the report cannot inline (the whole report is one <code>index.html</code> with its JavaScript in a <code><script></code> element) and that would have cost around 5KB in every report written. The one shipped costs 627 bytes.</p>
</li>
<li>
<p>The changelog is back at <code>CHANGELOG.md</code> in the project root, where the convention documented at <a href="https://keepachangelog.com">keepachangelog.com</a> puts it and where humans and tooling look for it. Moving it under <code>docs/</code> was never what kept it out of the packaged gem: <code>gem.files</code> lists what ships, so the file stays unpackaged where it is. The gem's <code>changelog_uri</code> metadata follows it back, and the pre-0.18 entries stay at <code>docs/Changelog.old.md</code>. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1272">#1272</a>.</p>
</li>
<li>
<p><code>cover_views</code> reaches Haml and Slim, and its default glob is now <code>app/views/**/*.{erb,haml,slim}</code>. Nothing was needed to measure them beyond looking the handler up the way ActionView's own resolver does: both generate Ruby that keeps the template's line structure, so hits land on the lines their authors wrote. The same goes for any other language a project has registered a handler for, which needs only its extension named in a glob. An extension with no registered handler is now left out of the report instead of being compiled through ActionView's raw handler, which would have reported a project that has no Haml a file of static text for every <code>.haml</code> its default glob happened to match. The source view highlights Haml and Slim as themselves, the second through a small grammar of SimpleCov's own since highlight.js ships none.</p>
</li>
<li>
<p><code>simplecov watch</code> turns the report into something you look at while writing the test. It serves the report the way <code>serve</code> does, polls the tracked files for saves, re-runs the given command when something changes, and pushes a reload to the open tab over server-sent events the moment the report regenerates, with the result line naming the change and the coverage delta ("lib/result.rb changed, running 3 files... 100.00% (+0.40%)"), the number following the report's primary criterion. With a <code>track_tests</code> recording in the report a save re-runs only the tests touching the changed files, by the same selection walk <code>simplecov affected</code> uses and with the same fail-open rule, and without one every save runs the full command. The watched set is the report's own tracked files plus the recorded tests' files, polled by mtime rather than through a filesystem-event dependency, which also keeps report writes from triggering the next run. Child runs get a day-long merge window through the new <code>SIMPLECOV_MERGE_TIMEOUT</code> environment variable (honored by <code>merge_timeout</code> generally), so subset re-runs keep merging into a whole report across a long session. The report on disk stays byte-identical to a plain run's, with the reload listener added only on the way out of the server, and <code>--open</code> pops the report in the default browser on start. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1269">#1269</a>.</p>
</li>
<li>
<p><code>simplecov show <path></code> prints annotated source in the terminal, the way <code>go tool cover</code> and <code>llvm-cov show</code> do: hit counts in the gutter, a caret marker naming each miss under its line, and branch and method misses annotated the same way when the report measured them. <code>--uncovered-only</code> collapses the answer to <code>path:40,52-58,71</code>, a form that greps, fits in a commit message, and hands a coding agent exactly the lines whose tests are missing, and <code>--json</code> emits the whole annotation as data (missed lines, per-line hits, marker labels) for editor integrations. With no path, <code>--uncovered-only</code> sweeps the whole project into one <code>path:ranges</code> line per file with misses, and a bare <code>--json</code> emits the same sweep as data. Colors follow the usual <code>NO_COLOR</code>, <code>FORCE_COLOR</code>, and <code>--no-color</code> rules. The source comes from the report itself when it embeds one, and otherwise from disk, accepted only while the file's line count still matches the report's, since annotating drifted source would put hit counts on the wrong lines. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1270">#1270</a>.</p>
</li>
<li>
<p><code>simplecov status</code> answers "is this report fresh?" from metadata the artifacts have carried all along: the report's age, the SimpleCov version and run that produced it, the recorded commit and how many commits HEAD has moved since, the measured totals, whether a <code>track_tests</code> map is present (and what to enable when it isn't), and the resultset's entries with their ages. <code>--json</code> emits the same facts as data. Every staleness question the change-aware commands raise now has a one-command answer.</p>
</li>
<li>
<p><code>simplecov uncovered --missing</code> appends the missed line ranges to each row (<code>50.00% 5/10 lib/foo.rb missing 4-7,9</code>), following the chosen criterion (zero-hit lines, or the lines missed branches and methods report on), and adds a <code>missing</code> array to each <code>--json</code> row, so the list says not just where to add tests but which lines they're for. <code>--annotate github</code> emits <code>::warning</code> workflow commands instead of rows, one per contiguous missed range, so a plain GitHub Actions workflow gets inline diff annotations with no upload step and no code-scanning permissions.</p>
</li>
<li>
<p><code>simplecov badge</code> renders the report's percentage as a flat SVG badge in the shields.io style, to stdout or to a file with <code>--output</code>, so a README or CI artifact can carry the number straight from the local report with no badge service in the loop. The color follows the ladder badge services use for coverage (bright green at 90% and above, stepping down to red below 50%), <code>--criterion</code> picks the line, branch, or method percentage, and the label names the chosen criterion ("line coverage", "branch coverage", "method coverage") unless <code>--label</code> replaces it. The percent comes from the totals <code>coverage.json</code> already carries, so the badge always matches what the other read-only commands report.</p>
</li>
<li>
<p><code>simplecov completions fish|bash|zsh</code> prints a tab-completion script for the named shell, covering every subcommand with its description and each command's own options. The script is generated from the usage document itself rather than a hand-kept table, so a new command or option appears in completions the moment it is documented.</p>
</li>
<li>
<p>The gem ships a man page, <code>man/simplecov.1</code>, covering every CLI command and option with the environment variables and files the commands honor. Like the shell completions, it is generated from the usage document (<code>rake man</code> regenerates it) so it cannot drift, and the suite fails when the committed copy is stale. RubyGems does not install man pages onto <code>MANPATH</code>, so read it with <code>man $(gem contents simplecov | grep man/simplecov.1)</code> or let a system package manager place it.</p>
</li>
<li>
<p>Every CLI command answers <code>--help</code> / <code>-h</code> with its own slice of the usage text: the command's row, its options, and the shared options it accepts, instead of the full listing. It also replaces what optparse's built-in handler did before, which was to print a bare option summary under the host program's banner and exit the process from inside the parser.</p>
</li>
<li>
<p>A checked-in per-file coverage baseline that only ratchets up, for legacy codebases where one <code>minimum_coverage</code> number does nothing and one <code>minimum_coverage_by_file</code> number lets the single worst file set the ceiling for the whole policy. <code>simplecov ratchet</code> writes <code>.simplecov_baseline.yml</code> from the current report, one floor per file per measured criterion, and the exit check fails any listed file that drops below its own floor. Rewriting only ever tightens: files that improved get their floors raised, files that regressed keep the floors they are now below (and are named in the summary), entries for deleted files are pruned, and new files never get an entry, so they answer to the real <code>minimum_per_file</code> standard (which files with an entry are exempt from, per criterion) rather than to a floor cut at whatever they launched with. The diff on the baseline file becomes the honest record of which direction the codebase moved, reviewable in the same PR as the change that moved it, the way <code>.rubocop_todo.yml</code> records offenses. The issue left open whether a floor should be a percent or a count of uncovered lines, since a percent moves when a file is edited without any coverage change at all. Each floor stores both: the percent is the policy, and the missed count is the dampener, so a violation requires a lower percent and more misses together, and an edit that only reshuffles covered lines fails nothing. A hand-written bare-percent entry (<code>lib/foo.rb: 41.2</code>) is accepted and decided by percent alone until the next ratchet records its missed count, while a malformed baseline fails loudly rather than silently un-enforcing every floor it carried. <code>--init</code> deliberately regenerates the file from scratch (new files added, floors reset), <code>--dry-run</code> prints without writing, <code>--json</code> emits the summary as data, and <code>--baseline</code> names the file, defaulting to the project's <code>SimpleCov.baseline_file</code>, which the command reads from <code>.simplecov</code> the way the read-only commands read <code>coverage_dir</code>. Baseline violations also land in coverage.json's <code>errors</code> section, under schema 1.2 (additive, with 1.1 staying frozen for pinned integrations). See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1268">#1268</a>.</p>
</li>
<li>
<p><code>maximum_missed</code> and <code>maximum_missed_per_file</code> cap the number of misses instead of demanding a ratio, per criterion: uncovered lines, branch arms, or methods, counted in the criterion's own units. The suite-wide cap is a burn-down number, because "12 uncovered lines left" stays meaningful as the codebase grows and shrinks and is the sentence a team driving to 100% actually says, while the equivalent percentage moves with every edit. The per-file cap says what a per-file percent minimum cannot: a 2,000-line file at 99% hides 20 misses while a 10-line file at 80% fails over 2, so the cap holds every file to the same absolute budget. Both are verbs in the <code>coverage</code> block (<code>coverage(:line) { maximum_missed 12; maximum_missed_per_file 5 }</code>, with the same <code>only:</code> per-path overrides as <code>minimum_per_file</code>) and flat helpers (<code>SimpleCov.maximum_missed line: 12, branch: 3</code>), a fractional or negative cap is a configuration error rather than a silent truncation, and files with a baseline entry are exempt from the per-file cap per covered criterion, the same fall-through <code>minimum_per_file</code> honors. Violations land in coverage.json's <code>errors</code> section as <code>maximum_missed</code> and <code>maximum_missed_per_file</code>, part of schema 1.2. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1268">#1268</a>.</p>
</li>
<li>
<p><code>formats :html, :json</code> selects the bundled formatters by name, so the most-typed constants in every README snippet (<code>SimpleCov::Formatter::HTMLFormatter</code> and friends) are no longer required for the common combinations. <code>:html</code>, <code>:json</code>, <code>:simple</code>, and <code>:baseline</code> are the built-in names, formatter classes and ready-built instances mix freely beside them for third-party and option-carrying formatters, an unknown name raises naming the built-ins, and the bare call reads back the configured chain the way <code>formatters</code> does. The constant-spelled <code>formatter</code> / <code>formatters</code> forms are unchanged and equivalent.</p>
</li>
<li>
<p>Entry filters are criterion-scoped <code>coverage</code> verbs now: <code>coverage(:branch) { ignore :implicit_else, :eval_generated }</code> and <code>coverage :method, ignore: :eval_generated</code> replace <code>ignore_branches</code> / <code>ignore_methods</code>, which had the criterion baked into their names the way the suffixed threshold verbs did. The flat setters are deprecated (warn-and-delegate, replacement named from their own arguments), with one behavior riding out the deprecation period: the coverage block enables the criterion it names, while the legacy setters record the filter without enabling.</p>
</li>
<li>
<p>SimpleCov keeps a coverage history now, not just the last run. Every successful run appends an entry to <code>coverage/.history.json</code>: the percentages for every measured criterion, recorded for the suite, for every group, and for every file, plus a timestamp and the branch and commit when the project is a git checkout. The file is bounded (<code>history_limit</code>, 100 entries by default, 0 disables), written atomically with the corrupt-file tolerance <code>.last_run.json</code> has, and plain committable JSON so the trend can survive a clean CI checkout, while <code>.last_run.json</code> itself keeps working exactly as before. The history buys three things. <code>simplecov history</code> prints the trend in the terminal as Unicode sparklines, one per measured criterion, with the run rows beneath, and <code>--file PATH</code> follows one file's per-criterion trajectory the same way. <code>drop_baseline :median</code> / <code>:branch</code> let <code>maximum_coverage_drop</code> compare against the median of the recorded history, or against the newest recorded run on the current git branch, instead of against whatever ran most recently, so one run that dipped for an unrelated reason cannot quietly become the baseline the next run is judged against. And the history rides into coverage.json (and the HTML report's embedded data) as an optional top-level <code>history</code> array under schema 1.2, so other tools can draw the trend from the report artifacts. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1267">#1267</a>.</p>
</li>
<li>
<p>Coverage can be measured in production to find dead code. <code>require "simplecov/production"</code> loads a standalone runtime (none of the reporting machinery, no formatters, no at-exit report) that is a no-op until <code>SimpleCov::Production.start</code> is called explicitly: it measures <code>:oneshot_lines</code> coverage, whose report-first-hit-only semantics are what make the overhead viable on live traffic, and a background thread drains the runtime's table every <code>flush_interval</code> into a pluggable sink instead of assuming one report per process at exit. Storage is the part a repository's coverage directory cannot be, so the sink is one <code>store(coverage)</code> method receiving root-relative paths mapped to line numbers: it must union-merge (each process holds only a slice), tolerate duplicates, and raise on failure, which makes the runtime keep the delta and retry, bounded by a configurable <code>max_buffered_lines</code> ceiling whose drops self-heal for still-running code because a drained line re-reports on its next execution. A locking single-file <code>FileSink</code> ships in the box; Redis or S3 implement the same method outside the gem. <code>sample_rate</code> duty-cycles measurement via <code>Coverage.suspend</code>/<code>resume</code> (rates below 1.0 need Ruby 3.2), a test suite's running Coverage always wins over <code>start</code>, forked workers re-<code>start</code> from the worker-boot hook and pick the inherited measurement back up, and configuration mistakes raise while environmental declines warn and no-op. Then <code>simplecov dead-code --production PATH</code> crosses the accumulated store with the test report, per line: run by both is normal, run in production but untested (<code>--untested-in-production</code>) is the highest-value place to add a test, tested but never run in production is possibly dead with only its own spec as a defender, and run by neither is dead. The default view prints the two deletion-candidate rows in the greppable <code>path:ranges</code> form, marks a file whose every relevant line skipped production as <code>(entire file)</code>, names the window the data spans because the window is the evidence, and <code>--json</code> emits every category as data. Documented in docs/Production.md. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1271">#1271</a>.</p>
</li>
<li>
<p>Production coverage reaches the reports. <code>production_coverage "/path/to/production.json"</code> names the store a <code>SimpleCov::Production</code> sink accumulated, and the bundled formatters cross it with the test coverage: the HTML report's file list gains a sortable "Last Run in Production" column (ascending floats the files production never touched, the deletion candidates, to the top), each source view marks the cross's two actionable cells (covered code production never ran gets a gray gutter stripe, missed code production did run gets a teal stripe and a "runs in production" badge), the file header summarizes the ran share with the last-run date, and the legend explains both exactly when the section is present. With <code>simplecov serve</code> that report is a browsable production-coverage web UI. <code>coverage.json</code> carries the same data as an optional <code>production</code> section (the window plus per-file lines and <code>last_seen</code> stamps) under schema 1.3, additive as usual, so downstream tools get the cross as data. Backing both, the bundled <code>FileSink</code> now stamps each file with the last drain that carried it (<code>last_seen</code>, optional on read so v1 stores and remote sinks that only fill the documented shape keep working, and honest recency because oneshot's clear-on-drain makes still-running code re-report every interval), and the runtime adds a fresh random share of <code>flush_jitter</code> (default a tenth of <code>flush_interval</code>) to every wait, so a fleet of workers booted together drifts apart instead of contending on the shared sink at the same instant forever. An unreadable store warns and the report generates without the section, because a missing night of production data should not fail the suite that measured the tests. <code>simplecov dead-code</code> reads the same stamps: rows gain a <code>(last run 2026-08-03)</code> annotation dating the store's last sighting of the file (on a dead or possibly dead row that means other lines of the file ran then, and no date means the window never saw the file at all), <code>--json</code> entries carry the full stamp as <code>last_seen</code>, and rows from a stamp-less store print bare, exactly as before. The setting is also the CLI's default: <code>dead-code</code> fills in <code>--production</code> from the <code>production_coverage</code> a project's <code>.simplecov</code> configures, the way <code>ratchet</code> reads <code>baseline_file</code>, so the configuration names the store once and everything that crosses reads it from there.</p>
</li>
<li>
<p><code>deprecations :raise</code> turns every deprecated API into a <code>SimpleCov::ConfigurationError</code> instead of a warning, so a project that has migrated can guard in CI against old spellings creeping back, and early adopters can hold themselves to the current surface as the configuration DSL evolves along its roadmap. The default stays <code>deprecations :warn</code>, the error names the replacement the way the warning does, and there is deliberately no silencing mode, because a deprecation you cannot see is a migration you never make.</p>
</li>
<li>
<p>Threshold scope is now a uniform <code>per:</code> argument on the <code>coverage</code> block's verbs, instead of being baked into method names. <code>minimum 80, per: :file</code> sets the per-file default, <code>minimum 100, per: "app/x.rb"</code> (or a Regexp) overrides it for matching files, and <code>minimum 95, per: group("Models")</code> sets a group minimum, with <code>maximum_missed</code> taking the same targets for its per-file cap. One construct replaces three encodings (the bare verb, the <code>_per_file</code> / <code>_per_group</code> suffixes, and the <code>only:</code> keyword), so any future threshold verb gets every scope by composition rather than by minting new names. The suffixed forms (<code>minimum_per_file</code>, <code>minimum_per_group</code>, <code>maximum_missed_per_file</code>, and the flat <code>SimpleCov.maximum_missed_per_file</code> setter) are deprecated: they keep working and warn with the exact <code>per:</code> replacement built from their own arguments, and the older <code>minimum_coverage_by_file</code> / <code>minimum_coverage_by_group</code> deprecation messages now suggest the <code>per:</code> grammar directly instead of the intermediate spelling. A scope the enforcement cannot check yet is refused loudly rather than silently stored, which today means <code>maximum_missed</code> rejects <code>per: group(...)</code>. The wider plan this is the first step of, covering the remaining matrix cells, the <code>:eval</code> pseudo-criterion, baseline unification, and the eventual single-surface 2.0 configuration, is written down in <a href="https://github.com/simplecov-ruby/simplecov/blob/HEAD/docs/Roadmap.md">https://github.com/simplecov-ruby/simplecov/blob/HEAD/docs/Roadmap.md</a>.</p>
</li>
<li>
<p><code>SimpleCov::Formatter::BaselineFormatter</code> auto-ratchets the per-file baseline at the end of every run, for teams that want floors to tighten continuously instead of by deliberate <code>simplecov ratchet</code> invocations. The semantics are exactly the CLI's (floors only tighten, regressed files keep the floors they are below and are named in the status line, deleted files are pruned, new files never get an entry), the file is rewritten only when a floor actually moved so an unchanged run leaves the working tree clean, and the exit checks still judge the run against the floors as they were when it started, which ratcheting cannot flip since it never loosens. See <a href="https://redirect.github.com/simplecov-ruby/simplecov/issues/1268">#1268</a>.</p>
</li>
<li>
<p><code>simplecov version</code> (also <code>--version</code> and <code>-v</code>) prints the installed gem version, so a bug report can name the release it came from without a trip through <code>gem list</code>. It sits in the usage document like every other command, so the shell completions and the man page carry it too.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/simpleco...
_Description has been truncated_
You can view, comment on, or merge this pull request online at:
https://github.com/openstreetmap/openstreetmap-website/pull/7377
-- Commit Summary --
* Bump the dependencies group with 7 updates
-- File Changes --
M Gemfile.lock (23)
-- Patch Links --
https://github.com/openstreetmap/openstreetmap-website/pull/7377.patch
https://github.com/openstreetmap/openstreetmap-website/pull/7377.diff
--
Reply to this email directly or view it on GitHub:
https://github.com/openstreetmap/openstreetmap-website/pull/7377
You are receiving this because you are subscribed to this thread.
Message ID: <openstreetmap/openstreetmap-website/pull/7377 at github.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstreetmap.org/pipermail/rails-dev/attachments/20260909/cf6255f7/attachment-0001.htm>
More information about the rails-dev
mailing list