Skip to content

Commit

Permalink
Merge pull request #3008 from mbhall88/main
Browse files Browse the repository at this point in the history
feat: add crates.io as a source for auto version bump
  • Loading branch information
beckermr authored Sep 26, 2024
2 parents 8508dfb + 7ca7367 commit 7ea599e
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 0 deletions.
45 changes: 45 additions & 0 deletions conda_forge_tick/update_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import collections.abc
import copy
import functools
import json
import logging
import re
import subprocess
import typing
import urllib.parse
from pathlib import Path
from typing import Iterator, List, Optional

import feedparser
Expand Down Expand Up @@ -708,3 +710,46 @@ def get_url(self, meta_yaml) -> Optional[str]:

def get_version(self, url: str) -> Optional[str]:
return url # = next version, same as in BaseRawURL


class CratesIO(AbstractSource):
name = "CratesIO"

def get_url(self, meta_yaml) -> Optional[str]:
if "crates.io" not in meta_yaml["url"]:
return None

pkg = Path(meta_yaml["url"]).parts[5]
tier = self._tier_directory(pkg)

return f"https://index.crates.io/{tier}"

def get_version(self, url: str) -> Optional[str]:
r = requests.get(url)

if not r.ok:
return None

# the response body is a newline-delimited JSON stream, with the latest version
# being the last line
latest = json.loads(r.text.splitlines()[-1])

return latest.get("vers")

@staticmethod
def _tier_directory(package: str) -> str:
"""Depending on the length of the package name, the tier directory structure
will differ.
Documented here: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-files
"""
if not package:
raise ValueError("Package name cannot be empty")

name_len = len(package)

if name_len <= 2:
return f"{name_len}/{package}"
elif name_len == 3:
return f"{name_len}/{package[0]}/{package}"
else:
return f"{package[0:2]}/{package[2:4]}/{package}"
2 changes: 2 additions & 0 deletions conda_forge_tick/update_upstream_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
NPM,
NVIDIA,
AbstractSource,
CratesIO,
Github,
GithubReleases,
IncrementAlphaRawURL,
Expand Down Expand Up @@ -418,6 +419,7 @@ def all_version_sources():
return (
PyPI(),
CRAN(),
CratesIO(),
NPM(),
ROSDistro(),
RawURL(),
Expand Down
91 changes: 91 additions & 0 deletions tests/test_update_sources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from unittest.mock import Mock, patch

import pytest

from conda_forge_tick.update_sources import CratesIO


class TestCratesIOTierDirectory:
def test_four_or_more_characters(self):
pkg = "rasusa"

actual = CratesIO._tier_directory(pkg)
expected = "ra/su/rasusa"

assert actual == expected

def test_four_characters(self):
pkg = "psdm"

actual = CratesIO._tier_directory(pkg)
expected = "ps/dm/psdm"

assert actual == expected

def test_three_characters(self):
pkg = "syn"

actual = CratesIO._tier_directory(pkg)
expected = "3/s/syn"

assert actual == expected

def test_two_characters(self):
pkg = "it"

actual = CratesIO._tier_directory(pkg)
expected = "2/it"

assert actual == expected

def test_one_character(self):
pkg = "a"

actual = CratesIO._tier_directory(pkg)
expected = "1/a"

assert actual == expected

def test_empty_string(self):
pkg = ""

with pytest.raises(ValueError):
CratesIO._tier_directory(pkg)


class TestCratesIOGetVersion:
def test_valid_package(self):
# as far as I can tell, this package has not had a new version in the last 9
# years, so it should be safe to use for testing as we don't expect the version
# to change
pkg = "gopher"
tier = CratesIO._tier_directory(pkg)
url = f"https://index.crates.io/{tier}"

actual = CratesIO().get_version(url)
expected = "0.0.3"

assert actual == expected

def test_invalid_package(self):
pkg = "shdfbshbvjhbvhsbhsb"
tier = CratesIO._tier_directory(pkg)
url = f"https://index.crates.io/{tier}"

result = CratesIO().get_version(url)
assert result is None

@patch("conda_forge_tick.update_sources.requests.get")
def test_empty_package(self, mock_get):
pkg = "syn"
tier = CratesIO._tier_directory(pkg)
url = f"https://index.crates.io/{tier}"

# Mock response
mock_response = Mock()
mock_response.ok = True
mock_response.text = '{"name": "syn"}'
mock_get.return_value = mock_response

result = CratesIO().get_version(url)
assert result is None
36 changes: 36 additions & 0 deletions tests/test_upstream_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
NPM,
NVIDIA,
AbstractSource,
CratesIO,
Github,
GithubReleases,
PyPI,
Expand Down Expand Up @@ -1254,6 +1255,7 @@ def test_update_upstream_versions_no_packages_to_update(
default_sources = (
"PyPI",
"CRAN",
"CratesIO",
"NPM",
"ROSDistro",
"RawURL",
Expand Down Expand Up @@ -1718,3 +1720,37 @@ def test_github_releases(tmpdir, url, feedstock_version):
ghr = GithubReleases()
url = ghr.get_url(meta_yaml)
assert VersionOrder(ghr.get_version(url)) > VersionOrder(feedstock_version)


def test_latest_version_cratesio(tmpdir):
name = "wbg-rand"
recipe_path = os.path.join(YAML_PATH, "version_wbg-rand.yaml")
curr_ver = "0.4.0"
ver = "0.4.1"
source = CratesIO()

with open(recipe_path) as fd:
inp = fd.read()

pmy = LazyJson(os.path.join(str(tmpdir), "cf-scripts-test.json"))
with pmy as _pmy:
yml = parse_meta_yaml(inp)
_pmy.update(yml["source"])
_pmy.update(
{
"feedstock_name": name,
"version": curr_ver,
"raw_meta_yaml": inp,
"meta_yaml": yml,
},
)

attempt = get_latest_version(name, pmy, [source], use_container=False)
if ver is None:
assert attempt["new_version"] is not False
assert attempt["new_version"] != curr_ver
assert VersionOrder(attempt["new_version"]) > VersionOrder(curr_ver)
elif ver is False:
assert attempt["new_version"] is ver
else:
assert ver == attempt["new_version"]
37 changes: 37 additions & 0 deletions tests/test_yaml/version_wbg-rand.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package:
name: wbg-rand
version: "0.4.0"

source:
url: https://crates.io/api/v1/crates/wbg-rand/0.4.0/download
fn: "wbg-rand-0.4.0.tar.gz"
sha256: 5505e10cb191f56fed835c35baf4ac97b5466148a13fbcaeb1173198b1a52b4c

build:
number: 0
skip: true # [win]

requirements:
build:
- {{ compiler('rust') }}
- {{ compiler('c') }}
- {{ stdlib("c") }}
- cargo-bundle-licenses

test:
commands:
- echo "This is a placeholder for the test section"

about:
home: https://github.com/alexcrichton/wbg-rand
summary: 'Random numbers for wasm32-unknown-unknown in Rust'
description: |
Implementation of rand for wasm32-unknown-unknown in Rust using #[wasm_bindgen].
license: MIT AND Apache-2.0
license_file:
- LICENSE-MIT
- LICENSE-APACHE

extra:
recipe-maintainers:
- mbhall88

0 comments on commit 7ea599e

Please sign in to comment.