module GemChecksums
def generate(git_dry_run: false)
-
(void)
-
Parameters:
-
git_dry_run
(Boolean
) -- when true, perform a dry-run and do not leave files staged
def generate(git_dry_run: false) git_dry_run_flag = (git_dry_run || GIT_DRY_RUN_ENV) ? "--dry-run" : nil warn("Will run git commit with --dry-run") if git_dry_run_flag # Header: identify the gem and version being run begin puts "[ stone_checksums #{::StoneChecksums::Version::VERSION} ]" rescue StandardError # If for any reason the version constant isn't available, skip header gracefully end # Bundler version gate for reproducibility requirements bundler_ver = Gem::Version.new(Bundler::VERSION) requires_epoch = bundler_ver < Gem::Version.new("2.7.0") if requires_epoch # For older bundler, ask the user whether to proceed, or quit to update. proceed = ENV.fetch("GEM_CHECKSUMS_ASSUME_YES", "").casecmp("true").zero? unless proceed # Non-interactive prompt: advise and abort prompt_msg = <<~PROMPT Detected Bundler #{bundler_ver || "(unknown)"} which is older than 2.7.0. For reproducible builds without SOURCE_DATE_EPOCH, please update Bundler to >= 2.7.0. If you still want to proceed with this older Bundler, you must set SOURCE_DATE_EPOCH and re-run. Tip: set GEM_CHECKSUMS_ASSUME_YES=true to proceed non-interactively (still requires SOURCE_DATE_EPOCH). PROMPT warn(prompt_msg) # Continue to enforce SOURCE_DATE_EPOCH below; if not set, this will raise. end build_time = ENV.fetch("SOURCE_DATE_EPOCH", "") build_time_missing = !(build_time =~ /\d{10,}/) if build_time_missing warn(BUILD_TIME_WARNING) raise Error, BUILD_TIME_ERROR_MESSAGE end end gem_path_parts = case RUNNING_AS when "rake", "gem_checksums" first_arg = ARGV.first first_arg.respond_to?(:split) ? first_arg.split("/") : [] else # e.g. "rspec" [] end if gem_path_parts.any? gem_name = gem_path_parts.last gem_pkg = File.join(gem_path_parts) puts "Looking for: #{gem_pkg.inspect}" gems = Dir[gem_pkg] raise Error, "Unable to find gem #{gem_pkg}" if gems.empty? puts "Found: #{gems.inspect}" else gem_pkgs = File.join(PACKAGE_DIR, "*.gem") puts "Looking for: #{gem_pkgs.inspect}" gems = Dir[gem_pkgs] raise Error, "Unable to find gems #{gem_pkgs}" if gems.empty? # Sort by newest last # [ "my_gem-2.3.9.gem", "my_gem-2.3.11.pre.alpha.4.gem", "my_gem-2.3.15.gem", ... ] gems.sort_by! { |gem| Gem::Version.new(gem[VERSION_REGEX]) } gem_pkg = gems.last gem_path_parts = gem_pkg.split("/") gem_name = gem_path_parts.last puts "Found: #{gems.length} gems; latest is #{gem_name}" end pkg_bits = File.read(gem_pkg) # SHA-512 digest is 8 64-bit words digest512_64bit = Digest::SHA512.new.hexdigest(pkg_bits) digest512_64bit_path = "#{CHECKSUMS_DIR}/#{gem_name}.sha512" Dir.mkdir(CHECKSUMS_DIR) unless Dir.exist?(CHECKSUMS_DIR) File.write(digest512_64bit_path, digest512_64bit) # SHA-256 digest is 8 32-bit words digest256_32bit = Digest::SHA256.new.hexdigest(pkg_bits) digest256_32bit_path = "#{CHECKSUMS_DIR}/#{gem_name}.sha256" File.write(digest256_32bit_path, digest256_32bit) version = gem_name[VERSION_REGEX] git_cmd = <<~GIT_MSG.rstrip git add #{CHECKSUMS_DIR}/* && \ git commit #{git_dry_run_flag} -m "🔒️ Checksums for v#{version}" GIT_MSG if git_dry_run_flag git_cmd += <<~CLEANUP_MSG && \ echo "Cleaning up in dry run mode" && \ git reset #{digest512_64bit_path} && \ git reset #{digest256_32bit_path} && \ rm -f #{digest512_64bit_path} && \ rm -f #{digest256_32bit_path} CLEANUP_MSG end puts <<~RESULTS [ GEM: #{gem_name} ] [ VERSION: #{version} ] [ GEM PKG LOCATION: #{gem_pkg} ] [ CHECKSUM SHA-256: #{digest256_32bit} ] [ CHECKSUM SHA-512: #{digest512_64bit} ] [ CHECKSUM SHA-256 PATH: #{digest256_32bit_path} ] [ CHECKSUM SHA-512 PATH: #{digest512_64bit_path} ] ... Running ... #{git_cmd} RESULTS if git_dry_run_flag %x{#{git_cmd}} else # `exec` will replace the current process with the git process, and exit. # Within the generate method, Ruby code placed after the `exec` *will not be run*: # See: https://www.akshaykhot.com/call-shell-commands-in-ruby # But we can't exit the process when testing from RSpec, # since that would exit the parent RSpec process exec(git_cmd) end end
def install_tasks
-
(void)
-
def install_tasks load("gem_checksums/tasks.rb") end