This repository has been archived by the owner on Jun 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
[PROF-4779] Publish libddprof as a Ruby gem on rubygems.org #16
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
06178a5
Bootstrap scaffolding for libddprof Ruby gem
ivoanjo f1c6da8
Add Rake task for releasing gem including binary libddprof releases
ivoanjo 6738318
Add helper methods for consuming libddprof
ivoanjo 1dbfad4
Dockerize and document release process
ivoanjo fd55f0f
Fix flaky test due to filesystem ordering
ivoanjo 84c71fd
Gracefully handle cases where vendor directory does not exist
ivoanjo 7ead908
Bump gem version to beta2
ivoanjo 0ea7bc4
Adopt new versioning scheme, as suggested during PR review
ivoanjo cd59500
Refactor .no_binaries? helper into its reverse .binaries?
ivoanjo 8d23e24
Improving logging when file did not match the expected hash
ivoanjo 90af8a2
Clarify that Ruby release instructions are for Datadog employees
ivoanjo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/.bundle/ | ||
/.yardoc | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
|
||
# rspec failure tracking | ||
.rspec_status | ||
|
||
gems.locked | ||
|
||
vendor/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--format documentation | ||
--color | ||
--require spec_helper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# For available configuration options, see: | ||
# https://github.com/testdouble/standard | ||
ruby_version: 2.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# libddprof Ruby gem | ||
|
||
`libddprof` provides a shared library containing common code used in the implementation of Datadog's | ||
[Continuous Profilers](https://docs.datadoghq.com/tracing/profiler/). | ||
|
||
**NOTE**: If you're building a new profiler or want to contribute to Datadog's existing profilers, you've come to the | ||
right place! | ||
Otherwise, this is possibly not the droid you were looking for. | ||
|
||
## Development | ||
|
||
Run `bundle exec rake` to run the tests and the style autofixer. | ||
You can also run `bundle exec pry` for an interactive prompt that will allow you to experiment. | ||
|
||
## Releasing a new version to rubygems.org | ||
|
||
Note: No Ruby needed to run this! It all runs inside docker :) | ||
|
||
Note: Publishing new releases to rubygems.org can only be done by Datadog employees. | ||
|
||
1. [ ] Locate the new libddprof release on GitHub: <https://github.com/DataDog/libddprof/releases> | ||
2. [ ] Update the `LIB_GITHUB_RELEASES` section of the <Rakefile> with the new version | ||
3. [ ] Update the <lib/libddprof/version.rb> file with the `LIB_VERSION` and `VERSION` to use | ||
4. [ ] Commit change, open PR, get it merged | ||
5. [ ] Release by running `docker-compose run push_to_rubygems`. | ||
(When asked for rubygems credentials, check your local friendly Datadog 1Password.) | ||
6. [ ] Verify that release shows up correctly on: <https://rubygems.org/gems/libddprof> | ||
|
||
## Contributing | ||
|
||
See <../CONTRIBUTING.md>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# frozen_string_literal: true | ||
|
||
require "bundler/gem_tasks" | ||
require "rspec/core/rake_task" | ||
require "standard/rake" unless RUBY_VERSION < "2.5" | ||
|
||
require "fileutils" | ||
require "http" | ||
require "pry" | ||
require "rubygems/package" | ||
|
||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
LIB_GITHUB_RELEASES = { | ||
"0.2.0" => [ | ||
{ | ||
file: "libddprof-x86_64-unknown-linux-gnu.tar.gz", | ||
sha256: "cba0f24074d44781d7252b912faff50d330957e84a8f40a172a8138e81001f27", | ||
ruby_platform: "x86_64-linux" | ||
}, | ||
{ | ||
file: "libddprof-x86_64-alpine-linux-musl.tar.gz", | ||
sha256: "d519a6241d78260522624b8e79e98502510f11d5d9551f5f80fc1134e95fa146", | ||
ruby_platform: "x86_64-linux-musl" | ||
} | ||
] | ||
# Add more versions here | ||
} | ||
|
||
task default: [ | ||
:spec, | ||
(:'standard:fix' unless RUBY_VERSION < "2.5") | ||
].compact | ||
|
||
desc "Download lib release from github" | ||
task :fetch do | ||
Helpers.each_github_release_variant do |file:, sha256:, target_directory:, target_file:, **_| | ||
target_url = "https://github.com/DataDog/libddprof/releases/download/v#{Libddprof::LIB_VERSION}/#{file}" | ||
|
||
if File.exist?(target_file) | ||
target_file_hash = Digest::SHA256.hexdigest(File.read(target_file)) | ||
|
||
if target_file_hash == sha256 | ||
puts "Found #{target_file} matching the expected sha256, skipping download" | ||
next | ||
else | ||
puts "Found #{target_file} with hash (#{target_file_hash}) BUT IT DID NOT MATCH THE EXPECTED sha256 (#{sha256}), downloading it again..." | ||
end | ||
end | ||
|
||
puts "Going to download #{target_url} into #{target_file}" | ||
|
||
File.open(target_file, "wb") do |file| | ||
HTTP.follow.get(target_url).body.each { |chunk| file.write(chunk) } | ||
end | ||
|
||
if Digest::SHA256.hexdigest(File.read(target_file)) == sha256 | ||
puts "Success!" | ||
else | ||
raise "Downloaded file is corrupt, does not match expected sha256" | ||
end | ||
end | ||
end | ||
|
||
desc "Extract lib downloaded releases" | ||
task extract: [:fetch] do | ||
Helpers.each_github_release_variant do |target_directory:, target_file:, **_| | ||
puts "Extracting #{target_file}" | ||
File.open(target_file, "rb") do |file| | ||
Gem::Package.new("").extract_tar_gz(file, target_directory) | ||
end | ||
end | ||
end | ||
|
||
desc "Package lib downloaded releases as gems" | ||
task package: [:spec, :'standard:fix', :extract] do | ||
gemspec = eval(File.read("libddprof.gemspec"), nil, "libddprof.gemspec") # standard:disable Security/Eval | ||
FileUtils.mkdir_p("pkg") | ||
|
||
Helpers.package_without_binaries(gemspec) | ||
Helpers.package_linux_x86_64(gemspec) | ||
end | ||
|
||
desc "Release all packaged gems" | ||
task push_to_rubygems: [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems uncanny to have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While a bit uncommon, I like that it exactly matches the name of the docker invocation that calls it ( |
||
:package, | ||
:'release:guard_clean' | ||
] do | ||
system("gem signout") # make sure there are no existing credentials in use | ||
|
||
system("gem push pkg/libddprof-#{Libddprof::VERSION}.gem") | ||
system("gem push pkg/libddprof-#{Libddprof::VERSION}-x86_64-linux.gem") | ||
|
||
system("gem signout") # leave no credentials behind | ||
end | ||
|
||
module Helpers | ||
def self.each_github_release_variant(version: Libddprof::LIB_VERSION) | ||
LIB_GITHUB_RELEASES.fetch(version).each do |variant| | ||
file = variant.fetch(:file) | ||
sha256 = variant.fetch(:sha256) | ||
ruby_platform = variant.fetch(:ruby_platform) | ||
|
||
# These two are so common that we just centralize them here | ||
target_directory = "vendor/libddprof-#{version}/#{ruby_platform}" | ||
target_file = "#{target_directory}/#{file}" | ||
|
||
FileUtils.mkdir_p(target_directory) | ||
|
||
yield(file: file, sha256: sha256, ruby_platform: ruby_platform, target_directory: target_directory, target_file: target_file) | ||
end | ||
end | ||
|
||
def self.package_without_binaries(gemspec) | ||
target_gemspec = gemspec.dup | ||
|
||
puts "Building a variant without binaries including:" | ||
pp target_gemspec.files | ||
|
||
package = Gem::Package.build(target_gemspec) | ||
FileUtils.mv(package, "pkg") | ||
puts("-" * 80) | ||
end | ||
|
||
def self.package_linux_x86_64(gemspec) | ||
# We include both glibc and musl variants in the same binary gem to avoid the issues | ||
# documented in https://github.com/rubygems/rubygems/issues/3174 | ||
target_gemspec = gemspec.dup | ||
target_gemspec.files += files_for("x86_64-linux", "x86_64-linux-musl") | ||
target_gemspec.platform = "x86_64-linux" | ||
|
||
puts "Building for x86_64-linux including: (this can take a while)" | ||
pp target_gemspec.files | ||
|
||
package = Gem::Package.build(target_gemspec) | ||
FileUtils.mv(package, "pkg") | ||
puts("-" * 80) | ||
end | ||
|
||
def self.files_for(*included_platforms, version: Libddprof::LIB_VERSION) | ||
files = [] | ||
|
||
each_github_release_variant(version: version) do |ruby_platform:, target_directory:, target_file:, **_| | ||
next unless included_platforms.include?(ruby_platform) | ||
|
||
files += Dir.glob("#{target_directory}/**/*").select { |path| File.file?(path) } - [target_file] | ||
end | ||
|
||
files | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
version: '3.2' | ||
services: | ||
push_to_rubygems: | ||
image: ruby:3.1 | ||
platform: linux/x86_64 | ||
stdin_open: true | ||
tty: true | ||
command: bash -c 'cd /libddprof/ruby && bundle install && bundle exec rake push_to_rubygems' | ||
volumes: | ||
- ..:/libddprof | ||
- bundle-3.1:/usr/local/bundle | ||
|
||
volumes: | ||
bundle-3.1: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# frozen_string_literal: true | ||
|
||
source "https://rubygems.org" | ||
|
||
# Specify your gem's dependencies in libddprof.gemspec | ||
gemspec | ||
|
||
gem "rake", "~> 13.0" | ||
gem "rspec", "~> 3.10" | ||
gem "standard", "~> 1.3" unless RUBY_VERSION < "2.5" | ||
gem "http", "~> 5.0" | ||
gem "pry" | ||
gem "pry-byebug" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "libddprof/version" | ||
|
||
module Libddprof | ||
# Does this libddprof release include any binaries? | ||
def self.binaries? | ||
available_binaries.any? | ||
end | ||
|
||
# This should only be used for debugging/logging | ||
def self.available_binaries | ||
File.directory?(vendor_directory) ? Dir.children(vendor_directory) : [] | ||
end | ||
|
||
def self.pkgconfig_folder | ||
current_platform = Gem::Platform.local.to_s | ||
|
||
return unless available_binaries.include?(current_platform) | ||
|
||
pkgconfig_file = Dir.glob("#{vendor_directory}/#{current_platform}/**/ddprof_ffi.pc").first | ||
|
||
return unless pkgconfig_file | ||
|
||
File.absolute_path(File.dirname(pkgconfig_file)) | ||
end | ||
|
||
private_class_method def self.vendor_directory | ||
ENV["LIBDDPROF_VENDOR_OVERRIDE"] || "#{__dir__}/../vendor/libddprof-#{Libddprof::LIB_VERSION}/" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# frozen_string_literal: true | ||
|
||
module Libddprof | ||
# Current libddprof version | ||
LIB_VERSION = "0.2.0" | ||
|
||
GEM_MAJOR_VERSION = "1" | ||
GEM_MINOR_VERSION = "0" | ||
GEM_PRERELEASE_VERSION = ".beta3" | ||
private_constant :GEM_MAJOR_VERSION, :GEM_MINOR_VERSION, :GEM_PRERELEASE_VERSION | ||
|
||
# The gem version scheme is lib_version.gem_major.gem_minor[.prerelease]. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, this makes sense. |
||
# This allows a version constraint such as ~> 0.2.0.1.0 in the consumer (ddtrace), in essence pinning the libddprof to | ||
# a specific version like = 0.2.0, but still allow a) introduction of a gem-level breaking change by bumping gem_major | ||
# and b) allow to push automatically picked up bugfixes by bumping gem_minor. | ||
VERSION = "#{LIB_VERSION}.#{GEM_MAJOR_VERSION}.#{GEM_MINOR_VERSION}#{GEM_PRERELEASE_VERSION}" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# frozen_string_literal: true | ||
|
||
lib = File.expand_path("../lib", __FILE__) | ||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | ||
require "libddprof/version" | ||
|
||
Gem::Specification.new do |spec| | ||
spec.name = "libddprof" | ||
spec.version = Libddprof::VERSION | ||
spec.authors = ["Datadog, Inc."] | ||
spec.email = ["dev@datadoghq.com"] | ||
|
||
spec.summary = "Library of common code used by Datadog Continuous Profiler for Ruby" | ||
spec.description = | ||
"libddprof contains implementation bits used by Datadog's ddtrace gem as part of its Continuous Profiler feature." | ||
spec.homepage = "https://docs.datadoghq.com/tracing/profiler/" | ||
spec.license = "Apache-2.0" | ||
spec.required_ruby_version = ">= 2.1.0" | ||
|
||
spec.metadata["allowed_push_host"] = "https://rubygems.org" | ||
|
||
spec.metadata["homepage_uri"] = spec.homepage | ||
spec.metadata["source_code_uri"] = "https://github.com/DataDog/libddprof/tree/main/ruby" | ||
|
||
# Require releases on rubygems.org to be coming from multi-factor-auth-authenticated accounts | ||
spec.metadata["rubygems_mfa_required"] = "true" | ||
|
||
# Specify which files should be added to the gem when it is released. | ||
# The `git ls-files -z` loads the files in the RubyGem that have been added into git. | ||
spec.files = Dir.chdir(File.expand_path(__dir__)) do | ||
`git ls-files -z`.split("\x0").reject do |f| | ||
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) | ||
end | ||
end | ||
spec.require_paths = ["lib"] | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pedantic, but will anyone be confused by seeing
libddprof-x86_64-alpine-linux-musl
on their non-Alpine musl system? As far as I know, the liddprof artifacts don't care. In fact, I wouldn't be surprised if the musl artifact works perfectly fine on glibc systems.(irrelevant comment is irrelevant, sorry)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good question!
Ideally we would upload each
ruby_platform
variant separately to rubygems.org, and Ruby would pick the right one. But there's a bunch of bugs around that and even if the bugs were fixed, we support really old Ruby versions that wouldn't be running the fixed versions.So actually we're shipping both variants inside the same release on rubygems.org, and then the consumer will pick the right one:
But TL;DR I don't think this will confuse customers because they will only get libddprof through dd-trace-rb, which will use the code above to pick the right one and ignore the other.