diff --git a/features/codedeploy-local/codedeploy_local.feature b/features/codedeploy-local/codedeploy_local.feature index 14d72b5f..6b0f871d 100644 --- a/features/codedeploy-local/codedeploy_local.feature +++ b/features/codedeploy-local/codedeploy_local.feature @@ -31,6 +31,13 @@ Feature: Local Deploy using AWS CodeDeploy Local CLI And the expected files should have have been locally deployed to my host And the scripts should have been executed during local deployment + Scenario: Doing a sample local deployment using a zipped_directory bundle + Given I have a sample local zipped_directory bundle + When I create a local deployment with my bundle + Then the local deployment command should succeed + And the expected files should have have been locally deployed to my host + And the scripts should have been executed during local deployment + Scenario: Doing a sample local deployment using a tgz bundle Given I have a sample local tgz bundle When I create a local deployment with my bundle diff --git a/features/step_definitions/codedeploy_local_steps.rb b/features/step_definitions/codedeploy_local_steps.rb index d12d2410..0985ef2b 100644 --- a/features/step_definitions/codedeploy_local_steps.rb +++ b/features/step_definitions/codedeploy_local_steps.rb @@ -21,7 +21,7 @@ FileUtils.rm_rf(@test_directory) unless @test_directory.nil? end -Given(/^I have a sample local (tgz|tar|zip|directory|relative_directory|custom_event_directory|directory_with_destination_files) bundle$/) do |bundle_type| +Given(/^I have a sample local (tgz|tar|zip|zipped_directory|directory|relative_directory|custom_event_directory|directory_with_destination_files) bundle$/) do |bundle_type| case bundle_type when 'custom_event_directory' @bundle_original_directory_location = StepConstants::SAMPLE_CUSTOM_EVENT_APP_BUNDLE_FULL_PATH @@ -32,13 +32,15 @@ end expect(File.directory?(@bundle_original_directory_location)).to be true - @bundle_type = bundle_type.include?('directory') ? 'directory' : bundle_type + @bundle_type = bundle_type.include?('zip') ? 'zip' : (bundle_type.include?('directory') ? 'directory' : bundle_type) case bundle_type when 'relative_directory' @bundle_location = Pathname.new(@bundle_original_directory_location).relative_path_from Pathname.getwd when 'zip' @bundle_location = zip_app_bundle(@test_directory) + when 'zipped_directory' + @bundle_location = zip_app_dir_bundle(@test_directory) when 'tar' @bundle_location = tar_app_bundle(@test_directory) when 'tgz' @@ -50,6 +52,19 @@ expect(File.file?(@bundle_location)).to be true unless bundle_type.include? 'directory' end +# Create a zip of the bundle with a nested directory containing the actual bundle files +def zip_app_dir_bundle(temp_directory_to_create_bundle) + zip_file_name = "#{temp_directory_to_create_bundle}/app_dir_bundle.zip" + Dir.mktmpdir { |zip_build_dir| + # Copy the bundle files into a temporary directory so we can just zip the sample bundle + FileUtils.cp_r(StepConstants::SAMPLE_APP_BUNDLE_FULL_PATH, zip_build_dir) + zip_directory(zip_build_dir, zip_file_name) + } + # Confirm appspec.yml is not at top level + Zip::File.open(zip_file_name) { |zip| expect(zip.entries.map(&:name).include? "appspec.yml").to be false } + zip_file_name +end + def tar_app_bundle(temp_directory_to_create_bundle) tar_file_name = "#{temp_directory_to_create_bundle}/app_bundle.tar" old_direcory = Dir.pwd diff --git a/lib/instance_agent/plugins/codedeploy/command_executor.rb b/lib/instance_agent/plugins/codedeploy/command_executor.rb index b8587e24..a97a58be 100644 --- a/lib/instance_agent/plugins/codedeploy/command_executor.rb +++ b/lib/instance_agent/plugins/codedeploy/command_executor.rb @@ -374,16 +374,7 @@ def handle_local_directory(deployment_spec, local_location) private def unpack_bundle(cmd, bundle_file, deployment_spec) - strip_leading_directory = deployment_spec.revision_source == 'GitHub' - - if strip_leading_directory - # Extract to a temporary directory first so we can move the files around - dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive-temp') - actual_dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive') - FileUtils.rm_rf(dst) - else - dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive') - end + dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive') if "tar".eql? deployment_spec.bundle_type InstanceAgent::Platform.util.extract_tar(bundle_file, dst) @@ -407,26 +398,27 @@ def unpack_bundle(cmd, bundle_file, deployment_spec) InstanceAgent::Platform.util.extract_tar(bundle_file, dst) end - if strip_leading_directory - log(:info, "Stripping leading directory from archive bundle contents.") - - # Find leading directory to remove - archive_root_files = Dir.entries(dst) - archive_root_files.delete_if { |name| name == '.' || name == '..' } + archive_root_files = Dir.entries(dst) + archive_root_files.delete_if { |name| name == '.' || name == '..' } - if (archive_root_files.size != 1) - log(:warn, "Expected archive to have a single root directory containing the actual bundle root, but it had #{archive_root_files.size} entries instead. Skipping leading directory removal and using archive as is.") - FileUtils.mv(dst, actual_dst) - return - end - - nested_archive_root = File.join(dst, archive_root_files[0]) - log(:debug, "Actual archive root at #{nested_archive_root}. Moving to #{actual_dst}") - - FileUtils.mv(nested_archive_root, actual_dst) - FileUtils.rmdir(dst) - - log(:debug, Dir.entries(actual_dst).join("; ")) + # If the top level of the archive is a directory that contains an appspec, + # strip that before giving up + if ((archive_root_files.size == 1) && + File.directory?(File.join(dst, archive_root_files[0])) && + Dir.entries(File.join(dst, archive_root_files[0])).grep(/appspec/i).any?) + log(:info, "Stripping leading directory from archive bundle contents.") + # Move the unpacked files to a temporary location + tmp_dst = File.join(deployment_root_dir(deployment_spec), 'deployment-archive-temp') + FileUtils.rm_rf(tmp_dst) + FileUtils.mv(dst, tmp_dst) + + # Move the top level directory to the intended location + nested_archive_root = File.join(tmp_dst, archive_root_files[0]) + log(:debug, "Actual archive root at #{nested_archive_root}. Moving to #{dst}") + FileUtils.mv(nested_archive_root, dst) + FileUtils.rmdir(tmp_dst) + + log(:debug, Dir.entries(dst).join("; ")) end end