Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,12 @@ jobs:
- uses: rubygems/release-gem@6317d8d1f7e28c24d28f6eff169ea854948bd9f7 # v1.2.0
with:
token: ${{ steps.octo-sts.outputs.token }}

complete:
name: Build (complete)
# Depends on the validation jobs, not on publish: publish is conditional
# (only on push to main) and would otherwise leave this job skipped on PRs.
needs: [validate-linux, validate-macos]
runs-on: ubuntu-24.04
steps:
- run: echo "DONE!"
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
complete:
name: Main (complete)
needs:
- build
- test
- nix
runs-on: ubuntu-24.04
Expand Down
26 changes: 0 additions & 26 deletions .github/workflows/publish.yml

This file was deleted.

4 changes: 0 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,3 @@ jobs:
bundler: ${{ matrix.ruby.bundler }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle exec rake
- run: bundle exec rake extract
if: ${{ matrix.ruby.version == '4.0' }}
- run: bundle exec rake package
if: ${{ matrix.ruby.version == '4.0' }}
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,24 @@ You can also run `bundle exec pry` for an interactive prompt that will allow you

### Testing packaging locally

You can use `bundle exec rake package` to generate packages locally without publishing them.
First build the libdatadog binaries for your platform from source with
`bundle exec rake libdatadog:build`, then package them into gems (without
publishing) with `bundle exec rake gem:package`.

TIP: If the test that checks for permissions ("gem release process ... sets the right permissions on the gem files"), fails you
may need to run `umask 0022 && bundle exec rake package` so that the generated packages have the correct permissions.
You can check the file permissions of the built gems with
`bundle exec rake gem:validate`.

## Releasing a new version to rubygems.org

Note: No Ruby needed to run this! It all runs in CI!

1. [ ] Locate the new libdatadog release on GitHub: <https://github.com/datadog/libdatadog/releases>
2. [ ] Update the `LIB_GITHUB_RELEASES` section of the `Rakefile` with the hashes from the new version
3. [ ] In the <lib/libdatadog/version.rb> file:
2. [ ] In the <lib/libdatadog/version.rb> file:
- [ ] Update `LIB_VERSION` with the new version. Example: Setting "25.0.0" results in the first part of the string "25.0.0.1.0.x"
- [ ] (OPTIONAL) Update `GEM_PRERELEASE_VERSION` with a prerelease descriptor. This is only needed if you want to do a prerelease. Example: Setting ".beta" results in "25.0.0.1.0.beta".
4. [ ] Commit change, open PR, get it merged
5. [ ] Trigger the "Publish" workflow in <https://github.com/DataDog/libdatadog-rb/actions/workflows/publish.yml>
6. [ ] Verify that release shows up correctly on: <https://rubygems.org/gems/libdatadog>
3. [ ] Commit change, open PR, get it merged
4. [ ] Trigger the "Build" workflow on `main` with the "Push gems to RubyGems.org" option enabled: <https://github.com/DataDog/libdatadog-rb/actions/workflows/build.yml>
5. [ ] Verify that release shows up correctly on: <https://rubygems.org/gems/libdatadog>

## Contributing

Expand Down
233 changes: 1 addition & 232 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,237 +1,6 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "standard/rake" unless RUBY_VERSION < "2.6"

require "fileutils"
require "http" unless RUBY_VERSION < "2.5"
require "pry"
require "rubygems/package"

RSpec::Core::RakeTask.new(:spec)

# Note: When packaging rc releases and the like, you may need to set this differently from LIB_VERSION
LIB_VERSION_TO_PACKAGE = Libdatadog::LIB_VERSION

unless LIB_VERSION_TO_PACKAGE.start_with?(Libdatadog::LIB_VERSION)
raise "`LIB_VERSION_TO_PACKAGE` setting in <Rakefile> (#{LIB_VERSION_TO_PACKAGE}) does not match " \
"`LIB_VERSION` setting in <lib/libdatadog/version.rb> (#{Libdatadog::LIB_VERSION})"
end

LIB_GITHUB_RELEASES = [
{
file: "libdatadog-aarch64-alpine-linux-musl.tar.gz",
sha256: "e93457fd251444dbece87ad424140711a43cbc20da2c5c98009ba84d9be5e733",
ruby_platform: "aarch64-linux-musl"
},
{
file: "libdatadog-aarch64-unknown-linux-gnu.tar.gz",
sha256: "2a11baa8966e6c681b591124dfe6f4770fc4eae2c56f78aa2c7948088aea7a7b",
ruby_platform: "aarch64-linux"
},
{
file: "libdatadog-x86_64-alpine-linux-musl.tar.gz",
sha256: "42ec78865aacb9259656834dec9c4ab16ffe3d654c7eb5286eb543c7fd8f8baf",
ruby_platform: "x86_64-linux-musl"
},
{
file: "libdatadog-x86_64-unknown-linux-gnu.tar.gz",
sha256: "2925f2ed001ecb0d34d7c485aa5aadf86678bba62012ccb3fd5bdf272faee5da",
ruby_platform: "x86_64-linux"
},
{
file: "libdatadog-aarch64-apple-darwin.tar.gz",
sha256: "d277945d612fa6f38f644f15d1c1b2f63ea92cd53794e9d48ee7ad3290a7660d",
ruby_platform: "arm64-darwin"
}
]

task default: [
:spec,
(:standard unless RUBY_VERSION < "2.6")
].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/libdatadog/releases/download/v#{LIB_VERSION_TO_PACKAGE}/#{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

# Fix file permissions after extraction
puts "Fixing file permissions in #{target_directory}"
Helpers.fix_file_permissions(target_directory)
end
end

desc "Package lib downloaded releases as gems"
task package: [
:spec,
(:"standard:fix" unless RUBY_VERSION < "2.6")
] do
gemspec = eval(File.read("libdatadog.gemspec"), nil, "libdatadog.gemspec") # standard:disable Security/Eval
FileUtils.mkdir_p("pkg")

# Fallback package with all binaries
# This package will get used by (1) platforms that have no matching `ruby_platform` or (2) that have set
# "BUNDLE_FORCE_RUBY_PLATFORM" (or its equivalent via code) to avoid precompiled gems.
# In a previous version of libdatadog, this package had no binaries, but that could mean that we broke customers in case (2).
# For customers in case (1), this package is a no-op, and dd-trace-rb will correctly detect and warn that
# there are no valid binaries for the platform.
Helpers.package_for(gemspec, ruby_platform: nil, files: Helpers.files_for("x86_64-linux", "x86_64-linux-musl", "aarch64-linux", "aarch64-linux-musl", "arm64-darwin"))

# 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
Helpers.package_for(gemspec, ruby_platform: "x86_64-linux", files: Helpers.files_for("x86_64-linux", "x86_64-linux-musl"))
Helpers.package_for(gemspec, ruby_platform: "aarch64-linux", files: Helpers.files_for("aarch64-linux", "aarch64-linux-musl"))

# macOS package (Apple Silicon)
Helpers.package_for(gemspec, ruby_platform: "arm64-darwin", files: Helpers.files_for("arm64-darwin"))
end

Rake::Task["package"].enhance { Rake::Task["spec_validate_permissions"].execute }

task :spec_validate_permissions do
require "rspec"
RSpec.world.reset # If any other tests ran before, flushes them
ret = RSpec::Core::Runner.run(["spec/gem_packaging.rb"])
raise "Release tests failed! See error output above." if ret != 0
end

desc "Release all packaged gems"
task push_to_rubygems: [
:"release:guard_clean"
] do
[
"gem push pkg/libdatadog-#{Libdatadog::VERSION}.gem",
"gem push pkg/libdatadog-#{Libdatadog::VERSION}-x86_64-linux.gem",
"gem push pkg/libdatadog-#{Libdatadog::VERSION}-aarch64-linux.gem",
"gem push pkg/libdatadog-#{Libdatadog::VERSION}-arm64-darwin.gem"
].each do |command|
puts "Running: #{command}"
abort unless system(command)
end
end

module Helpers
# Files that should have executable permissions (755) in the gem
# Note: .so for Linux, .dylib for macOS
EXECUTABLE_FILES = ["libdatadog-crashtracking-receiver", "libdatadog_profiling.so", "libdatadog_profiling.dylib"].freeze

def self.each_github_release_variant
LIB_GITHUB_RELEASES.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/libdatadog-#{Libdatadog::LIB_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_for(gemspec, ruby_platform:, files:)
target_gemspec = gemspec.dup
target_gemspec.files += files
target_gemspec.platform = ruby_platform if ruby_platform

puts "Building with ruby_platform=#{ruby_platform.inspect} 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.fix_file_permissions(directory)
Dir.glob("#{directory}/**/*").each do |path|
next unless File.file?(path)

filename = File.basename(path)
current_permissions = File.stat(path).mode & 0o777

if EXECUTABLE_FILES.include?(filename)
# Should be executable (755), fix if not
if current_permissions != 0o755
puts "Fixing permissions for #{filename}: #{current_permissions.to_s(8)} -> 755"
FileUtils.chmod(0o755, path)
end
elsif current_permissions != 0o644
# Should be non-executable (644), fix if not
puts "Fixing permissions for #{filename}: #{current_permissions.to_s(8)} -> 644"
FileUtils.chmod(0o644, path)
end
end
end

def self.files_for(
*included_platforms,
excluded_files: [
"datadog_profiling.pc", # we use the datadog_profiling_with_rpath.pc variant
"libdatadog_profiling.a", "datadog_profiling-static.pc", # We don't use the static library
"libdatadog_profiling.debug", # We don't include debug info
"DatadogConfig.cmake" # We don't compile using cmake
]
)
files = []

each_github_release_variant do |ruby_platform:, target_directory:, target_file:, **_|
next unless included_platforms.include?(ruby_platform)

downloaded_release_tarball = target_file

files +=
Dir.glob("#{target_directory}/**/*")
.select { |path| File.file?(path) }
.reject { |path| path == downloaded_release_tarball }
.reject { |path| excluded_files.include?(File.basename(path)) }
end

files
end
end

Rake::Task["build"].clear
task(:build) { raise "Build task is disabled, use package instead" }

Rake::Task["release"].clear
task(:release) { Rake::Task["push_to_rubygems"].invoke }

# Load additional tasks
# Each logical group of tasks lives in its own file under tasks/.
Dir.glob("tasks/**/*.rake").each { |r| import r }
51 changes: 0 additions & 51 deletions spec/gem_packaging.rb

This file was deleted.

Loading
Loading