Skip to content

Commit fc4033e

Browse files
committed
github_packages: Bump to Sorbet typed: strict
1 parent 6664aa5 commit fc4033e

File tree

1 file changed

+51
-14
lines changed

1 file changed

+51
-14
lines changed

Library/Homebrew/github_packages.rb

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# typed: true # rubocop:todo Sorbet/StrictSigil
1+
# typed: strict
22
# frozen_string_literal: true
33

44
require "utils/curl"
@@ -16,8 +16,8 @@ class GitHubPackages
1616
include Utils::Output::Mixin
1717

1818
URL_DOMAIN = "ghcr.io"
19-
URL_PREFIX = "https://#{URL_DOMAIN}/v2/".freeze
20-
DOCKER_PREFIX = "docker://#{URL_DOMAIN}/".freeze
19+
URL_PREFIX = T.let("https://#{URL_DOMAIN}/v2/".freeze, String)
20+
DOCKER_PREFIX = T.let("docker://#{URL_DOMAIN}/".freeze, String)
2121
public_constant :URL_DOMAIN
2222
private_constant :URL_PREFIX
2323
private_constant :DOCKER_PREFIX
@@ -30,16 +30,22 @@ class GitHubPackages
3030
INVALID_OCI_TAG_CHARS_REGEX = /[^a-zA-Z0-9._-]/
3131

3232
# Translate Homebrew tab.arch to OCI platform.architecture
33-
TAB_ARCH_TO_PLATFORM_ARCHITECTURE = {
34-
"arm64" => "arm64",
35-
"x86_64" => "amd64",
36-
}.freeze
33+
TAB_ARCH_TO_PLATFORM_ARCHITECTURE = T.let(
34+
{
35+
"arm64" => "arm64",
36+
"x86_64" => "amd64",
37+
}.freeze,
38+
T::Hash[String, String],
39+
)
3740

3841
# Translate Homebrew built_on.os to OCI platform.os
39-
BUILT_ON_OS_TO_PLATFORM_OS = {
40-
"Linux" => "linux",
41-
"Macintosh" => "darwin",
42-
}.freeze
42+
BUILT_ON_OS_TO_PLATFORM_OS = T.let(
43+
{
44+
"Linux" => "linux",
45+
"Macintosh" => "darwin",
46+
}.freeze,
47+
T::Hash[String, String],
48+
)
4349

