mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-13 08:06:41 +00:00
83 lines
3.5 KiB
Ruby
83 lines
3.5 KiB
Ruby
require 'base64'
|
|
require 'uri'
|
|
require_relative 'release-metadata'
|
|
|
|
# 所有发行线只推进 main 中已公开可下载的候选,保留备版字段
|
|
module PublishedChannels
|
|
PATH = 'release/version.yaml'
|
|
LIMIT = 8192
|
|
|
|
def self.advance(document, version)
|
|
version = ReleaseMetadata.version(version)
|
|
major, = version.split('.', 2)
|
|
core, stage = version.split('+', 2).first.split('-', 2)
|
|
channels = (document.fetch('published')[major] ||= {})
|
|
if stage&.start_with?('exp.')
|
|
channels = (channels['exp'] ||= {})
|
|
keys = [core]
|
|
else
|
|
stages = %w[stable rc beta alpha]
|
|
keys = stages.drop(stages.index(stage ? stage.split('.').first : 'stable'))
|
|
end
|
|
incoming = ReleaseMetadata.sort_key(version)
|
|
changed = false
|
|
keys.each do |key|
|
|
current = channels[key]
|
|
if current
|
|
comparison = incoming <=> ReleaseMetadata.sort_key(current)
|
|
raise "Conflicting release identities: #{current}, #{version}" if comparison.zero? && current != version
|
|
next unless comparison.positive?
|
|
end
|
|
channels[key] = version
|
|
changed = true
|
|
end
|
|
changed
|
|
end
|
|
|
|
def self.api(endpoint, payload = nil)
|
|
args = ['gh', 'api', endpoint]
|
|
args.concat(%w[--method PUT --input -]) if payload
|
|
out, error, status = Open3.capture3(*args, stdin_data: payload ? JSON.generate(payload) : '')
|
|
return :conflict if payload && !status.success? && error.include?('(HTTP 409)')
|
|
raise "Cannot access #{endpoint}: #{error.strip}" unless status.success?
|
|
JSON.parse(out)
|
|
end
|
|
|
|
def self.verify_assets(base, version, request)
|
|
tag = "v#{version}"
|
|
release = request.call("#{base}/releases/tags/#{tag}")
|
|
raise "Release is not public or tag identity differs: #{tag}" unless release.fetch('tag_name') == tag &&
|
|
!release.fetch('draft') && release.fetch('prerelease') == ReleaseMetadata.prerelease?(version)
|
|
platforms = request.call("#{base}/contents/release/platforms.yaml?ref=#{URI.encode_www_form_component(tag)}")
|
|
expected = YAML.safe_load(Base64.decode64(platforms.fetch('content'))).fetch('platforms').map do |p|
|
|
ReleaseMetadata.archive_name(version, p)
|
|
end
|
|
assets = release.fetch('assets').select { |a| a.fetch('state') == 'uploaded' && a.fetch('size').positive? }.map { |a| a.fetch('name') }
|
|
missing = (expected + %w[checksums.txt compose.yaml config.example.yaml plugin-release-manifest.json]) - assets
|
|
raise "Incomplete release #{tag}: #{missing.join(', ')}" if expected.empty? || !missing.empty?
|
|
end
|
|
|
|
def self.publish(repository, version, &request)
|
|
request ||= method(:api)
|
|
version = ReleaseMetadata.version(version)
|
|
base = "repos/#{repository}"
|
|
verify_assets(base, version, request)
|
|
endpoint = "#{base}/contents/#{PATH}"
|
|
3.times do
|
|
file = request.call("#{endpoint}?ref=main")
|
|
document = YAML.safe_load(Base64.decode64(file.fetch('content')))
|
|
return unless advance(document, version)
|
|
content = YAML.dump(document)
|
|
raise 'Published index exceeds the client size limit' if content.bytesize > LIMIT
|
|
written = request.call(endpoint, { branch: 'main', sha: file.fetch('sha'), content: Base64.strict_encode64(content),
|
|
message: "chore(release): publish channel index for v#{version}" })
|
|
return unless written == :conflict
|
|
end
|
|
raise 'main changed during channel publication; rerun the index step'
|
|
end
|
|
end
|
|
|
|
if $PROGRAM_NAME == __FILE__
|
|
PublishedChannels.publish(ENV.fetch('GITHUB_REPOSITORY'), ARGV.fetch(0))
|
|
end
|