lib/dependabot/uv/file_updater.rb
# typed: strict # frozen_string_literal: true require "toml-rb" require "dependabot/file_updaters" require "dependabot/file_updaters/base" require "dependabot/shared_helpers" require "sorbet-runtime" module Dependabot module Uv class FileUpdater < Dependabot::FileUpdaters::Base extend T::Sig require_relative "file_updater/compile_file_updater" require_relative "file_updater/lock_file_updater" require_relative "file_updater/requirement_file_updater" sig { override.returns(T::Array[Regexp]) } def self.updated_files_regex [ /^.*\.txt$/, # Match any .txt files (e.g., requirements.txt) at any level /^.*\.in$/, # Match any .in files at any level /^.*pyproject\.toml$/, # Match pyproject.toml at any level /^.*uv\.lock$/ # Match uv.lock at any level ] end sig { override.returns(T::Array[DependencyFile]) } def updated_dependency_files updated_files = updated_pip_compile_based_files updated_files += updated_uv_lock_files if updated_files.none? || updated_files.sort_by(&:name) == dependency_files.sort_by(&:name) raise "No files have changed!" end updated_files end private sig { returns(T.nilable(Symbol)) } def subdependency_resolver raise "Claimed to be a sub-dependency, but no lockfile exists!" if pip_compile_files.empty? :pip_compile if pip_compile_files.any? end sig { returns(T::Array[DependencyFile]) } def updated_pip_compile_based_files CompileFileUpdater.new( dependencies: dependencies, dependency_files: dependency_files, credentials: credentials, index_urls: pip_compile_index_urls ).updated_dependency_files end sig { returns(T::Array[DependencyFile]) } def updated_requirement_based_files RequirementFileUpdater.new( dependencies: dependencies, dependency_files: dependency_files, credentials: credentials, index_urls: pip_compile_index_urls ).updated_dependency_files end sig { returns(T::Array[DependencyFile]) } def updated_uv_lock_files LockFileUpdater.new( dependencies: dependencies, dependency_files: dependency_files, credentials: credentials, index_urls: pip_compile_index_urls ).updated_dependency_files end sig { returns(T::Array[String]) } def pip_compile_index_urls if credentials.any?(&:replaces_base?) credentials.select(&:replaces_base?).map { |cred| AuthedUrlBuilder.authed_url(credential: cred) } else urls = credentials.map { |cred| AuthedUrlBuilder.authed_url(credential: cred) } # If there are no credentials that replace the base, we need to # ensure that the base URL is included in the list of extra-index-urls. [nil, *urls] end end sig { override.void } def check_required_files filenames = dependency_files.map(&:name) return if filenames.any? { |name| name.end_with?(".txt", ".in") } return if pyproject raise "Missing required files!" end sig { returns(T.nilable(Dependabot::DependencyFile)) } def pyproject @pyproject ||= T.let(get_original_file("pyproject.toml"), T.nilable(Dependabot::DependencyFile)) end sig { returns(T::Array[DependencyFile]) } def pip_compile_files @pip_compile_files ||= T.let( dependency_files.select { |f| f.name.end_with?(".in") }, T.nilable(T::Array[DependencyFile]) ) end end end end Dependabot::FileUpdaters.register("uv", Dependabot::Uv::FileUpdater)