lib/packaging/util/ship.rb in packaging-0.104.0 vs lib/packaging/util/ship.rb in packaging-0.105.0

- old
+ new

@@ -353,6 +353,153 @@ hosts_to_override.each do |host| ENV[host] = vm end Rake::Task[ship_task].invoke end + + # Ship pkg directory contents to distribution server + def ship(target = 'artifacts', local_directory = 'pkg') + Pkg::Util::File.fetch + + unless Pkg::Config.project + fail "You must set the 'project' in build_defaults.yaml or with the 'PROJECT_OVERRIDE' environment variable." + end + + project_basedir = "#{Pkg::Config.jenkins_repo_path}/#{Pkg::Config.project}/#{Pkg::Config.ref}" + artifact_directory = "#{project_basedir}/#{target}" + + # For EZBake builds, we also want to include the ezbake.manifest file to + # get a snapshot of this build and all dependencies. We eventually will + # create a yaml version of this file, but until that point we want to + # make the original ezbake.manifest available + # + ezbake_manifest = File.join('ext', 'ezbake.manifest') + if File.exist?(ezbake_manifest) + FileUtils.cp(ezbake_manifest, File.join(local_directory, "#{Pkg::Config.ref}.ezbake.manifest")) + end + ezbake_yaml = File.join("ext", "ezbake.manifest.yaml") + if File.exists?(ezbake_yaml) + FileUtils.cp(ezbake_yaml, File.join(local_directory, "#{Pkg::Config.ref}.ezbake.manifest.yaml")) + end + + # Inside build_metadata*.json files there is additional metadata containing + # information such as git ref and dependencies that are needed at build + # time. If these files exist, copy them downstream. + # Typically these files are named 'ext/build_metadata.<project>.<platform>.json' + build_metadata_json_files = Dir.glob('ext/build_metadata*.json') + build_metadata_json_files.each do |source_file| + target_file = File.join(local_directory, "#{Pkg::Config.ref}.#{File.basename(source_file)}") + FileUtils.cp(source_file, target_file) + end + + # Sadly, the packaging repo cannot yet act on its own, without living + # inside of a packaging-repo compatible project. This means in order to + # use the packaging repo for shipping and signing (things that really + # don't require build automation, specifically) we still need the project + # clone itself. + Pkg::Util::Git.bundle('HEAD', 'signing_bundle', local_directory) + + # While we're bundling things, let's also make a git bundle of the + # packaging repo that we're using when we invoke pl:jenkins:ship. We can + # have a reasonable level of confidence, later on, that the git bundle on + # the distribution server was, in fact, the git bundle used to create the + # associated packages. This is because this ship task is automatically + # called upon completion each cell of the pl:jenkins:uber_build, and we + # have --ignore-existing set below. As such, the only git bundle that + # should possibly be on the distribution is the one used to create the + # packages. + # We're bundling the packaging repo because it allows us to keep an + # archive of the packaging source that was used to create the packages, + # so that later on if we need to rebuild an older package to audit it or + # for some other reason we're assured that the new package isn't + # different by virtue of the packaging automation. + if defined?(PACKAGING_ROOT) + packaging_bundle = '' + Dir.chdir(PACKAGING_ROOT) do + packaging_bundle = Pkg::Util::Git.bundle('HEAD', 'packaging-bundle') + end + FileUtils.mv(packaging_bundle, local_directory) + end + + # This is functionality to add the project-arch.msi links that have no + # version. The code itself looks for the link (if it's there already) + # and if the source package exists before linking. Searching for the + # packages has been restricted specifically to just the pkg/windows dir + # on purpose, as this is where we currently have all windows packages + # building to. Once we move the Metadata about the output location in + # to one source of truth we can refactor this to use that to search + # -Sean P. M. 08/12/16 + + { + 'windows' => ['x86', 'x64'], + 'windowsfips' => ['x64'] + }.each_pair do |platform, archs| + packages = Dir["#{local_directory}/#{platform}/*"] + + archs.each do |arch| + package_version = Pkg::Util::Git.describe.tr('-', '.') + package_filename = File.join(local_directory, platform, "#{Pkg::Config.project}-#{package_version}-#{arch}.msi") + link_filename = File.join(local_directory, platform, "#{Pkg::Config.project}-#{arch}.msi") + + next unless !packages.include?(link_filename) && packages.include?(package_filename) + # Dear future code spelunkers: + # Using symlinks instead of hard links causes failures when we try + # to set these files to be immutable. Also be wary of whether the + # linking utility you're using expects the source path to be relative + # to the link target or pwd. + # + FileUtils.ln(package_filename, link_filename) + end + end + + Pkg::Util::Execution.retry_on_fail(times: 3) do + Pkg::Util::Net.remote_execute(Pkg::Config.distribution_server, "mkdir --mode=775 -p #{project_basedir}") + Pkg::Util::Net.remote_execute(Pkg::Config.distribution_server, "mkdir -p #{artifact_directory}") + Pkg::Util::Net.rsync_to("#{local_directory}/", Pkg::Config.distribution_server, "#{artifact_directory}/", extra_flags: ['--ignore-existing', '--exclude repo_configs']) + end + + # In order to get a snapshot of what this build looked like at the time + # of shipping, we also generate and ship the params file + # + Pkg::Config.config_to_yaml(local_directory) + Pkg::Util::Execution.retry_on_fail(:times => 3) do + Pkg::Util::Net.rsync_to("#{local_directory}/#{Pkg::Config.ref}.yaml", Pkg::Config.distribution_server, "#{artifact_directory}/", extra_flags: ["--exclude repo_configs"]) + end + + # If we just shipped a tagged version, we want to make it immutable + files = Dir.glob("#{local_directory}/**/*").select { |f| File.file?(f) and !f.include? "#{Pkg::Config.ref}.yaml" }.map do |file| + "#{artifact_directory}/#{file.sub(/^#{local_directory}\//, '')}" + end + + Pkg::Util::Net.remote_set_ownership(Pkg::Config.distribution_server, 'root', 'release', files) + Pkg::Util::Net.remote_set_permissions(Pkg::Config.distribution_server, '0664', files) + Pkg::Util::Net.remote_set_immutable(Pkg::Config.distribution_server, files) + end + + def ship_to_artifactory(local_directory = 'pkg') + Pkg::Util::File.fetch + unless Pkg::Config.project + fail "You must set the 'project' in build_defaults.yaml or with the 'PROJECT_OVERRIDE' environment variable." + end + artifactory = Pkg::ManageArtifactory.new(Pkg::Config.project, Pkg::Config.ref) + + artifacts = Dir.glob("#{local_directory}/**/*").reject { |e| File.directory? e } + artifacts.sort! do |a, b| + if File.extname(a) =~ /(md5|sha\d+)/ && File.extname(b) !~ /(md5|sha\d+)/ + 1 + elsif File.extname(b) =~ /(md5|sha\d+)/ && File.extname(a) !~ /(md5|sha\d+)/ + -1 + else + a <=> b + end + end + artifacts.each do |artifact| + if File.extname(artifact) == ".yaml" || File.extname(artifact) == ".json" + artifactory.deploy_package(artifact) + elsif artifactory.package_exists_on_artifactory?(artifact) + warn "Attempt to upload '#{artifact}' failed. Package already exists!" + else + artifactory.deploy_package(artifact) + end + end + end end