Skip to content

Add ruby4.0 to unit tests#855

Draft
SB-khushbum wants to merge 4 commits intonextfrom
khushbu/PLAT-15923-add-ruby4.0-unit-tests
Draft

Add ruby4.0 to unit tests#855
SB-khushbum wants to merge 4 commits intonextfrom
khushbu/PLAT-15923-add-ruby4.0-unit-tests

Conversation

@SB-khushbum
Copy link
Copy Markdown

Goal

Add Ruby 4.0 support to the bugsnag-ruby by updating dependencies and test configurations to ensure compatibility with the latest Ruby version.

Design

  • Added ostruct gem for Ruby 4.0+
  • Added Ruby 4.0 to the GitHub Actions test matrix to run unit tests against the new Ruby version
  • Updated stack trace frame count assertions in tests to account for potential differences in exception handling between Ruby versions
  • Added necessary gems for Ruby 4.0 compatibility in specs fixtures

Changeset

  • Added ostruct gem for Ruby 4.0+ (not shipped by default in Ruby 4+)
  • Updated .github/workflows/test-package.yml to include Ruby 4.0 in the test matrix
  • Modified spec/fixtures/apps/*/Gemfile to conditionally specify logger versions based on Ruby version
  • Updated spec/report_spec.rb to allow a range of bugsnag frames (5-6) for stack trace compatibility

Testing

  • Verified logger gem version compatibility across Ruby versions
  • Verified ostruct gem is available for Ruby 4.0+
  • Tested stack trace generation with updated frame count assertions
  • All existing unit tests pass with Ruby 4.0 and all other supported Ruby versions

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the bugsnag-ruby test and dependency setup to run unit/integration specs on Ruby 4.0, including tweaks to fixtures and spec assertions to account for Ruby/Bundler behavior changes.

Changes:

  • Add Ruby 4.0 to the GitHub Actions test matrix and adjust dependency installation steps for newer Bundler behavior.
  • Add ostruct (and related fixture dependencies) for Ruby 4.0+ compatibility in the main Gemfile and fixture app Gemfiles.
  • Update specs to tolerate minor Ruby-version differences (e.g., stacktrace frame count) and to handle Bundler env isolation changes.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
spec/report_spec.rb Loosens a stacktrace-frame assertion to accommodate Ruby version differences.
spec/integrations/logger_spec.rb Updates fixture app/script execution to support newer Bundler env methods and install flows.
spec/fixtures/apps/rails-no-config/Gemfile Adjusts fixture dependencies for Ruby 4.0+ (logger/bigdecimal/ostruct/etc.).
spec/fixtures/apps/rails-invalid-initializer-config/Gemfile Same as above for the invalid-initializer fixture.
Gemfile Adds ostruct for Ruby 4.0+ in the dev/test dependency set.
CHANGELOG.md Notes the CI matrix enhancement (currently added without a version header).
.github/workflows/test-package.yml Adds Ruby 4.0 to CI matrix and splits bundler install behavior by Ruby version.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +148 to +151
# Run Ruby script with environment variables
# Quote environment variable values to handle spaces and special characters
env_str = @env.map { |k, v| "#{k}='#{v}'" }.join(' ')
IO.popen("#{env_str} bundle exec ruby #{name}.rb 2>&1") do |io|
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_script builds a shell command string from @env and name and passes it to IO.popen, which re-introduces shell parsing/quoting issues (and potential command injection if any value contains quotes/whitespace). Prefer the array form of IO.popen with an env hash (as previously used) so Ruby bypasses the shell and handles escaping safely.

Suggested change
# Run Ruby script with environment variables
# Quote environment variable values to handle spaces and special characters
env_str = @env.map { |k, v| "#{k}='#{v}'" }.join(' ')
IO.popen("#{env_str} bundle exec ruby #{name}.rb 2>&1") do |io|
# Run Ruby script with environment variables, avoiding shell interpolation
# Use the env-hash + array form so Ruby bypasses the shell and handles escaping
IO.popen(@env, ['bundle', 'exec', 'ruby', "#{name}.rb"], err: [:child, :out]) do |io|

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +77
pid = Process.spawn(@env, 'bundle exec rackup config.ru',
out: out_writer.fileno,
err: out_writer.fileno)
sleep(2)
Process.kill('TERM', pid)
end
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After Process.kill('TERM', pid) the code never waits for the rackup process to exit. This can leave a zombie process and/or cause flaky specs due to lingering servers/locked resources. Consider waiting on the PID (optionally with a timeout and fallback SIGKILL) after sending TERM.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
### Enhancements

* Add Ruby 4.0 to the unit test matrix for CI
| [PLAT-15923](https://smartbear.atlassian.net/browse/PLAT-15923)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog entry is added as a top-level "### Enhancements" section without a version heading, which breaks the existing format where entries are grouped under ## vX.Y.Z (date) sections. Consider adding this bullet under the appropriate release section or introducing a clearly-labeled unreleased section (consistent with the project's changelog conventions).

Copilot uses AI. Check for mistakes.
Gemfile Outdated
Comment on lines +78 to +79
if ruby_version >= Gem::Version.new("4.0") # not shipped by default in Ruby 4+
gem 'ostruct'
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces the only double-quoted version string in the Gemfile (elsewhere uses single quotes) and also leaves trailing whitespace on the gem 'ostruct' line. Consider switching to single quotes and removing the trailing whitespace for consistency.

Suggested change
if ruby_version >= Gem::Version.new("4.0") # not shipped by default in Ruby 4+
gem 'ostruct'
if ruby_version >= Gem::Version.new('4.0') # not shipped by default in Ruby 4+
gem 'ostruct'

Copilot uses AI. Check for mistakes.
# - Report.generate_exceptions_list | raw_exceptions.map
# - Report.generate_exceptions_list | raw_exceptions.map | block
expect(bugsnag_count).to eq(6)
expect(bugsnag_count).to be_between(5, 6).inclusive
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace after .inclusive can cause noisy diffs and may be flagged by editors/linters. Consider removing the trailing space.

Suggested change
expect(bugsnag_count).to be_between(5, 6).inclusive
expect(bugsnag_count).to be_between(5, 6).inclusive

Copilot uses AI. Check for mistakes.
else
gem 'logger', '>= 1.7', '< 2.0'
gem 'bigdecimal', '>= 4.0.0', '< 5.0.0'
gem 'ostruct'
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is trailing whitespace after gem 'ostruct', which can lead to noisy diffs and editor/linter warnings. Consider removing the trailing space.

Suggested change
gem 'ostruct'
gem 'ostruct'

Copilot uses AI. Check for mistakes.
else
gem 'logger', '>= 1.7', '< 2.0'
gem 'bigdecimal', '>= 4.0.0', '< 5.0.0'
gem 'ostruct'
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is trailing whitespace after gem 'ostruct', which can lead to noisy diffs and editor/linter warnings. Consider removing the trailing space.

Suggested change
gem 'ostruct'
gem 'ostruct'

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +77 to +83
begin
# Wait up to 5 seconds for the process to exit
Timeout.timeout(5) { Process.waitpid(pid) }
rescue Timeout::Error
# If still running, force kill
Process.kill('KILL', pid) rescue nil
Process.waitpid(pid) rescue nil
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeout.timeout is used here, but this spec file (and spec/spec_helper.rb) never requires the timeout stdlib, so this will raise NameError: uninitialized constant Timeout on a clean Ruby process. Add require 'timeout' (ideally near the top of this spec) or avoid Timeout entirely.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +48
def execute_bundle_and_app(name, out_writer)
# Handle Bundler install for different Ruby versions
ruby_version = Gem::Version.new(RUBY_VERSION.dup)

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute_bundle_and_app accepts name but never uses it. Either remove the parameter to avoid confusion, or use it if there’s fixture-specific behavior intended.

Copilot uses AI. Check for mistakes.
Comment on lines 21 to +27
Dir.chdir(File.join(File.dirname(__FILE__), "../fixtures/apps/#{name}")) do
Bundler.with_clean_env do
pid = Process.spawn('bundle install',
out: out_writer.fileno,
err: out_writer.fileno)
Process.waitpid(pid, 0)
pid = Process.spawn(@env, 'bundle exec rackup config.ru',
out: out_writer.fileno,
err: out_writer.fileno)
sleep(2)
Process.kill(1, pid)
# Determine which Bundler env method to use based on availability
# Ruby 4.0+ uses with_unbundled_env, Ruby 2-3.x uses with_clean_env, Ruby 1.9.2 has no env isolation
if Bundler.respond_to?(:with_unbundled_env)
Bundler.with_unbundled_env do
execute_bundle_and_app(name, out_writer)
end
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ruby 4.0 runs of this spec will still execute the rails-initializer-config fixture (see below), but spec/fixtures/apps/rails-initializer-config/Gemfile still pins logger 1.6.5/bigdecimal 3.1.9 for Ruby >= 3.4. That is inconsistent with the other updated fixtures and is likely to break bundler resolution on Ruby 4.0; update that fixture Gemfile similarly.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to 8
### Enhancements

* Add Ruby 4.0 to the unit test matrix for CI
| [PLAT-15923](https://smartbear.atlassian.net/browse/PLAT-15923)

## v6.29.0 (21 January 2026)
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new entry is not under a version heading, whereas the rest of the changelog is organized by ## vX.Y.Z (date) sections. Consider adding a new version section (or an explicit “Unreleased”) and placing this bullet under it to keep the changelog structure consistent.

Copilot uses AI. Check for mistakes.
# For Ruby < 3.4, use the legacy flags which are still supported
- name: Install dependencies (Ruby < 3.4)
if: ${{ !startsWith(matrix.ruby-version, '3.4') && !startsWith(matrix.ruby-version, '4.') }}
run: bundle install --with "${{ matrix.optional-groups }}" --binstubs
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be trailing whitespace at the end of this line. Please remove it to avoid whitespace-only diffs and potential YAML lint failures.

Suggested change
run: bundle install --with "${{ matrix.optional-groups }}" --binstubs
run: bundle install --with "${{ matrix.optional-groups }}" --binstubs

Copilot uses AI. Check for mistakes.
@SB-khushbum SB-khushbum self-assigned this Apr 3, 2026
@SB-khushbum SB-khushbum changed the title Khushbu/plat 15923 add ruby4.0 unit tests Add ruby4.0 to unit tests Apr 3, 2026
@SB-khushbum SB-khushbum changed the base branch from master to next April 3, 2026 13:28
@SB-khushbum SB-khushbum requested a review from Copilot April 3, 2026 13:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +76 to +80
Process.kill('TERM', pid)
begin
# Wait up to 5 seconds for the process to exit
Timeout.timeout(5) { Process.waitpid(pid) }
rescue Timeout::Error
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeout.timeout is used here but this spec file does not require 'timeout'. Without requiring the stdlib, Ruby will raise NameError: uninitialized constant Timeout when this path runs. Add require 'timeout' near the top (or load it via spec_helper) before referencing Timeout.

Copilot uses AI. Check for mistakes.
Sign up for free to 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