Files
opencode-compat/scripts/promote_runtime_tuple.rb

105 lines
4.2 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
require "json"
require "optparse"
require_relative "../lib/opencode_compat/runtime_tuple_promoter"
root = File.expand_path("..", __dir__)
command = ARGV.shift
options = {
"evidence" => [],
"previous_evidence" => []
}
parser = OptionParser.new do |opts|
opts.banner = <<~USAGE
Usage:
ruby scripts/promote_runtime_tuple.rb fingerprint --consumer NAME --consumer-commit SHA
ruby scripts/promote_runtime_tuple.rb promote --consumer NAME --consumer-commit SHA \\
--status pass --certified-at TIMESTAMP --evidence evidence/FILE.json \\
[--previous-status pass --previous-certified-at TIMESTAMP \\
--previous-evidence evidence/FILE.json] [--dry-run]
USAGE
opts.on("--consumer NAME") { |value| options["consumer"] = value }
opts.on("--consumer-commit SHA") { |value| options["consumer_commit"] = value }
opts.on("--status STATUS") { |value| options["status"] = value }
opts.on("--certified-at TIMESTAMP") { |value| options["certified_at"] = value }
opts.on("--evidence PATH") { |value| options["evidence"] << value }
opts.on("--previous-status STATUS") { |value| options["previous_status"] = value }
opts.on("--previous-certified-at TIMESTAMP") { |value| options["previous_certified_at"] = value }
opts.on("--previous-evidence PATH") { |value| options["previous_evidence"] << value }
opts.on("--dry-run") { options["dry_run"] = true }
end
def required!(options, *keys)
missing = keys.reject { |key| options[key] && (!options[key].respond_to?(:empty?) || !options[key].empty?) }
raise OptionParser::MissingArgument, missing.join(", ") unless missing.empty?
end
begin
parser.parse!(ARGV)
raise OptionParser::InvalidArgument, "unexpected arguments: #{ARGV.join(' ')}" unless ARGV.empty?
promoter = OpenCodeCompat::RuntimeTuplePromoter.new(root: root)
case command
when "fingerprint"
required!(options, "consumer", "consumer_commit")
puts JSON.pretty_generate(
promoter.fingerprints(
consumer: options.fetch("consumer"),
consumer_commit: options.fetch("consumer_commit")
)
)
when "promote"
required!(options, "consumer", "consumer_commit", "status", "certified_at", "evidence")
previous_fields = %w[previous_status previous_certified_at previous_evidence]
supplied_previous_fields = previous_fields.select do |key|
value = options[key]
value && (!value.respond_to?(:empty?) || !value.empty?)
end
if supplied_previous_fields.any? && supplied_previous_fields.length != previous_fields.length
raise OptionParser::MissingArgument, (previous_fields - supplied_previous_fields).join(", ")
end
previous_certification = if supplied_previous_fields.empty?
nil
else
{
"status" => options.fetch("previous_status"),
"certified_at" => options.fetch("previous_certified_at"),
"evidence" => options.fetch("previous_evidence")
}
end
promoted = promoter.promote(
consumer: options.fetch("consumer"),
consumer_commit: options.fetch("consumer_commit"),
certification: {
"status" => options.fetch("status"),
"certified_at" => options.fetch("certified_at"),
"evidence" => options.fetch("evidence")
},
previous_certification: previous_certification,
dry_run: options.fetch("dry_run", false)
)
if options.fetch("dry_run", false)
puts JSON.pretty_generate(promoted)
else
current = promoted.fetch("consumers").fetch(options.fetch("consumer")).fetch("current")
puts JSON.pretty_generate(
"consumer" => options.fetch("consumer"),
"current_consumer_commit" => current.fetch("consumer_commit"),
"current_tuple_sha256" => current.dig("certification", "tuple_sha256"),
"migration_state" => promoted.fetch("migration_state")
)
end
else
raise OptionParser::InvalidArgument, "command must be fingerprint or promote"
end
rescue OpenCodeCompat::PromotionError, OptionParser::ParseError => e
warn "error: #{e.message}"
warn parser
exit 1
end