-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPIKE: Gem Version Compatibility Checks #1016
SPIKE: Gem Version Compatibility Checks #1016
Conversation
8e54b46
to
99f1645
Compare
@robertlaurin @ericmustin This is a first step in a multi stage refactoring to add some constraints around what versions an auto-instrumented library will support. Before I proceed I would like to get your initial thoughts and feedback. cc: #947
The only headache here for me is the redundant The other thing bouncing around in my head is reducing test friction. Would there be a way to validate the these constraints without combinatorial explosion of appraisals? Also, how does the instrumentation semver relate to the target library? |
broadly speaking i think what you've laid out here would work, but practically speaking i'm not sure it actually accomplishes too much beside making things more confusing for the benefit of a little bit of automagic on the compatibility check, especially since your use case of not wanting to rely on Here's what I think we've gotten to
I think we could do this a few ways but the most straightforward way i could think of for now is just to
kinda thinking out loud...wdyt? |
To confirm you are advocating that each auto-instrumentation define a E.g. module OpenTelemetry
module Instrumentation
module Sinatra
class Instrumentation < OpenTelemetry::Instrumentation::Base
MIN_VERSION = "2.0.7"
MAX_VERSION = "2.9"
compatible do
spec_version = Gem.loaded_specs["sinatra"]&.version || Gem::Version.new(::Sinatra::VERSION)
Gem::Version.new(MIN_VERSION) <= spec_version && spec_version >= Gem::Version.new(MAX_VERSION)
end
end
end
end
end That makes it possible to generate appraisals easier because we will be able to find the constants by convention. Is that right?
👍🏼 This may be a matter of changing how our test suite runs to parallelize execution in a more interesting and meaningful way.
🤔 the advantage here is that we could test out compatibility with newer versions without requiring code changes right? module OpenTelemetry
module Instrumentation
module Sinatra
class Instrumentation < OpenTelemetry::Instrumentation::Base
MIN_VERSION = "2.0.7"
MAX_VERSION = "2.9"
compatible do
spec_version = Gem.loaded_specs["sinatra"]&.version || Gem::Version.new(::Sinatra::VERSION)
Gem::Version.new(MIN_VERSION) <= spec_version && (config[:enforce_max_version] && spec_version >= Gem::Version.new(MAX_VERSION))
end
end
end
end
end There is something that still isn't sitting right with me and I cannot quite articulate what is wrong. Maybe I need to write down all of the references to versioning to help me formulate some thoughts... ℹ️ We define a minimal supported gem version as a development dependency for development and testing: We add it as a development dependency to make it easier to include all dependencies without impacting the target applications runtime dependencies. ℹ️ We sometimes define an appraisal for all gem versions we believe this gem supports ℹ️ We always exercise a test suite for the appraised versions on all of our supported platforms https://github.com/open-telemetry/opentelemetry-ruby/blob/main/.github/workflows/ci.yml#L15 ℹ️ We sometimes programmatically enforce compatibility constraints ℹ️ We sometimes fallback to constant if the gemspecs were not loaded I wonder if there is something that we can do to declare the dependent versions in a single way and leverage them in all of the scenarios laid out above? Is it possibly to do that using the declared library dependency version defined in the gemspec of the current instrumentation? |
@ericmustin After doing a little research it looks like using irb(main):008:0> instrumentation_gemspec = Gem::Specification.find_by_name("opentelemetry-instrumentation-faraday")
=> Gem::Specification.new do |s|
...
irb(main):009:0> supported_gemspec = instrumentation_gemspec.development_dependencies.find { |spec| spec.name == "faraday" }
=> Gem::Dependency.new("faraday", Gem::Requirement.new(["~> 0.17.0"]), :development)
irb(main):010:0> requirement = supported_gemspec.requirement
=> Gem::Requirement.new(["~> 0.17.0"])
irb(main):019:0> installed_gemspec = Gem::Specification.find_by_name("faraday")
=> Gem::Specification.new do |s|
...
irb(main):021:0> installed_gemspec.version
=> Gem::Version.new("0.17.4")
irb(main):020:0> requirement.satisfied_by?(installed_gemspec.version)
=> true
irb(main):029:0> requirement.satisfied_by?(Gem::Version.new("0.16.9"))
=> false
irb(main):030:0> requirement.satisfied_by?(Gem::Version.new("0.18.0"))
=> false I think what this will do is give us the ability to declare explicitly target gem requirements without having to create a separate declaration in the instrumentation source. |
@arielvalentin I think I agree with all the ℹ️'s you've laid out. And looking at your example of
What would this look like exactly? are you saying we could possibly just determine the min/max requirements from the instrumentation's I guess what's confusing to me is we're trying to do a few things at once here. Is there one of the issues that we've talked about that is most important to your use case or that you're blocked on? Or are you just interested in broadly improving/adding a DSL here? If it's the latter that's fine I just want to make sure i'm on the same page. |
It sounds like I wasn't clear about what I was suggesting in my previous comment. I am abandoning the idea of the versioning DSL as well as falling back on a constant in favor of comparing the instrumentation gemspec and the target library gemspec as the source for the compatibility check at runtime. This should reduce friction for engineers since they can be as specific as they need to in gemspec dependencies instead of defining specific constraints in code. Using The only thing we would need to developer to specific is the name of the target gem they are instrumenting. The Instrumentation::Base class can take it from there. I will update the PR with an example of what I mean tomorrow. |
@arielvalentin ah gotcha gotcha, yea I think that makes sense, we should prob still accept an optional compatibility block in the case that the logic is more complicated (maybe, based on platform or some other arbitrary thing that we cant plan for) |
I agree ... Circle gets the square! |
6a7b2ea
to
4d6c071
Compare
daa8084
to
aa8ef4b
Compare
@ericmustin I hacked together a spike to get some feedback from you. LMK if you think it looks good. |
@arielvalentin i think this approach lgtm, off the top of my head my largest concerns are all addressed
I will ask for some feedback from the other folks on my team but my 2 cents is I really like this approach and i think it improves instrumentation compatibility definitions (by baking it into the gemspec), and also creates a path to more tightly define+test our gem compatibility in appraisals (since we can abstract out the major support versions for appraisals programmatically from the gemspec). Maybe can split this work into
Wdyt? |
@ericmustin Yes that sounds good to me. I am on vacation for Thanksgiving week so let's allow this to sit for a bit to give others a chance at providing some feedback. |
Closing this out in favor of #1025 |
This PR is not intended to be merged. It is a spike to flesh out alternative implementations of instrumentation version compatibility.