4450
sig {
4551
params(
@@ -79,6 +85,7 @@ def upload_bottles(bottles_hash, keep_old:, dry_run:, warn_on_error:)
7985
# rubocop:enable Style/CombinableLoops
8086
end
8187

88+
sig { params(version: String, rebuild: String, bottle_tag: T.nilable(String)).returns(String) }
8289
def self.version_rebuild(version, rebuild, bottle_tag = nil)
8390
bottle_tag = (".#{bottle_tag}" if bottle_tag.present?)
8491

@@ -93,18 +100,21 @@ def self.version_rebuild(version, rebuild, bottle_tag = nil)
93100
"#{version}#{bottle_tag}#{rebuild}"
94101
end
95102

103+
sig { params(repo: String).returns(String) }
96104
def self.repo_without_prefix(repo)
97105
# Remove redundant repository prefix for a shorter name.
98106
repo.delete_prefix("homebrew-")
99107
end
100108

109+
sig { params(org: String, repo: String, prefix: String).returns(String) }
101110
def self.root_url(org, repo, prefix = URL_PREFIX)
102111
# `docker`/`skopeo` insist on lowercase organisation (“repository name”).
103112
org = org.downcase
104113

105114
"#{prefix}#{org}/#{repo_without_prefix(repo)}"
106115
end
107116

117+
sig { params(url: T.nilable(String)).returns(T.nilable(String)) }
108118
def self.root_url_if_match(url)
109119
return if url.blank?
110120

@@ -114,6 +124,7 @@ def self.root_url_if_match(url)
114124
root_url(org, repo)
115125
end
116126

127+
sig { params(formula_name: String).returns(String) }
117128
def self.image_formula_name(formula_name)
118129
# Invalid docker name characters:
119130
# - `/` makes sense because we already use it to separate repository/formula.
@@ -122,6 +133,7 @@ def self.image_formula_name(formula_name)
122133
.tr("+", "x")
123134
end
124135

136+
sig { params(version_rebuild: String).returns(String) }
125137
def self.image_version_rebuild(version_rebuild)
126138
unless version_rebuild.match?(VALID_OCI_TAG_REGEX)
127139
raise ArgumentError, "GitHub Packages versions must match #{VALID_OCI_TAG_REGEX.source}!"
@@ -141,6 +153,7 @@ def self.image_version_rebuild(version_rebuild)
141153
private_constant :IMAGE_CONFIG_SCHEMA_URI, :IMAGE_INDEX_SCHEMA_URI, :IMAGE_LAYOUT_SCHEMA_URI,
142154
:IMAGE_MANIFEST_SCHEMA_URI, :GITHUB_PACKAGE_TYPE
143155

156+
sig { void }
144157
def load_schemas!
145158
schema_uri("content-descriptor",
146159
"https://opencontainers.org/schema/image/content-descriptor.json")
@@ -168,6 +181,7 @@ def load_schemas!
168181
schema_uri("image-manifest-schema", IMAGE_MANIFEST_SCHEMA_URI)
169182
end
170183

184+
sig { params(basename: String, uris: T.any(String, T::Array[String])).void }
171185
def schema_uri(basename, uris)
172186
# The current `main` version has an invalid JSON schema.
173187
# Going forward, this should probably be pinned to tags.
@@ -176,18 +190,20 @@ def schema_uri(basename, uris)
176190
out = Utils::Curl.curl_output(url).stdout
177191
json = JSON.parse(out)
178192

179-
@schema_json ||= {}
193+
@schema_json ||= T.let({}, T.nilable(T::Hash[String, T::Hash[String, T.untyped]]))
180194
Array(uris).each do |uri|
181195
@schema_json[uri] = json
182196
end
183197
end
184198

199+
sig { params(uri: URI::Generic).returns(T.nilable(T::Hash[String, T.untyped])) }
185200
def schema_resolver(uri)
186-
@schema_json[uri.to_s.gsub(/#.*/, "")]
201+
@schema_json&.fetch(uri.to_s.gsub(/#.*/, ""))
187202
end
188203

204+
sig { params(schema_uri: String, json: T::Hash[String, T.untyped]).void }
189205
def validate_schema!(schema_uri, json)
190-
schema = JSONSchemer.schema(@schema_json[schema_uri], ref_resolver: method(:schema_resolver))
206+
schema = JSONSchemer.schema(@schema_json&.fetch(schema_uri), ref_resolver: method(:schema_resolver))
191207
json = json.deep_stringify_keys
192208
return if schema.valid?(json)
193209

@@ -200,6 +216,7 @@ def validate_schema!(schema_uri, json)
200216
exit 1
201217
end
202218

219+
sig { params(user: String, token: String, skopeo: Pathname, image_uri: String, root: Pathname, dry_run: T::Boolean).void }
203220
def download(user, token, skopeo, image_uri, root, dry_run:)
204221
puts
205222
args = ["copy", "--all", image_uri.to_s, "oci:#{root}"]
@@ -211,6 +228,14 @@ def download(user, token, skopeo, image_uri, root, dry_run:)
211228
end
212229
end
213230

231+
sig {
232+
params(
233+
user: String, token: String, skopeo: Pathname, _formula_full_name: String,
234+
bottle_hash: T::Hash[String, T.untyped], keep_old: T::Boolean, dry_run: T::Boolean, warn_on_error: T::Boolean
235+
).returns(
236+
T.nilable([String, String, String, String, String, String, String, String, T::Boolean]),
237+
)
238+
}
214239
def preupload_check(user, token, skopeo, _formula_full_name, bottle_hash, keep_old:, dry_run:, warn_on_error:)
215240
formula_name = bottle_hash["formula"]["name"]
216241

@@ -260,6 +285,12 @@ def preupload_check(user, token, skopeo, _formula_full_name, bottle_hash, keep_o
260285
[formula_name, org, repo, version, rebuild, version_rebuild, image_name, image_uri, keep_old]
261286
end
262287

288+
sig {
289+
params(
290+
user: String, token: String, skopeo: Pathname, formula_full_name: String,
291+
bottle_hash: T::Hash[String, T.untyped], keep_old: T::Boolean, dry_run: T::Boolean, warn_on_error: T::Boolean
292+
).void
293+
}
263294
def upload_bottle(user, token, skopeo, formula_full_name, bottle_hash, keep_old:, dry_run:, warn_on_error:)
264295
# We run the preupload check twice to prevent TOCTOU bugs.
265296
result = preupload_check(user, token, skopeo, formula_full_name, bottle_hash,
@@ -479,19 +510,22 @@ def upload_bottle(user, token, skopeo, formula_full_name, bottle_hash, keep_old:
479510
end
480511
end
481512

513+
sig { params(root: Pathname).returns([String, Integer]) }
482514
def write_image_layout(root)
483515
image_layout = { imageLayoutVersion: "1.0.0" }
484516
validate_schema!(IMAGE_LAYOUT_SCHEMA_URI, image_layout)
485517
write_hash(root, image_layout, "oci-layout")
486518
end
487519

520+
sig { params(local_file: String, blobs: Pathname).returns(String) }
488521
def write_tar_gz(local_file, blobs)
489522
tar_gz_sha256 = Digest::SHA256.file(local_file)
490523
.hexdigest
491524
FileUtils.ln local_file, blobs/tar_gz_sha256, force: true
492525
tar_gz_sha256
493526
end
494527

528+
sig { params(platform_hash: T::Hash[String, T.untyped], tar_sha256: String, blobs: Pathname).returns([String, Integer]) }
495529
def write_image_config(platform_hash, tar_sha256, blobs)
496530
image_config = platform_hash.merge({
497531
rootfs: {
@@ -503,6 +537,7 @@ def write_image_config(platform_hash, tar_sha256, blobs)
503537
write_hash(blobs, image_config)
504538
end
505539

540+
sig { params(manifests: T::Array[T::Hash[String, T.untyped]], blobs: Pathname, annotations: T::Hash[String, String]).returns([String, Integer]) }
506541
def write_image_index(manifests, blobs, annotations)
507542
image_index = {
508543
schemaVersion: 2,
@@ -513,6 +548,7 @@ def write_image_index(manifests, blobs, annotations)
513548
write_hash(blobs, image_index)
514549
end
515550

551+
sig { params(index_json_sha256: String, index_json_size: Integer, root: Pathname, annotations: T::Hash[String, String]).void }
516552
def write_index_json(index_json_sha256, index_json_size, root, annotations)
517553
index_json = {
518554
schemaVersion: 2,
@@ -527,6 +563,7 @@ def write_index_json(index_json_sha256, index_json_size, root, annotations)
527563
write_hash(root, index_json, "index.json")
528564
end
529565

566+
sig { params(directory: Pathname, hash: T::Hash[String, T.untyped], filename: T.nilable(String)).returns([String, Integer]) }
530567
def write_hash(directory, hash, filename = nil)
531568
json = JSON.pretty_generate(hash)
532569
sha256 = Digest::SHA256.hexdigest(json)

0 commit comments

Comments
 (0)