Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tap_auditor: validate pypi_formula_mappings.json #16800

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions Library/Homebrew/Gemfile
Expand Up @@ -30,9 +30,6 @@ end
group :man, optional: true do
gem "kramdown", require: false
end
group :pr_upload, optional: true do
gem "json_schemer", require: false
end
group :prof, optional: true do
gem "ruby-prof", require: false
gem "stackprof", require: false
Expand Down Expand Up @@ -70,6 +67,9 @@ end
group :audit, :bump_unversioned_casks, :livecheck, optional: true do
gem "rexml", require: false
end
group :audit, :pr_upload, optional: true do
gem "json_schemer", require: false
end

# vendored gems (no group)
gem "addressable"
Expand Down
55 changes: 55 additions & 0 deletions Library/Homebrew/data/schemas/pypi_formula_mappings.schema.json
@@ -0,0 +1,55 @@
{
"$id": "https://brew.sh/pypi_formula_mappings.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "pypi_formula_mappings",
"type": "object",
"additionalProperties": {
"oneOf": [
{ "$ref": "#/$defs/package_name" },
{
"type": "object",
"properties": {
"package_name": {
"description": "Normalized PyPI package name with optional extras or empty string to skip main package",
"type": "string",
"oneOf": [
{ "$ref": "#/$defs/package_name" },
{ "maxLength": 0 }
]
},
"exclude_packages": {
"description": "PyPI packages to exclude from result",
"type": "array",
"items": { "$ref": "#/$defs/package_name" },
"minItems": 1
},
"extra_packages": {
"description": "PyPI packages to include with result",
"type": "array",
"items": { "$ref": "#/$defs/requirement_specifier" },
"minItems": 1
},
"dependencies": {
"description": "Formulae that need to be installed to resolve PyPI packages",
"type": "array",
"items": { "type":"string" },
"minItems": 1
}
},
"additionalProperties": false
}
]
},
"$defs": {
"package_name": {
"description": "Normalized PyPI package name with optional extras",
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*(\\[[a-z0-9][a-z0-9-]*(,[a-z0-9][a-z0-9-]*)*\\])?$"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a simplification of https://packaging.python.org/en/latest/specifications/name-normalization/. It doesn't handle trailing - or consecutive - as those make the regex messier.

},
"requirement_specifier": {
"description": "Normalized PyPI package name with optional extras and optional pinned version",
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]*(\\[[a-z0-9][a-z0-9-]*(,[a-z0-9][a-z0-9-]*)*\\])?(==.*)?$"
}
}
}
16 changes: 16 additions & 0 deletions Library/Homebrew/tap_auditor.rb
Expand Up @@ -47,13 +47,29 @@ def audit_json_files
rescue JSON::ParserError
problem "#{file.to_s.delete_prefix("#{@path}/")} contains invalid JSON"
end

require "json_schemer"
schemer = JSONSchemer.schema(HOMEBREW_DATA_PATH/"schemas/pypi_formula_mappings.schema.json")
return if schemer.valid?(@tap_pypi_formula_mappings)

problem <<~EOS
pypi_formula_mappings.json schema validation failed with following errors:
#{schemer.validate(@tap_pypi_formula_mappings).map { |error| "* #{error["error"]}" }.join("\n")}
EOS
end

sig { void }
def audit_tap_formula_lists
check_formula_list_directory "audit_exceptions", @tap_audit_exceptions
check_formula_list_directory "style_exceptions", @tap_style_exceptions
check_formula_list "pypi_formula_mappings", @tap_pypi_formula_mappings

@tap_pypi_formula_mappings.each_value do |formula_mapping|
next unless formula_mapping.is_a?(Hash)
next unless formula_mapping.key?("dependencies")

check_formula_list "pypi_formula_mappings", formula_mapping["dependencies"]
end
end

sig { void }
Expand Down