diff --git a/Library/Homebrew/utils/shared_audits.rb b/Library/Homebrew/utils/shared_audits.rb index 923245645a849b..7c9cf36b51597a 100644 --- a/Library/Homebrew/utils/shared_audits.rb +++ b/Library/Homebrew/utils/shared_audits.rb @@ -92,6 +92,48 @@ def gitlab_release(user, repo, tag, formula: nil, cask: nil) "#{tag} is a GitLab pre-release." end + def codeberg_repo_data(user, repo) + @codeberg_repo_data ||= {} + @codeberg_repo_data["#{user}/#{repo}"] ||= begin + out, _, status = Utils::Curl.curl_output("https://codeberg.org/api/v1/repos/#{user}%2F#{repo}") + json = JSON.parse(out) if status.success? + json = nil if json&.dig("message")&.include?("404 Project Not Found") + json + end + end + + def codeberg_release_data(user, repo, tag) + id = "#{user}/#{repo}/#{tag}" + @codeberg_release_data ||= {} + @codeberg_release_data[id] ||= begin + out, _, status = Utils::Curl.curl_output( + "https://codeberg.org/api/v1/repos/#{user}%2F#{repo}/releases/tags/#{tag}", "--fail" + ) + JSON.parse(out) if status.success? + end + end + + def codeberg_release(user, repo, tag, formula: nil, cask: nil) + release = codeberg_release_data(user, repo, tag) + return unless release + + return if DateTime.parse(release["released_at"]) <= DateTime.now + + exception, name, version = if formula + [formula.tap&.audit_exception(:codeberg_prerelease_allowlist, formula.name), formula.name, formula.version] + elsif cask + [cask.tap&.audit_exception(:codeberg_prerelease_allowlist, cask.token), cask.token, cask.version] + end + + return "#{tag} is a GitHub pre-release." if release["prerelease"] && [version, "all"].exclude?(exception) + + if !release["prerelease"] && exception + return "#{tag} is not a GitHub pre-release but '#{name}' is in the GitHub prerelease allowlist." + end + + return "#{tag} is a Codeberg draft." if release["draft"] + end + def github(user, repo) metadata = github_repo_data(user, repo) @@ -124,6 +166,21 @@ def gitlab(user, repo) "GitLab repository too new (<30 days old)" end + def codeberg(user, repo) + metadata = codeberg_repo_data(user, repo) + + return if metadata.nil? + + return "Codeberg fork (not canonical repository)" if metadata["fork"] + if (metadata["forks_count"] < 30) && (metadata["stars_count"] < 75) + return "Codeberg repository not notable enough (<30 forks and <75 stars)" + end + + return if Date.parse(metadata["created_at"]) <= (Date.today - 30) + + "Codeberg repository too new (<30 days old)" + end + def bitbucket(user, repo) api_url = "https://api.bitbucket.org/2.0/repositories/#{user}/#{repo}" out, _, status = Utils::Curl.curl_output("--request", "GET", api_url) @@ -172,4 +229,11 @@ def gitlab_tag_from_url(url) .to_a .second end + + def codeberg_tag_from_url(url) + url = url.to_s + url.match(%r{^https://codeberg\.org/[\w-]+/[\w-]+/-/archive/([^/]+)/}) + .to_a + .second + end end