Skip to content

fix(rspec): scope everything the gem defines under RSpec::Trunk - #1211

Merged
trunk-io[bot] merged 2 commits into
mainfrom
dylan/rspec-namespace-globals
Sep 28, 2026
Merged

trunk-io[bot] merged 2 commits into
mainfrom
dylan/rspec-namespace-globals

Conversation

@dfrankland

Copy link
Copy Markdown
Member

Problem

rspec_trunk_flaky_tests runs inside other people's test suites, but it defined a lot in the global namespace:

  • Native extension: top-level classes Status, TestReport, IsQuarantinedResult, CIInfo, CIPlatform, BranchClass, plus a global env_parse function.
  • trunk_spec_helper.rb: eleven top-level methods (escape, trunk_disabled, strip_ansi_codes, ...), which become private methods on every object; top-level constants (ANSI_ESCAPE_PATTERN, PlainColorizer, TrunkAnalyticsListener); three $globals; and colorize/red/green/yellow patched onto String.

These break real apps:

  • An app with a Status class, e.g. a Rails model, fails with superclass mismatch for class Status, whichever of the two loads first.
  • The String patch breaks the colorize gem regardless of load order: "hi".colorize(:red) becomes "\e[redmhi\e[0m".
  • A user's own top-level escape silently replaces the gem's. The gem uses escape to build the file and classname it sends to Trunk, which feed the quarantine lookup.

Changes

  • Namespace: everything now lives under RSpec::Trunk. The native classes are defined under it (magnus::wrap(class = "RSpec::Trunk::..."), and ruby_init in context and test_report now takes the namespace), and env_parse became RSpec::Trunk.env_parse.
  • Colors: RSpec::Trunk::Colors replaces the String patch.
  • State: the three globals became one RSpec::Trunk.current_run, holding the report and the warn-once flags. It's only created when Trunk is enabled; before, a TestReport was built at require time even when Trunk was off.
  • Example patch: RSpec::Core::Example is extended with prepend plus super instead of an alias chain, and only when Trunk is enabled. It adds one public method, trunk_id.
  • Metadata keys: the keys the gem sets are now trunk_-prefixed (:trunk_quarantined_exception, :trunk_attempt_number, :trunk_is_description_generated). The old unprefixed keys are still written and marked deprecated in RSpec::Trunk::DEPRECATED_METADATA_KEYS.
  • README: "How Quarantining Works" now describes behavior instead of naming internal classes.

Compatibility

The documented setup is unchanged: gem "rspec_trunk_flaky_tests", require "trunk_spec_helper", and the env vars listed in the docs. I checked this against https://docs.trunk.io/flaky-tests/get-started/frameworks/rspec. Anyone who followed the docs upgrades without edits.

Two things do change:

  • Undocumented internals moved. Code that used TestReport, TrunkAnalyticsListener, env_parse, $test_report, "x".red and so on directly must use the RSpec::Trunk names. For a 0.x gem this suggests a minor bump (0.16.0), with the renames listed in the release notes. No compatibility shims.
  • Enablement is decided once, at load. DISABLE_RSPEC_TRUNK_FLAKY_TESTS, TRUNK_ORG_URL_SLUG and TRUNK_API_TOKEN are read when trunk_spec_helper loads. Before, they were also rechecked on every failure, so env vars changed after the require no longer have any effect. The docs already say to set them before running.

Keeping it this way

  • test/namespace_spec.rb loads the gem, with Trunk enabled, into a fresh Ruby process and compares everything defined before and after. It fails if anything besides RSpec::Trunk appears. It covers the native extension and patches to core classes, which RuboCop can't see.
  • .rubocop.yml no longer exempts $test_report from Style/GlobalVars, and turns on Style/TopLevelMethodDefinition.

Testing

  • bundle exec rake test: 23 examples, 0 failures. This includes the new namespace_spec.rb and metadata_spec.rb.
  • cargo fmt --check is clean. RuboCop reports nothing new; the only offense is set_exception, which the existing trunk-ignore already covers.

🤖 Generated with Claude Code

The gem is loaded into other people's test suites but defined things in the
global namespace: top-level classes from the native extension (Status,
TestReport, CIInfo, ...), a global env_parse function, eleven top-level
methods, $globals, and color methods patched onto String. These collide with
app code (a Status model fails with "superclass mismatch") and with gems like
colorize.

Everything now lives under RSpec::Trunk. The per-run state is a single
RSpec::Trunk.current_run, created only when Trunk is enabled. The Example
patch is a prepended module calling super instead of an alias chain.
Metadata keys the gem sets are trunk_-prefixed, with the old unprefixed
names still written and deprecated.

The documented setup (the gem, require "trunk_spec_helper", env vars) is
unchanged. Whether Trunk is enabled is now decided once, when the helper
loads, rather than rechecked on every failure.

test/namespace_spec.rb loads the gem in a fresh process and fails if anything
is defined outside RSpec::Trunk; RuboCop now enforces Style/GlobalVars with no
exceptions and Style/TopLevelMethodDefinition.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@codecov-commenter

codecov-commenter commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.96%. Comparing base (7864bdc) to head (0722bc6).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1211      +/-   ##
==========================================
+ Coverage   83.74%   83.96%   +0.21%     
==========================================
  Files          74       74              
  Lines       17745    17745              
==========================================
+ Hits        14860    14899      +39     
+ Misses       2885     2846      -39     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…refactor

check_quarantine and add_test_case carry over the trunk-ignore comments from
the methods they replace (handle_quarantine_check and add_test_case), which
also suppressed Metrics/CyclomaticComplexity.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@trunk-staging-io

trunk-staging-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
pending_quarantine_test should be quarantined when run with variant A test marked as pending was expected to fail but unexpectedly passed. Logs ↗︎
variant_quarantine_test should be quarantined when run with variant A test expected the sum of 2 + 2 to be 5, but it was actually 4, indicating a failed assertion. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@trunk-io

trunk-io Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
pending_quarantine_test should be quarantined when run with variant A test marked as pending was expected to fail but unexpectedly passed. Logs ↗︎
variant_quarantine_test should be quarantined when run with variant A test expected the sum of 2 + 2 to be 5, but it was actually 4, indicating an incorrect expected value or failing logic. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@acatxnamedvirtue

Copy link
Copy Markdown
Contributor

nice work fixing those "naughty" things

@trunk-io
trunk-io Bot merged commit 209c229 into main Sep 28, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants