From 6da056b7e06ad126d25006bda359cf2f274e68cb Mon Sep 17 00:00:00 2001 From: jackdpeterson Date: Wed, 6 May 2026 11:41:08 -0700 Subject: [PATCH] Modernize Ruby support and pin dependencies - Add Ruby 3.3 support, drop Ruby < 2.7 (align with gemspec >= 2.7.0, < 3.4) - Update ruby_versions in bin/install and bin/codedeploy-agent to [3.3, 3.2, 3.1, 3.0, 2.7] - Update GitHub Actions workflow to test matrix across all supported Ruby versions - Fix minitar: update require path from 'archive/tar/minitar' to 'minitar', remove obsolete 'include Archive::Tar' - Fix rubyzip: replace removed Zip::File::CREATE with create: true, handle extract API differences between rubyzip 2.x and 3.x - Fix PKCS7 test assertions to handle OpenSSL error message variations across versions (nested asn1 error vs no start line) - Pin all dependencies to exact tested versions for deterministic builds - Add Makefile for local Docker-based testing across all Ruby versions Validated 449 tests passing with 0 failures across Ruby 2.7, 3.0, 3.1, 3.2, and 3.3. --- .github/workflows/ruby.yml | 7 ++--- Makefile | 21 +++++++++++++++ bin/codedeploy-agent | 2 +- bin/install | 6 ++--- codedeploy_agent.gemspec | 26 +++++++++---------- .../codedeploy_local_steps.rb | 3 +-- lib/instance_agent/platform/windows_util.rb | 3 +-- .../plugins/codedeploy/command_executor.rb | 7 ++++- .../deployment_specification_test.rb | 6 +++-- .../plugins/codedeploy/unpack_bundle_test.rb | 2 +- 10 files changed, 55 insertions(+), 28 deletions(-) create mode 100644 Makefile diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8e3274e2..b4ea4536 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -17,14 +17,15 @@ jobs: test: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - ruby-version: ['2.7'] + ruby-version: ['3.3', '3.2', '3.1', '3.0', '2.7'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler-cache: true - name: Run tests run: bundle exec rake diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c75bd8c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +RUBY_VERSIONS := 2.7 3.0 3.1 3.2 3.3 +TARGETS := $(addprefix test-ruby-,$(RUBY_VERSIONS)) + +.PHONY: test test-all $(TARGETS) + +test-all: $(TARGETS) + @echo "All versions passed." + +define ruby_test_rule +test-ruby-$(1): + @echo "=== Ruby $(1) ===" + @docker run --rm -v "$$(CURDIR):/app" -w /app ruby:$(1) bash -c "\ + rm -f Gemfile.lock && \ + gem install bundler -v 2.4.22 --no-document > /dev/null 2>&1 && \ + bundle install --quiet 2>/dev/null && \ + bundle exec rake" +endef + +$(foreach v,$(RUBY_VERSIONS),$(eval $(call ruby_test_rule,$(v)))) + +test: test-ruby-3.3 diff --git a/bin/codedeploy-agent b/bin/codedeploy-agent index 6c84218e..f47289ed 100755 --- a/bin/codedeploy-agent +++ b/bin/codedeploy-agent @@ -2,7 +2,7 @@ $:.unshift File.join(File.dirname(File.expand_path('..', __FILE__)), 'lib') -ruby_versions = ["3.2", "3.1", "3.0", "2.7", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] +ruby_versions = ["3.3", "3.2", "3.1", "3.0", "2.7"] actual_ruby_version = RUBY_VERSION.split('.').map{|s|s.to_i} left_bound = '2.0.0'.split('.').map{|s|s.to_i} ruby_bin = nil diff --git a/bin/install b/bin/install index b1461555..ce589b85 100755 --- a/bin/install +++ b/bin/install @@ -245,8 +245,8 @@ IMDS v2 call is failed To use a HTTP proxy, specify --proxy followed by the proxy server defined by http://hostname:port -This install script needs Ruby versions 2.x or 3.x installed as a prerequisite. -Currently recommended Ruby versions are 2.0.0, 2.1.8, 2.2.4, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, and 3.2 +This install script needs Ruby versions 2.7 or 3.[1-3] installed as a prerequisite. +Currently recommended Ruby versions are 2.7, 3.0, 3.1, 3.2, and 3.3 If multiple Ruby versions are installed, the default ruby version will be used. If the default ruby version does not satisfy requirement, the newest version will be used. If you do not have a supported Ruby version installed, please install one of them first. @@ -255,7 +255,7 @@ EOF end def supported_ruby_versions - ['3.2','3.1','3.0', '2.7', '2.6', '2.5', '2.4', '2.3', '2.2', '2.1', '2.0'] + ['3.3', '3.2', '3.1', '3.0', '2.7'] end # check ruby version, only version 2.x 3.x works diff --git a/codedeploy_agent.gemspec b/codedeploy_agent.gemspec index e261ec1c..5df7996a 100644 --- a/codedeploy_agent.gemspec +++ b/codedeploy_agent.gemspec @@ -9,19 +9,19 @@ Gem::Specification.new do |spec| spec.bindir = ['bin'] spec.require_paths = ['lib'] spec.license = 'Apache-2.0' - spec.required_ruby_version = '>= 2.7.0' + spec.required_ruby_version = '>= 2.7.0', '< 3.4' - spec.add_dependency('gli', '~> 2.21') - spec.add_dependency('json_pure', '~> 1.6') - spec.add_dependency('minitar', '~> 0.6.1') - spec.add_dependency('rubyzip', '~> 1.3.0') - spec.add_dependency('logging', '~> 2.2') - spec.add_dependency('aws-sdk-core', '~> 3') - spec.add_dependency('aws-sdk-s3', '~> 1') - spec.add_dependency('docopt', '~> 0.5.0') - spec.add_dependency('concurrent-ruby', '~> 1.1.9') - spec.add_dependency('rexml', '~> 3.3.9') + spec.add_dependency('gli', '2.22.2') + spec.add_dependency('json_pure', '2.8.1') + spec.add_dependency('minitar', '0.12.1') + spec.add_dependency('rubyzip', '2.4.1') + spec.add_dependency('logging', '2.4.0') + spec.add_dependency('aws-sdk-core', '3.246.0') + spec.add_dependency('aws-sdk-s3', '1.220.0') + spec.add_dependency('docopt', '0.5.0') + spec.add_dependency('concurrent-ruby', '1.1.10') + spec.add_dependency('rexml', '3.3.9') - spec.add_development_dependency('rake', '~> 12.3.3') - spec.add_development_dependency('rspec', '~> 3.2.0') + spec.add_development_dependency('rake', '13.4.2') + spec.add_development_dependency('rspec', '3.13.2') end diff --git a/features/step_definitions/codedeploy_local_steps.rb b/features/step_definitions/codedeploy_local_steps.rb index 7b93aa1e..48e032f2 100644 --- a/features/step_definitions/codedeploy_local_steps.rb +++ b/features/step_definitions/codedeploy_local_steps.rb @@ -1,7 +1,6 @@ -require 'archive/tar/minitar' +require 'minitar' require 'zlib' require 'pathname' -include Archive::Tar $:.unshift File.join(File.dirname(File.expand_path('../../..', __FILE__)), 'lib') $:.unshift File.join(File.dirname(File.expand_path('../../..', __FILE__)), 'features') diff --git a/lib/instance_agent/platform/windows_util.rb b/lib/instance_agent/platform/windows_util.rb index 6238b9a4..600af44f 100644 --- a/lib/instance_agent/platform/windows_util.rb +++ b/lib/instance_agent/platform/windows_util.rb @@ -1,6 +1,5 @@ -require 'archive/tar/minitar' +require 'minitar' require 'zlib' -include Archive::Tar module InstanceAgent diff --git a/lib/instance_agent/plugins/codedeploy/command_executor.rb b/lib/instance_agent/plugins/codedeploy/command_executor.rb index defc7fb8..6db2ff43 100644 --- a/lib/instance_agent/plugins/codedeploy/command_executor.rb +++ b/lib/instance_agent/plugins/codedeploy/command_executor.rb @@ -505,7 +505,12 @@ def unpack_bundle(cmd, bundle_file, deployment_spec) zipfile.each do |f| file_dst = File.join(dst, f.name) FileUtils.mkdir_p(File.dirname(file_dst)) - zipfile.extract(f, file_dst) { true } + FileUtils.rm_f(file_dst) + if Gem::Version.new(Gem.loaded_specs['rubyzip'].version) >= Gem::Version.new('3.0') + zipfile.extract(f, destination_directory: dst) + else + zipfile.extract(f, file_dst) + end end end end diff --git a/test/instance_agent/plugins/codedeploy/deployment_specification_test.rb b/test/instance_agent/plugins/codedeploy/deployment_specification_test.rb index 2b0c4af1..b939318b 100644 --- a/test/instance_agent/plugins/codedeploy/deployment_specification_test.rb +++ b/test/instance_agent/plugins/codedeploy/deployment_specification_test.rb @@ -480,13 +480,14 @@ def generate_signed_message_for(map) should "raise when JSON submitted as PKCS7/JSON" do @packed_message.payload = @deployment_spec.to_json - assert_raised_with_message("Could not parse the PKCS7: nested asn1 error") do + error = assert_raise(RuntimeError) do begin InstanceAgent::Plugins::CodeDeployPlugin::DeploymentSpecification.parse(@packed_message) rescue ArgumentError => e raise e.message end end + assert_match(/Could not parse the PKCS7: (nested asn1 error|no start line)/, error.message) end end @@ -591,13 +592,14 @@ def generate_signed_message_for(map) should "raise when JSON submitted as PKCS7/JSON" do @packed_local_revision_message.payload = @deployment_local_revision_spec.to_json - assert_raised_with_message("Could not parse the PKCS7: nested asn1 error") do + error = assert_raise(RuntimeError) do begin InstanceAgent::Plugins::CodeDeployPlugin::DeploymentSpecification.parse(@packed_local_revision_message) rescue ArgumentError => e raise e.message end end + assert_match(/Could not parse the PKCS7: (nested asn1 error|no start line)/, error.message) end end diff --git a/test/instance_agent/plugins/codedeploy/unpack_bundle_test.rb b/test/instance_agent/plugins/codedeploy/unpack_bundle_test.rb index ad55f47d..2b61b30f 100644 --- a/test/instance_agent/plugins/codedeploy/unpack_bundle_test.rb +++ b/test/instance_agent/plugins/codedeploy/unpack_bundle_test.rb @@ -28,7 +28,7 @@ def setup_local_file_bundle end # create the bundle as a local zip file @local_file_location = File.join(@local_file_directory, "bundle.zip") - Zip::File.open(@local_file_location, Zip::File::CREATE) do |zipfile| + Zip::File.open(@local_file_location, create: true) do |zipfile| input_filenames.each do |filename| zipfile.add(filename, File.join(@local_file_directory, filename)) end