mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
130 lines
4.7 KiB
Ruby
130 lines
4.7 KiB
Ruby
require 'fileutils'
|
|
require 'json'
|
|
require 'open3'
|
|
require 'rubygems'
|
|
require 'time'
|
|
require 'yaml'
|
|
|
|
# 本地入口与发行工作流共用版本、说明和平台合同
|
|
module ReleaseMetadata
|
|
APP_NAME = 'codex-proxy-rs'
|
|
SEMVER = /\A(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:alpha|beta|rc|exp)\.[1-9]\d*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?\z/
|
|
|
|
def self.version(raw)
|
|
value = raw.delete_prefix('v')
|
|
raise "Invalid release version: #{raw}" unless value.match?(SEMVER)
|
|
value
|
|
end
|
|
|
|
def self.prerelease?(value)
|
|
version(value).split('+', 2).first.include?('-')
|
|
end
|
|
|
|
def self.sort_key(value)
|
|
Gem::Version.new(version(value).split('+', 2).first)
|
|
end
|
|
|
|
def self.validate_notes(value)
|
|
tag = "v#{version(value)}"
|
|
lines = File.readlines('release/notes.md')
|
|
unless lines.first&.strip == "# #{tag}" && !lines.drop(1).join.strip.empty?
|
|
raise "release/notes.md: expected non-empty notes starting with '# #{tag}'"
|
|
end
|
|
end
|
|
|
|
def self.git(*arguments)
|
|
output, status = Open3.capture2('git', *arguments)
|
|
raise "git #{arguments.join(' ')} failed" unless status.success?
|
|
output.strip
|
|
end
|
|
|
|
def self.platforms
|
|
entries = YAML.load_file('release/platforms.yaml').fetch('platforms')
|
|
raise 'release/platforms.yaml: platforms must be a non-empty array' unless entries.is_a?(Array) && !entries.empty?
|
|
seen = {}
|
|
entries.each do |entry|
|
|
raise 'Invalid release platform' unless entry.is_a?(Hash)
|
|
%w[os arch runner target binary archive].each do |key|
|
|
raise "Invalid platform #{key}" unless entry[key].is_a?(String) && !entry[key].strip.empty?
|
|
end
|
|
key = "#{entry['os']}-#{entry['arch']}"
|
|
raise "Duplicate release platform: #{key}" if seen[key]
|
|
seen[key] = true
|
|
raise "Unsupported archive: #{entry['archive']}" unless entry['archive'] == 'tar.gz'
|
|
if entry['docker'] == true
|
|
platform = entry['dockerPlatform']
|
|
raise "Missing Docker platform: #{key}" unless platform.is_a?(String) && !platform.strip.empty?
|
|
entry['dockerPlatform'] = platform.strip
|
|
end
|
|
entry['artifact'] = "#{APP_NAME}-#{key}"
|
|
end
|
|
raise 'At least one Docker platform is required' unless entries.any? { |entry| entry['docker'] == true }
|
|
entries
|
|
end
|
|
|
|
def self.outputs(tag)
|
|
value = version(YAML.load_file('release/version.yaml').fetch('version'))
|
|
raise "Release tag #{tag} does not match v#{value}" unless tag == "v#{value}"
|
|
validate_notes(value)
|
|
entries = platforms
|
|
docker, native = entries.partition { |entry| entry['docker'] == true }
|
|
previous = git('tag', '--list', 'v*', '--merged', 'HEAD').lines.map(&:strip).filter_map do |candidate|
|
|
next unless candidate.delete_prefix('v').match?(SEMVER)
|
|
key = sort_key(candidate)
|
|
[key, candidate] if key < sort_key(value)
|
|
end.max_by(&:first)&.last
|
|
{
|
|
'tag' => tag,
|
|
'version' => value,
|
|
'docker_version' => value.tr('+', '-'),
|
|
'build_time' => Time.now.utc.iso8601,
|
|
'git_sha' => git('rev-parse', 'HEAD'),
|
|
'platform_matrix' => JSON.generate('include' => entries),
|
|
'docker_matrix' => JSON.generate('include' => docker),
|
|
'non_docker_matrix' => JSON.generate('include' => native),
|
|
'docker_platforms' => docker.map { |entry| entry['dockerPlatform'] }.join(','),
|
|
'previous_tag' => previous,
|
|
'prerelease' => prerelease?(value),
|
|
'build_type' => value.split('+', 2).first.include?('-exp.') ? 'experimental' : 'release'
|
|
}
|
|
end
|
|
|
|
def self.seal_manifest(metadata)
|
|
path = 'backend/crates/gateway-plugin/runtime/plugin-host-compatibility.json'
|
|
host = JSON.parse(File.read(path))
|
|
raise "Invalid plugin host compatibility declaration: #{path}" unless host['schema_version'] == 2
|
|
manifest = {
|
|
'schema_version' => 1,
|
|
'sealed' => true,
|
|
'gateway_version' => metadata.fetch('version'),
|
|
'gateway_git_sha' => metadata.fetch('git_sha'),
|
|
'plugin_host' => host,
|
|
'plugins' => []
|
|
}
|
|
FileUtils.mkdir_p('dist/plugin-release-assets')
|
|
File.write('dist/plugin-release-assets/plugin-release-manifest.json', JSON.pretty_generate(manifest) + "\n")
|
|
end
|
|
end
|
|
|
|
if $PROGRAM_NAME == __FILE__
|
|
begin
|
|
command, value = ARGV
|
|
raise 'usage: release-metadata.rb validate VERSION | outputs TAG' unless ARGV.length == 2
|
|
case command
|
|
when 'validate'
|
|
value = ReleaseMetadata.version(value)
|
|
ReleaseMetadata.validate_notes(value)
|
|
puts value
|
|
when 'outputs'
|
|
metadata = ReleaseMetadata.outputs(value)
|
|
ReleaseMetadata.seal_manifest(metadata)
|
|
metadata.each { |key, entry| puts "#{key}=#{entry}" }
|
|
else
|
|
raise "Unknown command: #{command}"
|
|
end
|
|
rescue StandardError => error
|
|
warn "error: #{error.message}"
|
|
exit 1
|
|
end
|
|
end
|