class Dependabot::Uv::FileUpdater::PyprojectPreparer
def add_auth_env_vars(credentials)
For hosted Dependabot token will be nil since the credentials aren't present.
def add_auth_env_vars(credentials) TomlRB.parse(@pyproject_content).dig("tool", "poetry", "source")&.each do |source| cred = credentials&.find { |c| c["index-url"] == source["url"] } next unless cred token = cred.fetch("token", nil) next unless token && token.count(":") == 1 arr = token.split(":") # https://python-poetry.org/docs/configuration/#using-environment-variables name = source["name"]&.upcase&.gsub(/\W/, "_") ENV["POETRY_HTTP_BASIC_#{name}_USERNAME"] = arr[0] ENV["POETRY_HTTP_BASIC_#{name}_PASSWORD"] = arr[1] end end
def freeze_top_level_dependencies_except(dependencies)
rubocop:disable Metrics/PerceivedComplexity
def freeze_top_level_dependencies_except(dependencies) return pyproject_content unless lockfile pyproject_object = TomlRB.parse(pyproject_content) poetry_object = pyproject_object["tool"]["poetry"] excluded_names = dependencies.map(&:name) + ["python"] Dependabot::Uv::FileParser::PyprojectFilesParser::POETRY_DEPENDENCY_TYPES.each do |key| next unless poetry_object[key] source_types = %w(directory file url) poetry_object.fetch(key).each do |dep_name, _| next if excluded_names.include?(normalise(dep_name)) locked_details = locked_details(dep_name) next unless (locked_version = locked_details&.fetch("version")) next if source_types.include?(locked_details&.dig("source", "type")) if locked_details&.dig("source", "type") == "git" poetry_object[key][dep_name] = { "git" => locked_details&.dig("source", "url"), "rev" => locked_details&.dig("source", "reference") } subdirectory = locked_details&.dig("source", "subdirectory") poetry_object[key][dep_name]["subdirectory"] = subdirectory if subdirectory elsif poetry_object[key][dep_name].is_a?(Hash) poetry_object[key][dep_name]["version"] = locked_version elsif poetry_object[key][dep_name].is_a?(Array) # if it has multiple-constraints, locking to a single version is # going to result in a bad lockfile, ignore next else poetry_object[key][dep_name] = locked_version end end end TomlRB.dump(pyproject_object) end
def initialize(pyproject_content:, lockfile: nil)
def initialize(pyproject_content:, lockfile: nil) @pyproject_content = pyproject_content @lockfile = lockfile end
def locked_details(dep_name)
def locked_details(dep_name) parsed_lockfile.fetch("package") .find { |d| d["name"] == normalise(dep_name) } end
def normalise(name)
def normalise(name) NameNormaliser.normalise(name) end
def parsed_lockfile
def parsed_lockfile @parsed_lockfile ||= TomlRB.parse(lockfile.content) end
def sanitize
def sanitize # {{ name }} syntax not allowed pyproject_content .gsub(/\{\{.*?\}\}/, "something") .gsub('#{', "{") end
def update_python_requirement(requirement)
def update_python_requirement(requirement) pyproject_object = TomlRB.parse(@pyproject_content) if (python_specification = pyproject_object.dig("tool", "poetry", "dependencies", "python")) python_req = Uv::Requirement.new(python_specification) unless python_req.satisfied_by?(requirement) pyproject_object["tool"]["poetry"]["dependencies"]["python"] = "~#{requirement}" end end TomlRB.dump(pyproject_object) end