From 71808579f215499bee692aebfa7991a540aef93c Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 14 Oct 2025 07:33:42 -0400 Subject: [PATCH 1/6] Add `view_component` integration for `Datadog::Tracing` * `ViewComponent` supports instrumentation through `ActiveSupport` notifications, and having the ability to trace a ViewComponent using Datadog's APM provides a similar level of debugging ease that tracing `ActionView` template and partial rendering provides * This tracing component was based on `Datadog::Tracing::Contrib::ActionView`, with some key differences: * There is only one action available for instrumentation: `render` * ViewComponent is technically its own component, not part of Rails itself * Therefore, it uses `Contrib::Integration#auto_instrument?` rather than checking the Railtie * The `span.resource` is the name of the component (`MyComponent`), not its identifier (`my_component.rb`), for a better user experience * Added tests, but need to update the Matrixfile and appraisals --- .../view_component/configuration/settings.rb | 43 ++++++++++++ .../tracing/contrib/view_component/event.rb | 35 ++++++++++ .../tracing/contrib/view_component/events.rb | 32 +++++++++ .../contrib/view_component/events/render.rb | 52 +++++++++++++++ .../tracing/contrib/view_component/ext.rb | 23 +++++++ .../contrib/view_component/integration.rb | 48 ++++++++++++++ .../tracing/contrib/view_component/patcher.rb | 34 ++++++++++ .../tracing/contrib/view_component/utils.rb | 36 ++++++++++ .../view_component/integration_spec.rb | 66 +++++++++++++++++++ .../contrib/view_component/utils_spec.rb | 49 ++++++++++++++ 10 files changed, 418 insertions(+) create mode 100644 lib/datadog/tracing/contrib/view_component/configuration/settings.rb create mode 100644 lib/datadog/tracing/contrib/view_component/event.rb create mode 100644 lib/datadog/tracing/contrib/view_component/events.rb create mode 100644 lib/datadog/tracing/contrib/view_component/events/render.rb create mode 100644 lib/datadog/tracing/contrib/view_component/ext.rb create mode 100644 lib/datadog/tracing/contrib/view_component/integration.rb create mode 100644 lib/datadog/tracing/contrib/view_component/patcher.rb create mode 100644 lib/datadog/tracing/contrib/view_component/utils.rb create mode 100644 spec/datadog/tracing/contrib/view_component/integration_spec.rb create mode 100644 spec/datadog/tracing/contrib/view_component/utils_spec.rb diff --git a/lib/datadog/tracing/contrib/view_component/configuration/settings.rb b/lib/datadog/tracing/contrib/view_component/configuration/settings.rb new file mode 100644 index 00000000000..01b1feefff0 --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/configuration/settings.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'datadog/tracing/configuration/settings' +require_relative '../ext' + +module Datadog + module Tracing + module Contrib + module ViewComponent + module Configuration + # Custom settings for the ViewComponent integration + # @public_api + class Settings < Contrib::Configuration::Settings + option :enabled do |o| + o.type :bool + o.env Ext::ENV_ENABLED + o.default true + end + + # @!visibility private + option :analytics_enabled do |o| + o.type :bool + o.env Ext::ENV_ANALYTICS_ENABLED + o.default false + end + + option :analytics_sample_rate do |o| + o.type :float + o.env Ext::ENV_ANALYTICS_SAMPLE_RATE + o.default 1.0 + end + + option :service_name + option :component_base_path do |o| + o.type :string + o.default 'components/' + end + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/event.rb b/lib/datadog/tracing/contrib/view_component/event.rb new file mode 100644 index 00000000000..104df24c701 --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/event.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'datadog/tracing/contrib/active_support/notifications/event' + +module Datadog + module Tracing + module Contrib + module ViewComponent + # Defines basic behavior for an ViewComponent event. + module Event + def self.included(base) + base.include(ActiveSupport::Notifications::Event) + base.extend(ClassMethods) + end + + # Class methods for ViewComponent events. + module ClassMethods + def configuration + Datadog.configuration.tracing[:view_component] + end + + def record_exception(span, payload) + if payload[:exception_object] + span.set_error(payload[:exception_object]) + elsif payload[:exception] + # Fallback for ActiveSupport < 5.0 + span.set_error(payload[:exception]) + end + end + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/events.rb b/lib/datadog/tracing/contrib/view_component/events.rb new file mode 100644 index 00000000000..e8d83e64f2c --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/events.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require_relative 'events/render' + +module Datadog + module Tracing + module Contrib + module ViewComponent + # Defines collection of instrumented ViewComponent events + module Events + ALL = [ + Events::Render + ].freeze + + module_function + + def all + self::ALL + end + + def subscriptions + all.collect(&:subscriptions).collect(&:to_a).flatten + end + + def subscribe! + all.each(&:subscribe!) + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/events/render.rb b/lib/datadog/tracing/contrib/view_component/events/render.rb new file mode 100644 index 00000000000..73acea32fc4 --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/events/render.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'datadog/tracing' +require 'datadog/tracing/metadata/ext' +require 'datadog/tracing/analytics' +require_relative '../ext' +require_relative '../event' + +module Datadog + module Tracing + module Contrib + module ViewComponent + module Events + # Defines instrumentation for render.view_component event + module Render + include ViewComponent::Event + + EVENT_NAME = 'render.view_component' + + module_function + + def event_name + self::EVENT_NAME + end + + def span_name + Ext::SPAN_RENDER + end + + def on_start(span, _event, _id, payload) + span.service = configuration[:service_name] if configuration[:service_name] + span.type = Tracing::Metadata::Ext::HTTP::TYPE_TEMPLATE + + span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT) + span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_RENDER) + + span.resource = payload[:name] + span.set_tag(Ext::TAG_COMPONENT_NAME, payload[:name]) + + if (identifier = Utils.normalize_component_identifier(payload[:identifier])) + span.set_tag(Ext::TAG_COMPONENT_IDENTIFIER, identifier) + end + + # Measure service stats + Contrib::Analytics.set_measured(span) + end + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/ext.rb b/lib/datadog/tracing/contrib/view_component/ext.rb new file mode 100644 index 00000000000..111ea93a71b --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/ext.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Datadog + module Tracing + module Contrib + module ViewComponent + # ViewComponent integration constants + # @public_api Changing resource names, tag names, or environment variables creates breaking changes. + module Ext + ENV_ENABLED = 'DD_TRACE_VIEW_COMPONENT_ENABLED' + # @!visibility private + ENV_ANALYTICS_ENABLED = 'DD_TRACE_VIEW_COMPONENT_ANALYTICS_ENABLED' + ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_VIEW_COMPONENT_ANALYTICS_SAMPLE_RATE' + SPAN_RENDER = 'view_component.render' + TAG_COMPONENT = 'view_component' + TAG_OPERATION_RENDER = 'render' + TAG_COMPONENT_IDENTIFIER = 'view_component.component_identifier' + TAG_COMPONENT_NAME = 'view_component.component_name' + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/integration.rb b/lib/datadog/tracing/contrib/view_component/integration.rb new file mode 100644 index 00000000000..6a82a457cbc --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/integration.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative 'configuration/settings' +require_relative 'patcher' +require 'datadog/tracing/contrib/integration' +require 'datadog/tracing/contrib/rails/ext' +require 'datadog/core/contrib/rails/utils' + +module Datadog + module Tracing + module Contrib + module ViewComponent + # Describes the ViewComponent integration + class Integration + include Contrib::Integration + + MINIMUM_VERSION = "2.34.0" + + # @public_api Changing the integration name or integration options can cause breaking changes + register_as :view_component, auto_patch: false + def self.gem_name + 'view_component' + end + + def self.version + Gem.loaded_specs['view_component']&.version + end + + def self.loaded? + !defined?(::ViewComponent).nil? + end + + def self.compatible? + super && version >= MINIMUM_VERSION + end + + def new_configuration + Configuration::Settings.new + end + + def patcher + ViewComponent::Patcher + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/patcher.rb b/lib/datadog/tracing/contrib/view_component/patcher.rb new file mode 100644 index 00000000000..2026876a472 --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/patcher.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'datadog/core' +require 'datadog/tracing/contrib/patcher' +require_relative 'events' +require_relative 'ext' +require_relative 'utils' + +module Datadog + module Tracing + module Contrib + module ViewComponent + # Patcher enables patching of ViewComponent module. + module Patcher + include Contrib::Patcher + + module_function + + def target_version + Integration.version + end + + def patch + patch_renderer + end + + def patch_renderer + Events.subscribe! + end + end + end + end + end +end diff --git a/lib/datadog/tracing/contrib/view_component/utils.rb b/lib/datadog/tracing/contrib/view_component/utils.rb new file mode 100644 index 00000000000..a04b21ef4bb --- /dev/null +++ b/lib/datadog/tracing/contrib/view_component/utils.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'datadog/tracing/contrib/analytics' + +module Datadog + module Tracing + module Contrib + module ViewComponent + # common utilities for ViewComponent + module Utils + module_function + + # in ViewComponent the component identifier includes the component full path + # and it's better to avoid storing such information. This method + # returns the relative path from `components/` or the component identifier + # if a `components/` folder is not in the component full path. A wrong + # usage ensures that this method will not crash the tracing system. + def normalize_component_identifier(identifier) + return if identifier.nil? + + base_path = Datadog.configuration.tracing[:view_component][:component_base_path] + sections_view = identifier.split(base_path) + + if sections_view.length == 1 + identifier.split('/')[-1] + else + sections_view[-1] + end + rescue + identifier.to_s + end + end + end + end + end +end diff --git a/spec/datadog/tracing/contrib/view_component/integration_spec.rb b/spec/datadog/tracing/contrib/view_component/integration_spec.rb new file mode 100644 index 00000000000..06fdd2b31a6 --- /dev/null +++ b/spec/datadog/tracing/contrib/view_component/integration_spec.rb @@ -0,0 +1,66 @@ +require 'datadog/tracing/contrib/support/spec_helper' +require 'datadog/tracing/contrib/auto_instrument_examples' + +require 'datadog/tracing/contrib/view_component/integration' + +RSpec.describe Datadog::Tracing::Contrib::ViewComponent::Integration do + let(:integration) { described_class.new(:view_component) } + + describe '.version' do + subject(:version) { described_class.version } + + context 'when the "view_component" gem is loaded' do + include_context 'loaded gems', view_component: described_class::MINIMUM_VERSION + it { is_expected.to be_a_kind_of(Gem::Version) } + end + end + + describe '.loaded?' do + subject(:loaded?) { described_class.loaded? } + + context 'when ViewComponent is defined' do + before { stub_const('ViewComponent', Class.new) } + + it { is_expected.to be true } + end + + context 'when ViewComponent is not defined' do + before { hide_const('ViewComponent') } + + it { is_expected.to be false } + end + end + + describe '.compatible?' do + subject(:compatible?) { described_class.compatible? } + + context 'when "view_component" gem is loaded with a version' do + context 'that is less than the minimum' do + include_context 'loaded gems', view_component: decrement_gem_version(described_class::MINIMUM_VERSION) + it { is_expected.to be false } + end + + context 'that meets the minimum version' do + include_context 'loaded gems', view_component: described_class::MINIMUM_VERSION + it { is_expected.to be true } + end + end + + context 'when gem is not loaded' do + include_context 'loaded gems', actionpack: nil, view_component: nil + it { is_expected.to be false } + end + end + + describe '#default_configuration' do + subject(:default_configuration) { integration.default_configuration } + + it { is_expected.to be_a_kind_of(Datadog::Tracing::Contrib::ViewComponent::Configuration::Settings) } + end + + describe '#patcher' do + subject(:patcher) { integration.patcher } + + it { is_expected.to be Datadog::Tracing::Contrib::ViewComponent::Patcher } + end +end diff --git a/spec/datadog/tracing/contrib/view_component/utils_spec.rb b/spec/datadog/tracing/contrib/view_component/utils_spec.rb new file mode 100644 index 00000000000..62864712803 --- /dev/null +++ b/spec/datadog/tracing/contrib/view_component/utils_spec.rb @@ -0,0 +1,49 @@ +RSpec.describe Datadog::Tracing::Contrib::ViewComponent::Utils do + describe '#normalize_component_identifier' do + subject(:normalize_component_identifier) { described_class.normalize_component_identifier(name) } + + after { Datadog.configuration.tracing[:view_component].reset! } + + context 'with component identifer' do + let(:name) { '/rails/app/components/welcome/my_component.rb' } + + it { is_expected.to eq('welcome/my_component.rb') } + end + + context 'with nil identifer' do + let(:name) { nil } + + it { is_expected.to be(nil) } + end + + context 'with file name only' do + let(:name) { 'my_component.rb' } + + it { is_expected.to eq('my_component.rb') } + end + + context 'with identifer outside of `components/` directory' do + let(:name) { '/rails/app/other/welcome/my_component.rb' } + + it { is_expected.to eq('my_component.rb') } + end + + context 'with a custom component base path' do + before { Datadog.configuration.tracing[:view_component][:component_base_path] = 'custom/' } + + context 'with component outside of `components/` directory' do + let(:name) { '/rails/app/custom/welcome/my_component.rb' } + + it { is_expected.to eq('welcome/my_component.rb') } + end + end + + context 'with a non-string-like argument' do + let(:name) { :not_a_string } + + it 'stringifies arguments' do + is_expected.to eq('not_a_string') + end + end + end +end From 9a6ee4b45e65dc9040ed397f61ca9dad24fae289 Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 21 Oct 2025 23:29:13 -0400 Subject: [PATCH 2/6] Make `ViewComponent::Events::Render#event_name` configurable * Older versions of ViewComponent had a different notification name for ActiveSupport notifications, `!render.view_component` * See: https://github.com/ViewComponent/view_component/pull/1771 * To support this, there is a configuration flag, `:use_deprecated_instrumentation_name`, which mirrors the name of the configuration option within `ViewComponent` itself * If set to true, it changes the `event_name` for the `ViewComponent::Events::Render#event_name` to be `!render.view_component` --- .../tracing/contrib/view_component/configuration/settings.rb | 5 +++++ lib/datadog/tracing/contrib/view_component/events/render.rb | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/datadog/tracing/contrib/view_component/configuration/settings.rb b/lib/datadog/tracing/contrib/view_component/configuration/settings.rb index 01b1feefff0..6dad18ed7d4 100644 --- a/lib/datadog/tracing/contrib/view_component/configuration/settings.rb +++ b/lib/datadog/tracing/contrib/view_component/configuration/settings.rb @@ -35,6 +35,11 @@ class Settings < Contrib::Configuration::Settings o.type :string o.default 'components/' end + + option :use_deprecated_instrumentation_name do |o| + o.type :bool + o.default false + end end end end diff --git a/lib/datadog/tracing/contrib/view_component/events/render.rb b/lib/datadog/tracing/contrib/view_component/events/render.rb index 73acea32fc4..61cf4c298de 100644 --- a/lib/datadog/tracing/contrib/view_component/events/render.rb +++ b/lib/datadog/tracing/contrib/view_component/events/render.rb @@ -16,11 +16,13 @@ module Render include ViewComponent::Event EVENT_NAME = 'render.view_component' + DEPRECATED_EVENT_NAME = '!render.view_component' module_function def event_name - self::EVENT_NAME + return DEPRECATED_EVENT_NAME if configuration[:use_deprecated_instrumentation_name] + return EVENT_NAME end def span_name From 02a59d0beb60d9b17bd054842fb3d745bb550991 Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 14 Oct 2025 07:43:25 -0400 Subject: [PATCH 3/6] WIP: Add `view_component` build matricies in `appraisal` * I was not able to get the `docker compose` setup running on my machine due to the inability to pull the `ddapm-test-agent` * Therefore, I was not able to spool up containers for each version of Ruby to generate their `gemfiles/` * While I tested this locally with `ruby-3.3`, I did not commit the changes since I was not able to follow the containerized setup --- Matrixfile | 5 +++++ Rakefile | 3 ++- appraisal/jruby-9.2.rb | 1 + appraisal/jruby-9.3.rb | 1 + appraisal/jruby-9.4.rb | 1 + appraisal/ruby-2.5.rb | 1 + appraisal/ruby-2.6.rb | 1 + appraisal/ruby-2.7.rb | 1 + appraisal/ruby-3.0.rb | 1 + appraisal/ruby-3.1.rb | 1 + appraisal/ruby-3.2.rb | 1 + appraisal/ruby-3.3.rb | 1 + appraisal/ruby-3.4.rb | 1 + appraisal/ruby-3.5.rb | 1 + 14 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Matrixfile b/Matrixfile index 6a4bc6a4f74..6c2652b991d 100644 --- a/Matrixfile +++ b/Matrixfile @@ -293,6 +293,11 @@ 'redis-4' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', 'redis-3' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', }, + 'view_component' => { + 'view_component-min' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', + 'view_component-3' => '❌ 2.5 / ❌ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', + 'view_component-4' => '❌ 2.5 / ❌ 2.6 / ❌ 2.7 / ❌ 3.0 / ❌ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', + }, 'appsec:active_record' => { 'relational_db' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', }, diff --git a/Rakefile b/Rakefile index 4bf70667735..a7c29794dab 100644 --- a/Rakefile +++ b/Rakefile @@ -286,7 +286,8 @@ namespace :spec do :stripe, :sucker_punch, :suite, - :trilogy + :trilogy, + :view_component ].each do |contrib| desc '' # "Explicitly hiding from `rake -T`" RSpec::Core::RakeTask.new(contrib) do |t, args| diff --git a/appraisal/jruby-9.2.rb b/appraisal/jruby-9.2.rb index 68ef927cfd5..b9674b217c7 100644 --- a/appraisal/jruby-9.2.rb +++ b/appraisal/jruby-9.2.rb @@ -204,6 +204,7 @@ build_coverage_matrix('rest-client') build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) +build_coverage_matrix('view_component', (3..4), min: '2.34.0') # NOTE: JRuby bundler failed to install some dependencies https://github.com/ruby/psych/issues/700 # and it could be re-enabled when upstream fix the issue # build_coverage_matrix('devise', min: '3.2.1') diff --git a/appraisal/jruby-9.3.rb b/appraisal/jruby-9.3.rb index e6efd68e66e..7d3cb453071 100644 --- a/appraisal/jruby-9.3.rb +++ b/appraisal/jruby-9.3.rb @@ -177,6 +177,7 @@ build_coverage_matrix('rest-client') build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) +build_coverage_matrix('view_component', (3..4), min: '2.34.0') # NOTE: JRuby bundler failed to install some dependencies https://github.com/ruby/psych/issues/700 # and it could be re-enabled when upstream fix the issue # build_coverage_matrix('devise', min: '3.2.1') diff --git a/appraisal/jruby-9.4.rb b/appraisal/jruby-9.4.rb index a67c34b7670..1a670790625 100644 --- a/appraisal/jruby-9.4.rb +++ b/appraisal/jruby-9.4.rb @@ -82,6 +82,7 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') +build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'karafka-min' do gem 'karafka', '= 2.3.0' diff --git a/appraisal/ruby-2.5.rb b/appraisal/ruby-2.5.rb index 282bbd1066b..53786c63774 100644 --- a/appraisal/ruby-2.5.rb +++ b/appraisal/ruby-2.5.rb @@ -224,6 +224,7 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli') build_coverage_matrix('devise', min: '3.2.1', meta: { min: { 'bigdecimal' => '1.3.4' } }) +build_coverage_matrix('view_component', min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 5' diff --git a/appraisal/ruby-2.6.rb b/appraisal/ruby-2.6.rb index 94a0f71d5a4..74169527890 100644 --- a/appraisal/ruby-2.6.rb +++ b/appraisal/ruby-2.6.rb @@ -177,6 +177,7 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1', meta: { min: { 'bigdecimal' => '1.4.1' } }) +build_coverage_matrix('view_component', min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 6.0.0' diff --git a/appraisal/ruby-2.7.rb b/appraisal/ruby-2.7.rb index cfa083ac940..2ddceedd87a 100644 --- a/appraisal/ruby-2.7.rb +++ b/appraisal/ruby-2.7.rb @@ -178,6 +178,7 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 6.1.0' diff --git a/appraisal/ruby-3.0.rb b/appraisal/ruby-3.0.rb index c0e3ff9a208..a24d6606fef 100644 --- a/appraisal/ruby-3.0.rb +++ b/appraisal/ruby-3.0.rb @@ -98,6 +98,7 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'karafka-min' do gem 'karafka', '= 2.3.0' diff --git a/appraisal/ruby-3.1.rb b/appraisal/ruby-3.1.rb index 6269745e08a..6fad0cd2aa2 100644 --- a/appraisal/ruby-3.1.rb +++ b/appraisal/ruby-3.1.rb @@ -99,6 +99,7 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' diff --git a/appraisal/ruby-3.2.rb b/appraisal/ruby-3.2.rb index 0c65a83f0ec..087d2fc7f6c 100644 --- a/appraisal/ruby-3.2.rb +++ b/appraisal/ruby-3.2.rb @@ -144,6 +144,7 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' diff --git a/appraisal/ruby-3.3.rb b/appraisal/ruby-3.3.rb index cdeabe2e644..9b5975380e5 100644 --- a/appraisal/ruby-3.3.rb +++ b/appraisal/ruby-3.3.rb @@ -146,6 +146,7 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' diff --git a/appraisal/ruby-3.4.rb b/appraisal/ruby-3.4.rb index 92833c2f59e..cc422439f35 100644 --- a/appraisal/ruby-3.4.rb +++ b/appraisal/ruby-3.4.rb @@ -145,6 +145,7 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do # ActiveRecord locked because tests are failing with 7.1, which was attempted as a part of Ruby 3.4 testing in CI. diff --git a/appraisal/ruby-3.5.rb b/appraisal/ruby-3.5.rb index 6b0542ea9b7..26e615e4e4b 100644 --- a/appraisal/ruby-3.5.rb +++ b/appraisal/ruby-3.5.rb @@ -94,6 +94,7 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') +build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do # ActiveRecord locked because tests are failing with 7.1, which was attempted as a part of Ruby 3.4 testing in CI. From b5bcb5485e33085a0122b601665e53398a39a4ca Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 21 Oct 2025 22:28:12 -0400 Subject: [PATCH 4/6] WIP `DD_TRACE_VIEW_COMPONENT_ENABLED` to `supported-configurations` * Followed the documentation to add `DD_TRACE_VIEW_COMPONENT_ENABLED` to `supported-configurations.json`, then run the task to generate `lib/datadog/core/configuration/supported_configurations.rb` --- lib/datadog/core/configuration/supported_configurations.rb | 1 + supported-configurations.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/datadog/core/configuration/supported_configurations.rb b/lib/datadog/core/configuration/supported_configurations.rb index a2159507761..6e078da8d3a 100644 --- a/lib/datadog/core/configuration/supported_configurations.rb +++ b/lib/datadog/core/configuration/supported_configurations.rb @@ -304,6 +304,7 @@ module Configuration "DD_TRACE_TRILOGY_ENABLED" => {version: ["A"]}, "DD_TRACE_TRILOGY_PEER_SERVICE" => {version: ["A"]}, "DD_TRACE_TRILOGY_SERVICE_NAME" => {version: ["A"]}, + "DD_TRACE_VIEW_COMPONENT_ENABLED" => {version: ["A"]}, "DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH" => {version: ["A"]}, "DD_VERSION" => {version: ["A"]}, "OTEL_TRACES_SAMPLER_ARG" => {version: ["A"]}}.freeze diff --git a/supported-configurations.json b/supported-configurations.json index 25d1205804a..bdfa7b191be 100644 --- a/supported-configurations.json +++ b/supported-configurations.json @@ -892,6 +892,9 @@ "DD_TRACE_TRILOGY_SERVICE_NAME": { "version": ["A"] }, + "DD_TRACE_VIEW_COMPONENT_ENABLED": { + "version": ["A"] + }, "DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH": { "version": ["A"] }, From 6382468d803c0f9f8de205fc825335cbbdd8940f Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 21 Oct 2025 23:52:45 -0400 Subject: [PATCH 5/6] WIP: Prepare `appraisal` files for `view_component` integration tests * In order to write working integration tests for the major versions of ViewComponent that have instrumentation support, we need to use custom appraisal sets instead of `build_coverage_matrix`, since an ad-hoc Rails app needs to be spooled up, which includes `pg`, `rails`, and `sprockets < 4` for the max versions of Rails for `ViewComponent` `2.34.0 * I was not able to get the `docker compose` setup running on my machine due to the inability to pull the `ddapm-test-agent` * Therefore, I was not able to spool up containers for each version of Ruby to generate their `gemfiles/` * While I tested this locally with `ruby-3.3`, I did not commit the changes since I was not able to follow the containerized setup --- Matrixfile | 4 +- appraisal/jruby-9.2.rb | 18 ++++++- appraisal/jruby-9.3.rb | 18 ++++++- appraisal/jruby-9.4.rb | 18 ++++++- appraisal/ruby-2.5.rb | 9 +++- appraisal/ruby-2.6.rb | 9 +++- appraisal/ruby-2.7.rb | 18 ++++++- appraisal/ruby-3.0.rb | 18 ++++++- appraisal/ruby-3.1.rb | 18 ++++++- appraisal/ruby-3.2.rb | 18 ++++++- appraisal/ruby-3.3.rb | 18 ++++++- appraisal/ruby-3.4.rb | 19 ++++++- appraisal/ruby-3.5.rb | 18 ++++++- .../ruby_3.4_view_component_2.34.0.gemfile | 49 +++++++++++++++++++ .../ruby_3.4_view_component_3.23.2.gemfile | 48 ++++++++++++++++++ gemfiles/ruby_3.4_view_component_4.gemfile | 48 ++++++++++++++++++ 16 files changed, 334 insertions(+), 14 deletions(-) create mode 100644 gemfiles/ruby_3.4_view_component_2.34.0.gemfile create mode 100644 gemfiles/ruby_3.4_view_component_3.23.2.gemfile create mode 100644 gemfiles/ruby_3.4_view_component_4.gemfile diff --git a/Matrixfile b/Matrixfile index 6c2652b991d..aa06724331c 100644 --- a/Matrixfile +++ b/Matrixfile @@ -294,8 +294,8 @@ 'redis-3' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', }, 'view_component' => { - 'view_component-min' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', - 'view_component-3' => '❌ 2.5 / ❌ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', + 'view_component-2.34.0' => '✅ 2.5 / ✅ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', + 'view_component-3.23.2' => '❌ 2.5 / ❌ 2.6 / ✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', 'view_component-4' => '❌ 2.5 / ❌ 2.6 / ❌ 2.7 / ❌ 3.0 / ❌ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ 3.4 / ✅ 3.5 / ✅ jruby', }, 'appsec:active_record' => { diff --git a/appraisal/jruby-9.2.rb b/appraisal/jruby-9.2.rb index b9674b217c7..7f38e28ca84 100644 --- a/appraisal/jruby-9.2.rb +++ b/appraisal/jruby-9.2.rb @@ -204,7 +204,6 @@ build_coverage_matrix('rest-client') build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) -build_coverage_matrix('view_component', (3..4), min: '2.34.0') # NOTE: JRuby bundler failed to install some dependencies https://github.com/ruby/psych/issues/700 # and it could be re-enabled when upstream fix the issue # build_coverage_matrix('devise', min: '3.2.1') @@ -271,6 +270,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' + end +end + appraise 'contrib-old' do gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 end diff --git a/appraisal/jruby-9.3.rb b/appraisal/jruby-9.3.rb index 7d3cb453071..0a3cbf8cd90 100644 --- a/appraisal/jruby-9.3.rb +++ b/appraisal/jruby-9.3.rb @@ -177,7 +177,6 @@ build_coverage_matrix('rest-client') build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) -build_coverage_matrix('view_component', (3..4), min: '2.34.0') # NOTE: JRuby bundler failed to install some dependencies https://github.com/ruby/psych/issues/700 # and it could be re-enabled when upstream fix the issue # build_coverage_matrix('devise', min: '3.2.1') @@ -244,6 +243,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'contrib-old' do gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 end diff --git a/appraisal/jruby-9.4.rb b/appraisal/jruby-9.4.rb index 1a670790625..85463073dfe 100644 --- a/appraisal/jruby-9.4.rb +++ b/appraisal/jruby-9.4.rb @@ -82,7 +82,6 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') -build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'karafka-min' do gem 'karafka', '= 2.3.0' @@ -156,6 +155,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'contrib-old' do gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 end diff --git a/appraisal/ruby-2.5.rb b/appraisal/ruby-2.5.rb index 53786c63774..cac066da152 100644 --- a/appraisal/ruby-2.5.rb +++ b/appraisal/ruby-2.5.rb @@ -224,7 +224,6 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli') build_coverage_matrix('devise', min: '3.2.1', meta: { min: { 'bigdecimal' => '1.3.4' } }) -build_coverage_matrix('view_component', min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 5' @@ -288,6 +287,14 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + appraise 'contrib-old' do gem 'presto-client', '>= 0.5.14' # Renamed to trino-client in >= 1.0 end diff --git a/appraisal/ruby-2.6.rb b/appraisal/ruby-2.6.rb index 74169527890..47e34459852 100644 --- a/appraisal/ruby-2.6.rb +++ b/appraisal/ruby-2.6.rb @@ -177,7 +177,6 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1', meta: { min: { 'bigdecimal' => '1.4.1' } }) -build_coverage_matrix('view_component', min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 6.0.0' @@ -242,6 +241,14 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-2.7.rb b/appraisal/ruby-2.7.rb index 2ddceedd87a..5f4992b015d 100644 --- a/appraisal/ruby-2.7.rb +++ b/appraisal/ruby-2.7.rb @@ -178,7 +178,6 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 6.1.0' @@ -245,6 +244,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.0.rb b/appraisal/ruby-3.0.rb index a24d6606fef..c6e4bbc771a 100644 --- a/appraisal/ruby-3.0.rb +++ b/appraisal/ruby-3.0.rb @@ -98,7 +98,6 @@ build_coverage_matrix('mongo', min: '2.1.0') build_coverage_matrix('dalli', [2]) build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'karafka-min' do gem 'karafka', '= 2.3.0' @@ -169,6 +168,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.1.rb b/appraisal/ruby-3.1.rb index 6fad0cd2aa2..96aae7b3801 100644 --- a/appraisal/ruby-3.1.rb +++ b/appraisal/ruby-3.1.rb @@ -99,7 +99,6 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', [3], min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' @@ -166,6 +165,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.2.rb b/appraisal/ruby-3.2.rb index 087d2fc7f6c..74641c861b7 100644 --- a/appraisal/ruby-3.2.rb +++ b/appraisal/ruby-3.2.rb @@ -144,7 +144,6 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' @@ -211,6 +210,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.3.rb b/appraisal/ruby-3.3.rb index 9b5975380e5..2df62299565 100644 --- a/appraisal/ruby-3.3.rb +++ b/appraisal/ruby-3.3.rb @@ -146,7 +146,6 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do gem 'activerecord', '~> 7' @@ -213,6 +212,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.4.rb b/appraisal/ruby-3.4.rb index cc422439f35..8fc330f59a8 100644 --- a/appraisal/ruby-3.4.rb +++ b/appraisal/ruby-3.4.rb @@ -145,7 +145,6 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do # ActiveRecord locked because tests are failing with 7.1, which was attempted as a part of Ruby 3.4 testing in CI. @@ -226,6 +225,24 @@ end end + +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/appraisal/ruby-3.5.rb b/appraisal/ruby-3.5.rb index 26e615e4e4b..e4daa595839 100644 --- a/appraisal/ruby-3.5.rb +++ b/appraisal/ruby-3.5.rb @@ -94,7 +94,6 @@ build_coverage_matrix('dalli', [2]) build_coverage_matrix('karafka', min: '2.3.0') build_coverage_matrix('devise', min: '3.2.1') -build_coverage_matrix('view_component', (3..4), min: '2.34.0') appraise 'relational_db' do # ActiveRecord locked because tests are failing with 7.1, which was attempted as a part of Ruby 3.4 testing in CI. @@ -172,6 +171,23 @@ end end +appraise "view_component-2.34.0" do + gem 'view_component', "~> 2.34.0", require: "view_component/engine" + gem "actionview" + gem "rails" + gem 'sprockets', '< 4' + gem 'pg' +end + +['3.23.2', '4'].each do |v| + appraise "view_component-#{v}" do + gem 'view_component', "~> #{v}" + gem "actionview" + gem "rails" + gem 'pg' + end +end + appraise 'opentelemetry' do gem 'opentelemetry-sdk', '~> 1.1' end diff --git a/gemfiles/ruby_3.4_view_component_2.34.0.gemfile b/gemfiles/ruby_3.4_view_component_2.34.0.gemfile new file mode 100644 index 00000000000..df3e15b71b0 --- /dev/null +++ b/gemfiles/ruby_3.4_view_component_2.34.0.gemfile @@ -0,0 +1,49 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "base64" +gem "benchmark-ips", "~> 2.8" +gem "benchmark-memory", "< 0.2" +gem "bigdecimal" +gem "climate_control", "~> 1.2.0" +gem "concurrent-ruby" +gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" +gem "extlz4", "~> 0.3", ">= 0.3.3" +gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "json-schema", "< 3" +gem "memory_profiler", "~> 0.9" +gem "mutex_m" +gem "os", "~> 1.1" +gem "debug" +gem "byebug" +gem "pry" +gem "rake", ">= 10.5" +gem "rake-compiler", "~> 1.1", ">= 1.1.1" +gem "rspec", "~> 3.13" +gem "rspec-collection_matchers", "~> 1.1" +gem "rspec-wait", "~> 0" +gem "rspec_junit_formatter", ">= 0.5.1" +gem "simplecov", "~> 0.22.0" +gem "warning", "~> 1" +gem "webmock", ">= 3.10.0" +gem "webrick", ">= 1.8.2" +gem "view_component", "~> 2.34.0", require: "view_component/engine" +gem "actionview" +gem "rails" +gem "sprockets", "< 4" +gem "pg" + +group :check do + +end + +group :dev do + +end + +group :test do + gem "ostruct" +end + +gemspec path: "../" diff --git a/gemfiles/ruby_3.4_view_component_3.23.2.gemfile b/gemfiles/ruby_3.4_view_component_3.23.2.gemfile new file mode 100644 index 00000000000..587acdc68ee --- /dev/null +++ b/gemfiles/ruby_3.4_view_component_3.23.2.gemfile @@ -0,0 +1,48 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "base64" +gem "benchmark-ips", "~> 2.8" +gem "benchmark-memory", "< 0.2" +gem "bigdecimal" +gem "climate_control", "~> 1.2.0" +gem "concurrent-ruby" +gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" +gem "extlz4", "~> 0.3", ">= 0.3.3" +gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "json-schema", "< 3" +gem "memory_profiler", "~> 0.9" +gem "mutex_m" +gem "os", "~> 1.1" +gem "debug" +gem "byebug" +gem "pry" +gem "rake", ">= 10.5" +gem "rake-compiler", "~> 1.1", ">= 1.1.1" +gem "rspec", "~> 3.13" +gem "rspec-collection_matchers", "~> 1.1" +gem "rspec-wait", "~> 0" +gem "rspec_junit_formatter", ">= 0.5.1" +gem "simplecov", "~> 0.22.0" +gem "warning", "~> 1" +gem "webmock", ">= 3.10.0" +gem "webrick", ">= 1.8.2" +gem "view_component", "~> 3.23.2" +gem "actionview" +gem "rails" +gem "pg" + +group :check do + +end + +group :dev do + +end + +group :test do + gem "ostruct" +end + +gemspec path: "../" diff --git a/gemfiles/ruby_3.4_view_component_4.gemfile b/gemfiles/ruby_3.4_view_component_4.gemfile new file mode 100644 index 00000000000..76c0dafbd4d --- /dev/null +++ b/gemfiles/ruby_3.4_view_component_4.gemfile @@ -0,0 +1,48 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "base64" +gem "benchmark-ips", "~> 2.8" +gem "benchmark-memory", "< 0.2" +gem "bigdecimal" +gem "climate_control", "~> 1.2.0" +gem "concurrent-ruby" +gem "dogstatsd-ruby", ">= 3.3.0", "!= 5.0.0", "!= 5.0.1", "!= 5.1.0" +gem "extlz4", "~> 0.3", ">= 0.3.3" +gem "google-protobuf", ["~> 3.0", "!= 3.7.0", "!= 3.7.1"] +gem "json-schema", "< 3" +gem "memory_profiler", "~> 0.9" +gem "mutex_m" +gem "os", "~> 1.1" +gem "debug" +gem "byebug" +gem "pry" +gem "rake", ">= 10.5" +gem "rake-compiler", "~> 1.1", ">= 1.1.1" +gem "rspec", "~> 3.13" +gem "rspec-collection_matchers", "~> 1.1" +gem "rspec-wait", "~> 0" +gem "rspec_junit_formatter", ">= 0.5.1" +gem "simplecov", "~> 0.22.0" +gem "warning", "~> 1" +gem "webmock", ">= 3.10.0" +gem "webrick", ">= 1.8.2" +gem "view_component", "~> 4" +gem "actionview" +gem "rails" +gem "pg" + +group :check do + +end + +group :dev do + +end + +group :test do + gem "ostruct" +end + +gemspec path: "../" From 1e2b4c76a07fa8936a327a15d5f31d9f631304c8 Mon Sep 17 00:00:00 2001 From: Thomas Cannon Date: Tue, 21 Oct 2025 23:57:19 -0400 Subject: [PATCH 6/6] Add integration test for `Datadog::Tracing::Contrib::ViewComponent` * In order to properly write an integration test for ViewComponent we need to spin up an ad-hoc Rails app that we render the component within, then confirm the span data is generated * The integration test includes the `datadog/tracing/contrib/rails/rails_helper`, which provides a `Rails test application` context * Since there were configuration changes between different versions of ViewComponent, we need to adjust the configuration settings based on which version of the Gem has been loaded * This can be done using `Gem.loaded_specs` and `Gem::Version`, which provide an API for version comparison * Testing across the Appraised versions also checks that the `use_deprecated_instrumentation_name` configuration is applied, and does collect the necessary data --- .../view_component/integration_test_spec.rb | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 spec/datadog/tracing/contrib/view_component/integration_test_spec.rb diff --git a/spec/datadog/tracing/contrib/view_component/integration_test_spec.rb b/spec/datadog/tracing/contrib/view_component/integration_test_spec.rb new file mode 100644 index 00000000000..d5b66e46265 --- /dev/null +++ b/spec/datadog/tracing/contrib/view_component/integration_test_spec.rb @@ -0,0 +1,71 @@ +require 'datadog/tracing/contrib/rails/ext' +require 'datadog/tracing/contrib/rails/rails_helper' +require 'datadog/tracing/contrib/view_component/utils' +require 'datadog/tracing/contrib/view_component/integration' + + +require 'view_component' + +RSpec.describe 'ViewComponent integration tests', execute_in_fork: Rails.version.to_i >= 8 do + include_context 'Rails test application' + include ViewComponent::TestHelpers + + let(:initialize_block) do + if Gem.loaded_specs["view_component"].version <= Gem::Version.new("3") + require "view_component/engine" + end + + proc do + config.view_component.instrumentation_enabled = true + if Gem.loaded_specs["view_component"].version >= Gem::Version.new("4") + config.view_component.previews.controller = "TestController" + else + config.view_component.use_deprecated_instrumentation_name = false + config.view_component.test_controller = "TestController" + end + end + end + + let(:component) do + stub_const("TestComponent", Class.new(ViewComponent::Base) do + def call + content_tag(:h1, "Hello") + end + end) + end + + let(:controllers) { [controller] } + + let(:controller) do + stub_const('TestController', Class.new(ActionController::Base)) + end + + before do + Datadog.configure do |c| + if Gem.loaded_specs["view_component"].version >= Gem::Version.new("3") + c.tracing.instrument :view_component + else + c.tracing.instrument :view_component, use_deprecated_instrumentation_name: true + end + end + + allow(ENV).to receive(:[]).and_call_original + + app + end + + it "stores instrumentation data when rendering" do + controller.render(component.new) + span = spans.find{|s| s.name == "view_component.render" } + + expect(span.name).to eq("view_component.render") + expect(span.resource).to eq("TestComponent") + expect(span.type).to eq(Datadog::Tracing::Metadata::Ext::HTTP::TYPE_TEMPLATE) + + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT)).to eq("view_component") + expect(span.get_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION)).to eq("render") + + expect(span.get_tag("view_component.component_name")).to eq("TestComponent") + expect(span.get_tag("view_component.component_identifier")).to eq("integration_test_spec.rb") + end +end \ No newline at end of file