mirror of
https://github.com/lilydjwg/nvchecker.git
synced 2025-03-10 06:14:02 +00:00
Compare commits
82 commits
Author | SHA1 | Date | |
---|---|---|---|
|
fc8d90f46b | ||
|
e1882a2778 | ||
|
b83cbd2ead | ||
|
d4be5189fe | ||
|
cc9001ad88 | ||
|
fca89f7830 | ||
|
92a424f946 | ||
|
d3bf5b2db5 | ||
|
bd72ea04d2 | ||
|
50d5342586 | ||
|
1e3ed1e4b9 | ||
|
72c0730725 | ||
|
6759d2f206 | ||
|
17e351f825 | ||
|
d58638733e | ||
|
287282eb2c | ||
|
fa9ca38690 | ||
|
5c7918bf7a | ||
|
c03bec7452 | ||
|
7cacd9edaf | ||
|
af21f93bd1 | ||
|
ca011221cf | ||
|
745f0decdb | ||
|
6f5870787a | ||
|
4364759b29 | ||
|
dbf6c4601f | ||
|
4d5e29f26b | ||
|
ad892b713e | ||
|
5803237d39 | ||
|
71a0002624 | ||
|
2722ccc7fe | ||
|
228139ddd4 | ||
|
372fce4445 | ||
|
babb3aa74e | ||
|
d44a50c273 | ||
|
c0d6568434 | ||
|
2a64f7ab8f | ||
|
af1a855fd5 | ||
|
eeddd56156 | ||
|
29b0f63103 | ||
|
3a87f920a5 | ||
|
af7acde251 | ||
|
c7f571ae79 | ||
|
256bb9dd3b | ||
|
28f1ab5144 | ||
|
e1a6517169 | ||
|
afad2f08f2 | ||
|
5cead67640 | ||
|
728dcca1bd | ||
|
89b4cd90ba | ||
|
4eb70a0fbe | ||
|
8d3b6adaaa | ||
|
5b561456ae | ||
|
d5cc276000 | ||
|
3abe5ad394 | ||
|
e4cff0b507 | ||
|
d4e27c22ac | ||
|
7848f0907d | ||
|
a1ab77f92a | ||
|
5a3ca69c1c | ||
|
5677c9595e | ||
|
61ca3c95d0 | ||
|
1d55664b31 | ||
|
c66ca7f2bc | ||
|
2800f392d9 | ||
|
3cf403fc51 | ||
|
6af59aa2ae | ||
|
8397cbbce0 | ||
|
d49d07437b | ||
|
5db6a89fc3 | ||
|
9f6706e0e7 | ||
|
2a63ddef7a | ||
|
fdac4af358 | ||
|
0f441b0bf2 | ||
|
0890c7e966 | ||
|
7e2583be56 | ||
|
d13cbeea38 | ||
|
5140fa2542 | ||
|
c367b49703 | ||
|
62fdca8fbf | ||
|
f1ff604b4c | ||
|
61b3705f35 |
72 changed files with 946 additions and 248 deletions
49
.github/workflows/tests.yaml
vendored
49
.github/workflows/tests.yaml
vendored
|
@ -12,6 +12,7 @@ jobs:
|
||||||
- "3.10"
|
- "3.10"
|
||||||
- "3.11"
|
- "3.11"
|
||||||
- "3.12"
|
- "3.12"
|
||||||
|
- "3.13"
|
||||||
# pypy fails in some cases but we don't care much about that
|
# pypy fails in some cases but we don't care much about that
|
||||||
# with github actions we can't mark some jobs to not affect the overall
|
# with github actions we can't mark some jobs to not affect the overall
|
||||||
# conclusion so we have to omit "allow-failure" tests.
|
# conclusion so we have to omit "allow-failure" tests.
|
||||||
|
@ -19,7 +20,8 @@ jobs:
|
||||||
# - pypy-3.7
|
# - pypy-3.7
|
||||||
deps:
|
deps:
|
||||||
- tornado pycurl
|
- tornado pycurl
|
||||||
- aiohttp
|
# timer runs when loop is closed, see https://github.com/lilydjwg/nvchecker/actions/runs/11650699759/job/32439742210
|
||||||
|
# - aiohttp
|
||||||
- tornado
|
- tornado
|
||||||
- httpx[http2]>=0.14.0
|
- httpx[http2]>=0.14.0
|
||||||
exclude: []
|
exclude: []
|
||||||
|
@ -40,17 +42,52 @@ jobs:
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-${{ env.cache-name }}-${{ matrix.deps }}-
|
${{ runner.os }}-${{ env.cache-name }}-${{ matrix.deps }}-
|
||||||
${{ runner.os }}-${{ env.cache-name }}-
|
${{ runner.os }}-${{ env.cache-name }}-
|
||||||
- name: workaround pycurl wheel
|
|
||||||
|
- name: Install pycurl deps
|
||||||
if: ${{ contains(matrix.deps, 'pycurl') }}
|
if: ${{ contains(matrix.deps, 'pycurl') }}
|
||||||
run: |
|
run: |
|
||||||
sudo mkdir -p /etc/pki/tls/certs
|
sudo apt update
|
||||||
sudo ln -s /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt
|
sudo apt install -y libcurl4-openssl-dev
|
||||||
# werkzeug is pinned for httpbin compatibility https://github.com/postmanlabs/httpbin/issues/673
|
# werkzeug is pinned for httpbin compatibility https://github.com/postmanlabs/httpbin/issues/673
|
||||||
- name: Install Python deps
|
- name: Install Python deps
|
||||||
run: pip install -U ${{ matrix.deps }} pytest 'pytest-asyncio>=0.23' pytest-httpbin pytest-rerunfailures structlog tomli platformdirs lxml jq 'werkzeug<2.1' awesomeversion
|
env:
|
||||||
|
# use env to avoid `>` being redirection
|
||||||
|
deps: ${{ matrix.deps }}
|
||||||
|
run: pip install -U $deps pytest 'pytest-asyncio>=0.24' pytest-httpbin pytest-rerunfailures structlog tomli platformdirs lxml jq 'werkzeug<2.1' awesomeversion
|
||||||
|
# don't use binary distribution because:
|
||||||
|
# hardcoded cacert path doesn't work on Ubuntu (should have been resolved?)
|
||||||
|
# limited compression support (only deflate & gzip)
|
||||||
|
- name: Install pycurl
|
||||||
|
if: ${{ contains(matrix.deps, 'pycurl') }}
|
||||||
|
run: |
|
||||||
|
pip uninstall -y pycurl
|
||||||
|
pip install -U pycurl --no-binary :all:
|
||||||
- name: Decrypt keys
|
- name: Decrypt keys
|
||||||
env:
|
env:
|
||||||
KEY: ${{ secrets.KEY }}
|
KEY: ${{ secrets.KEY }}
|
||||||
run: if [[ -n $KEY ]]; then openssl enc -d -aes-256-ctr -pbkdf2 -k $KEY -in keyfile.toml.enc -out keyfile.toml; fi
|
run: if [[ -n $KEY ]]; then openssl enc -d -aes-256-ctr -pbkdf2 -k $KEY -in keyfile.toml.enc -out keyfile.toml; fi
|
||||||
|
|
||||||
|
- name: Setup mitmproxy cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
env:
|
||||||
|
cache-name: cache-mitm
|
||||||
|
with:
|
||||||
|
path: ~/.mitmproxy
|
||||||
|
key: ${{ env.cache-name }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ env.cache-name }}-
|
||||||
|
- name: Install mitmproxy
|
||||||
|
run: |
|
||||||
|
/usr/bin/python -m venv --system-site-packages ~/.mitmproxy/venv
|
||||||
|
. ~/.mitmproxy/venv/bin/activate
|
||||||
|
pip install -U mitmproxy
|
||||||
|
# https://github.com/DevToys-app/DevToys/issues/1373#issuecomment-2599820594
|
||||||
|
sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0
|
||||||
|
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
|
|
||||||
|
# - name: Setup upterm session
|
||||||
|
# uses: lhotari/action-upterm@v1
|
||||||
- name: Run pytest
|
- name: Run pytest
|
||||||
run: if [[ -f keyfile.toml ]]; then KEYFILE=keyfile.toml pytest; else pytest; fi
|
env:
|
||||||
|
mitmdump: /home/runner/.mitmproxy/venv/bin/mitmdump
|
||||||
|
run: scripts/run_cached_tests
|
||||||
|
|
125
docs/usage.rst
125
docs/usage.rst
|
@ -71,8 +71,8 @@ The JSON log is one JSON string per line. The following documented events and
|
||||||
fields are stable, undocumented ones may change without notice.
|
fields are stable, undocumented ones may change without notice.
|
||||||
|
|
||||||
event=updated
|
event=updated
|
||||||
An update is detected. Fields ``name``, ``old_version`` and ``version`` are
|
An update is detected. Fields ``name``, ``revision``, ``old_version`` and ``version`` are
|
||||||
available. ``old_version`` maybe ``null``.
|
available. ``old_version`` may be ``null`` and ``revision`` may be absent.
|
||||||
|
|
||||||
event=up-to-date
|
event=up-to-date
|
||||||
There is no update. Fields ``name`` and ``version`` are available.
|
There is no update. Fields ``name`` and ``version`` are available.
|
||||||
|
@ -182,7 +182,7 @@ from_pattern, to_pattern
|
||||||
|
|
||||||
missing_ok
|
missing_ok
|
||||||
Suppress warnings and errors if a version checking module finds nothing.
|
Suppress warnings and errors if a version checking module finds nothing.
|
||||||
Currently only ``regex`` supports it.
|
Not all sources support it.
|
||||||
|
|
||||||
proxy
|
proxy
|
||||||
The HTTP proxy to use. The format is ``proto://host:port``, e.g.
|
The HTTP proxy to use. The format is ``proto://host:port``, e.g.
|
||||||
|
@ -322,12 +322,23 @@ post_data
|
||||||
post_data_type
|
post_data_type
|
||||||
(*Optional*) Specifies the ``Content-Type`` of the request body (``post_data``). By default, this is ``application/x-www-form-urlencoded``.
|
(*Optional*) Specifies the ``Content-Type`` of the request body (``post_data``). By default, this is ``application/x-www-form-urlencoded``.
|
||||||
|
|
||||||
|
This source can also work with XML to some extent, e.g. it can parse an RSS feed like this:
|
||||||
|
|
||||||
|
.. code-block:: toml
|
||||||
|
|
||||||
|
[ProxmoxVE]
|
||||||
|
source = "htmlparser"
|
||||||
|
url = "https://my.proxmox.com/en/announcements/tag/proxmox-ve/rss"
|
||||||
|
xpath = "//item/title"
|
||||||
|
from_pattern = 'Proxmox VE ([\d.]+) released!'
|
||||||
|
to_pattern = '\1'
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
An additional dependency "lxml" is required.
|
An additional dependency "lxml" is required.
|
||||||
You can use ``pip install 'nvchecker[htmlparser]'``.
|
You can use ``pip install 'nvchecker[htmlparser]'``.
|
||||||
|
|
||||||
Search with an JSON Parser (jq)
|
Search with an JSON Parser (jq)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
||||||
source = "jq"
|
source = "jq"
|
||||||
|
@ -388,8 +399,8 @@ Check GitHub
|
||||||
source = "github"
|
source = "github"
|
||||||
|
|
||||||
Check `GitHub <https://github.com/>`_ for updates. The version returned is in
|
Check `GitHub <https://github.com/>`_ for updates. The version returned is in
|
||||||
date format ``%Y%m%d.%H%M%S``, e.g. ``20130701.012212``, unless ``use_latest_release``
|
date format ``%Y%m%d.%H%M%S``, e.g. ``20130701.012212``, unless ``use_latest_release``,
|
||||||
or ``use_max_tag`` is used. See below.
|
``use_max_tag`` or ``use_max_release`` is used. See below.
|
||||||
|
|
||||||
github
|
github
|
||||||
The github repository, with author, e.g. ``lilydjwg/nvchecker``.
|
The github repository, with author, e.g. ``lilydjwg/nvchecker``.
|
||||||
|
@ -412,11 +423,24 @@ use_latest_release
|
||||||
small ones like `nvchecker's <https://github.com/lilydjwg/nvchecker/releases>`_
|
small ones like `nvchecker's <https://github.com/lilydjwg/nvchecker/releases>`_
|
||||||
are only git tags that should use ``use_max_tag`` below.
|
are only git tags that should use ``use_max_tag`` below.
|
||||||
|
|
||||||
Will return the release name instead of date.
|
Will return the release's tag name instead of date. (For historical reasons
|
||||||
|
it doesn't return the release name. See below to change.)
|
||||||
|
|
||||||
|
use_max_release
|
||||||
|
Set this to ``true`` to check for the max release on GitHub.
|
||||||
|
This option returns the largest one sorted by the
|
||||||
|
``sort_version_key`` option. Will return the tag name instead of date.
|
||||||
|
|
||||||
|
use_release_name
|
||||||
|
When ``use_latest_release`` or ``use_max_release`` is ``true``,
|
||||||
|
setting this to ``true`` will cause nvchecker to return the release name
|
||||||
|
instead of the tag name.
|
||||||
|
|
||||||
include_prereleases
|
include_prereleases
|
||||||
When ``use_latest_release`` is ``true``, set this to ``true`` to take prereleases into
|
When ``use_latest_release`` or ``use_max_release`` is ``true``,
|
||||||
account.
|
set this to ``true`` to take prereleases into account.
|
||||||
|
|
||||||
|
This returns the release names (not the tag names).
|
||||||
|
|
||||||
This requires a token because it's using the v4 GraphQL API.
|
This requires a token because it's using the v4 GraphQL API.
|
||||||
|
|
||||||
|
@ -431,7 +455,7 @@ query
|
||||||
|
|
||||||
use_max_tag
|
use_max_tag
|
||||||
Set this to ``true`` to check for the max tag on GitHub. Unlike
|
Set this to ``true`` to check for the max tag on GitHub. Unlike
|
||||||
``use_latest_release``, this option includes both annotated tags and
|
``use_max_release``, this option includes both annotated tags and
|
||||||
lightweight ones, and return the largest one sorted by the
|
lightweight ones, and return the largest one sorted by the
|
||||||
``sort_version_key`` option. Will return the tag name instead of date.
|
``sort_version_key`` option. Will return the tag name instead of date.
|
||||||
|
|
||||||
|
@ -447,7 +471,8 @@ To set an authorization token, you can set:
|
||||||
- an entry in the keyfile for the host (e.g. ``github.com``)
|
- an entry in the keyfile for the host (e.g. ``github.com``)
|
||||||
- an entry in your ``netrc`` file for the host
|
- an entry in your ``netrc`` file for the host
|
||||||
|
|
||||||
This source supports :ref:`list options` when ``use_max_tag`` is set.
|
This source supports :ref:`list options` when ``use_max_tag`` or
|
||||||
|
``use_max_release`` is set.
|
||||||
|
|
||||||
Check Gitea
|
Check Gitea
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
@ -482,6 +507,15 @@ To set an authorization token, you can set:
|
||||||
|
|
||||||
This source supports :ref:`list options` when ``use_max_tag`` is set.
|
This source supports :ref:`list options` when ``use_max_tag`` is set.
|
||||||
|
|
||||||
|
Check Gogs / Forgejo / Codeberg
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Please use the above "gitea" source. Gitea is a fork of `Gogs <https://gogs.io/>`_.
|
||||||
|
`Forgejo <https://forgejo.org/>`_ is a fork of Gitea. Codeberg is a code
|
||||||
|
hosting provider that uses Forgejo. They share the same API endpoints nvchecker uses.
|
||||||
|
|
||||||
|
Alternatively, you can try the generic "git" source.
|
||||||
|
|
||||||
Check BitBucket
|
Check BitBucket
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
@ -562,7 +596,7 @@ Check PyPI
|
||||||
|
|
||||||
source = "pypi"
|
source = "pypi"
|
||||||
|
|
||||||
Check `PyPI <https://pypi.python.org/>`_ for updates.
|
Check `PyPI <https://pypi.python.org/>`_ for updates. Yanked releases are ignored.
|
||||||
|
|
||||||
pypi
|
pypi
|
||||||
The name used on PyPI, e.g. ``PySide``.
|
The name used on PyPI, e.g. ``PySide``.
|
||||||
|
@ -570,6 +604,8 @@ pypi
|
||||||
use_pre_release
|
use_pre_release
|
||||||
Whether to accept pre release. Default is false.
|
Whether to accept pre release. Default is false.
|
||||||
|
|
||||||
|
This source supports :ref:`list options`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
An additional dependency "packaging" is required.
|
An additional dependency "packaging" is required.
|
||||||
You can use ``pip install 'nvchecker[pypi]'``.
|
You can use ``pip install 'nvchecker[pypi]'``.
|
||||||
|
@ -654,11 +690,16 @@ Check crates.io
|
||||||
|
|
||||||
source = "cratesio"
|
source = "cratesio"
|
||||||
|
|
||||||
Check `crates.io <https://crates.io/>`_ for updates.
|
Check `crates.io <https://crates.io/>`_ for updates. Yanked releases are ignored.
|
||||||
|
|
||||||
cratesio
|
cratesio
|
||||||
The crate name on crates.io, e.g. ``tokio``.
|
The crate name on crates.io, e.g. ``tokio``.
|
||||||
|
|
||||||
|
use_pre_release
|
||||||
|
Whether to accept pre release. Default is false.
|
||||||
|
|
||||||
|
This source supports :ref:`list options`.
|
||||||
|
|
||||||
Check Local Pacman Database
|
Check Local Pacman Database
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
@ -755,6 +796,11 @@ This enables you to track updates from `Anitya <https://release-monitoring.org/>
|
||||||
anitya
|
anitya
|
||||||
``distro/package``, where ``distro`` can be a lot of things like "fedora", "arch linux", "gentoo", etc. ``package`` is the package name of the chosen distribution.
|
``distro/package``, where ``distro`` can be a lot of things like "fedora", "arch linux", "gentoo", etc. ``package`` is the package name of the chosen distribution.
|
||||||
|
|
||||||
|
anitya_id
|
||||||
|
The identifier of the project/package in anitya.
|
||||||
|
|
||||||
|
Note that either anitya or anitya_id needs to be specified, anitya_id is preferred when both specified.
|
||||||
|
|
||||||
Check Android SDK
|
Check Android SDK
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
@ -838,6 +884,29 @@ strip_release
|
||||||
|
|
||||||
Note that either pkg or srcpkg needs to be specified (but not both) or the item name will be used as pkg.
|
Note that either pkg or srcpkg needs to be specified (but not both) or the item name will be used as pkg.
|
||||||
|
|
||||||
|
Check RPM repository
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
::
|
||||||
|
|
||||||
|
source = "rpmrepo"
|
||||||
|
|
||||||
|
This enables you to check latest package versions in an arbitrary RPM repository in `repomd` format used by package managers such as ``dnf`` (Fedora, RHEL, AlmaLinux etc.) or ``zypper`` (openSUSE) without the need for native RPM tools.
|
||||||
|
|
||||||
|
pkg
|
||||||
|
Name of the RPM package (you can also use ``rpmrepo`` as with other sources, but ``pkg`` is preferred for clarity)
|
||||||
|
|
||||||
|
repo
|
||||||
|
URL of the repository (required, ``repodata/repomd.xml`` should be there)
|
||||||
|
|
||||||
|
arch
|
||||||
|
Architecture of the RPM package (``binary``, ``src``, ``any``, ``x86_64``, ``aarch64``, etc, defaults to ``binary``)
|
||||||
|
|
||||||
|
This source supports :ref:`list options`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
An additional dependency "lxml" is required.
|
||||||
|
You can use ``pip install 'nvchecker[rpmrepo]'``.
|
||||||
|
|
||||||
Check Git repository
|
Check Git repository
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
@ -995,6 +1064,36 @@ Check `Go packages and modules <https://pkg.go.dev/>`_ for updates.
|
||||||
go
|
go
|
||||||
The name of Go package or module, e.g. ``github.com/caddyserver/caddy/v2/cmd``.
|
The name of Go package or module, e.g. ``github.com/caddyserver/caddy/v2/cmd``.
|
||||||
|
|
||||||
|
Check opam repository
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
::
|
||||||
|
|
||||||
|
source = "opam"
|
||||||
|
|
||||||
|
This enables you to check latest package versions in an arbitrary `opam repository <https://opam.ocaml.org/doc/Manual.html#Repositories>` without the need for the opam command line tool.
|
||||||
|
|
||||||
|
pkg
|
||||||
|
Name of the opam package
|
||||||
|
|
||||||
|
repo
|
||||||
|
URL of the repository (optional, the default ``https://opam.ocaml.org`` repository is used if not specified)
|
||||||
|
|
||||||
|
This source supports :ref:`list options`.
|
||||||
|
|
||||||
|
Check Snapcraft
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
::
|
||||||
|
|
||||||
|
source = "snapcraft"
|
||||||
|
|
||||||
|
This source allows you to check the latest package versions in the `Snapcraft <https://snapcraft.io>`_.
|
||||||
|
|
||||||
|
snap
|
||||||
|
Name of the snap package.
|
||||||
|
|
||||||
|
channel
|
||||||
|
Name of the channel.
|
||||||
|
|
||||||
Combine others' results
|
Combine others' results
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
::
|
::
|
||||||
|
|
3
mypy.ini
3
mypy.ini
|
@ -26,3 +26,6 @@ ignore_missing_imports = True
|
||||||
|
|
||||||
[mypy-jq]
|
[mypy-jq]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
[mypy-tomli]
|
||||||
|
ignore_missing_imports = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
__version__ = '2.14.1'
|
__version__ = '2.17dev'
|
||||||
|
|
|
@ -78,6 +78,7 @@ def process_common_arguments(args: argparse.Namespace) -> bool:
|
||||||
slogconf.exc_info,
|
slogconf.exc_info,
|
||||||
slogconf.filter_exc,
|
slogconf.filter_exc,
|
||||||
slogconf.filter_nones,
|
slogconf.filter_nones,
|
||||||
|
slogconf.filter_taskname,
|
||||||
]
|
]
|
||||||
logger_factory = None
|
logger_factory = None
|
||||||
|
|
||||||
|
@ -316,13 +317,20 @@ def substitute_version(
|
||||||
return version
|
return version
|
||||||
|
|
||||||
def apply_list_options(
|
def apply_list_options(
|
||||||
versions: List[Union[str, RichResult]], conf: Entry,
|
versions: List[Union[str, RichResult]],
|
||||||
|
conf: Entry,
|
||||||
|
name: str,
|
||||||
) -> Optional[Union[str, RichResult]]:
|
) -> Optional[Union[str, RichResult]]:
|
||||||
pattern = conf.get('include_regex')
|
pattern = conf.get('include_regex')
|
||||||
if pattern:
|
if versions and pattern:
|
||||||
re_pat = re.compile(pattern)
|
re_pat = re.compile(pattern)
|
||||||
versions = [x for x in versions
|
versions2 = [x for x in versions
|
||||||
if re_pat.fullmatch(str(x))]
|
if re_pat.fullmatch(str(x))]
|
||||||
|
if not versions2:
|
||||||
|
logger.warning('include_regex matched no versions',
|
||||||
|
name=name, versions=versions, regex=pattern)
|
||||||
|
return None
|
||||||
|
versions = versions2
|
||||||
|
|
||||||
pattern = conf.get('exclude_regex')
|
pattern = conf.get('exclude_regex')
|
||||||
if pattern:
|
if pattern:
|
||||||
|
@ -362,7 +370,7 @@ def _process_result(r: RawResult) -> Union[RichResult, Exception]:
|
||||||
name=r.name, exc_info=r.version)
|
name=r.name, exc_info=r.version)
|
||||||
return version
|
return version
|
||||||
elif isinstance(version, list):
|
elif isinstance(version, list):
|
||||||
version_str = apply_list_options(version, conf)
|
version_str = apply_list_options(version, conf, name)
|
||||||
if isinstance(version_str, RichResult):
|
if isinstance(version_str, RichResult):
|
||||||
url = version_str.url
|
url = version_str.url
|
||||||
gitref = version_str.gitref
|
gitref = version_str.gitref
|
||||||
|
@ -409,6 +417,7 @@ def check_version_update(
|
||||||
'updated',
|
'updated',
|
||||||
name = name,
|
name = name,
|
||||||
version = r.version,
|
version = r.version,
|
||||||
|
revision = r.revision,
|
||||||
old_version = oldver,
|
old_version = oldver,
|
||||||
url = r.url,
|
url = r.url,
|
||||||
)
|
)
|
||||||
|
@ -435,6 +444,8 @@ async def process_result(
|
||||||
r1 = e
|
r1 = e
|
||||||
if isinstance(r1, Exception):
|
if isinstance(r1, Exception):
|
||||||
entry_waiter.set_exception(r.name, r1)
|
entry_waiter.set_exception(r.name, r1)
|
||||||
|
# no versions are returned from "apply_list_options"?
|
||||||
|
logger.error('no-result', name=r.name, error=repr(r1))
|
||||||
has_failures = True
|
has_failures = True
|
||||||
continue
|
continue
|
||||||
check_version_update(oldvers, r.name, r1, verbose)
|
check_version_update(oldvers, r.name, r1, verbose)
|
||||||
|
|
|
@ -12,7 +12,6 @@ from .base import BaseSession, TemporaryError, Response, HTTPError
|
||||||
__all__ = ['session']
|
__all__ = ['session']
|
||||||
|
|
||||||
logger = structlog.get_logger(logger_name=__name__)
|
logger = structlog.get_logger(logger_name=__name__)
|
||||||
connector = aiohttp.TCPConnector(limit=20)
|
|
||||||
|
|
||||||
class AiohttpSession(BaseSession):
|
class AiohttpSession(BaseSession):
|
||||||
session = None
|
session = None
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2020-2022,2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
from typing import Dict, Optional, Tuple
|
from typing import Dict, Optional, Tuple
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class HttpxSession(BaseSession):
|
||||||
client = httpx.AsyncClient(
|
client = httpx.AsyncClient(
|
||||||
timeout = httpx.Timeout(self.timeout, pool=None),
|
timeout = httpx.Timeout(self.timeout, pool=None),
|
||||||
http2 = True,
|
http2 = True,
|
||||||
proxies = {'all://': proxy},
|
proxy = proxy,
|
||||||
verify = verify_cert,
|
verify = verify_cert,
|
||||||
)
|
)
|
||||||
self.clients[(proxy, verify_cert)] = client
|
self.clients[(proxy, verify_cert)] = client
|
||||||
|
@ -49,7 +49,8 @@ class HttpxSession(BaseSession):
|
||||||
method, url, json = json, content = body,
|
method, url, json = json, content = body,
|
||||||
headers = headers,
|
headers = headers,
|
||||||
follow_redirects = follow_redirects,
|
follow_redirects = follow_redirects,
|
||||||
params = params,
|
# httpx checks for None but not ()
|
||||||
|
params = params or None,
|
||||||
)
|
)
|
||||||
err_cls: Optional[type] = None
|
err_cls: Optional[type] = None
|
||||||
if r.status_code >= 500:
|
if r.status_code >= 500:
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import json as _json
|
import json as _json
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
|
import os
|
||||||
|
|
||||||
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
||||||
|
|
||||||
|
@ -17,8 +18,9 @@ from .base import BaseSession, TemporaryError, Response, HTTPError
|
||||||
__all__ = ['session']
|
__all__ = ['session']
|
||||||
|
|
||||||
HTTP2_AVAILABLE = None if pycurl else False
|
HTTP2_AVAILABLE = None if pycurl else False
|
||||||
|
SSL_CERT_FILE = os.environ.get('SSL_CERT_FILE')
|
||||||
|
|
||||||
def try_use_http2(curl):
|
def setup_curl(curl):
|
||||||
global HTTP2_AVAILABLE
|
global HTTP2_AVAILABLE
|
||||||
if HTTP2_AVAILABLE is None:
|
if HTTP2_AVAILABLE is None:
|
||||||
try:
|
try:
|
||||||
|
@ -29,6 +31,10 @@ def try_use_http2(curl):
|
||||||
elif HTTP2_AVAILABLE:
|
elif HTTP2_AVAILABLE:
|
||||||
curl.setopt(pycurl.HTTP_VERSION, 4)
|
curl.setopt(pycurl.HTTP_VERSION, 4)
|
||||||
|
|
||||||
|
if SSL_CERT_FILE:
|
||||||
|
curl.setopt_string(pycurl.CAINFO, SSL_CERT_FILE)
|
||||||
|
curl.setopt_string(pycurl.ACCEPT_ENCODING, "")
|
||||||
|
|
||||||
class TornadoSession(BaseSession):
|
class TornadoSession(BaseSession):
|
||||||
def setup(
|
def setup(
|
||||||
self,
|
self,
|
||||||
|
@ -68,7 +74,7 @@ class TornadoSession(BaseSession):
|
||||||
kwargs['body'] = body
|
kwargs['body'] = body
|
||||||
elif json:
|
elif json:
|
||||||
kwargs['body'] = _json.dumps(json)
|
kwargs['body'] = _json.dumps(json)
|
||||||
kwargs['prepare_curl_callback'] = try_use_http2
|
kwargs['prepare_curl_callback'] = setup_curl
|
||||||
|
|
||||||
if proxy:
|
if proxy:
|
||||||
host, port = proxy.rsplit(':', 1)
|
host, port = proxy.rsplit(':', 1)
|
||||||
|
|
|
@ -71,6 +71,7 @@ class TornadoLogFormatter(logging.Formatter):
|
||||||
'filename', 'exc_info', 'exc_text', 'created', 'funcName',
|
'filename', 'exc_info', 'exc_text', 'created', 'funcName',
|
||||||
'processName', 'process', 'msecs', 'relativeCreated', 'thread',
|
'processName', 'process', 'msecs', 'relativeCreated', 'thread',
|
||||||
'threadName', 'name', 'levelno', 'msg', 'pathname', 'stack_info',
|
'threadName', 'name', 'levelno', 'msg', 'pathname', 'stack_info',
|
||||||
|
'taskName',
|
||||||
})
|
})
|
||||||
|
|
||||||
if record.exc_info:
|
if record.exc_info:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# vim: se sw=2:
|
# vim: se sw=2:
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2018 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2018-2020,2023-2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -26,6 +26,9 @@ def _console_msg(event):
|
||||||
else:
|
else:
|
||||||
msg = evt
|
msg = evt
|
||||||
|
|
||||||
|
if 'revision' in event and not event['revision']:
|
||||||
|
del event['revision']
|
||||||
|
|
||||||
if 'name' in event:
|
if 'name' in event:
|
||||||
msg = f"{event['name']}: {msg}"
|
msg = f"{event['name']}: {msg}"
|
||||||
del event['name']
|
del event['name']
|
||||||
|
@ -44,6 +47,12 @@ def filter_nones(logger, level, event):
|
||||||
del event['url']
|
del event['url']
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
def filter_taskname(logger, level, event):
|
||||||
|
# added in Python 3.12, not useful to us, but appears as a normal KV.
|
||||||
|
if 'taskName' in event:
|
||||||
|
del event['taskName']
|
||||||
|
return event
|
||||||
|
|
||||||
def filter_exc(logger, level, event):
|
def filter_exc(logger, level, event):
|
||||||
exc_info = event.get('exc_info')
|
exc_info = event.get('exc_info')
|
||||||
if not exc_info:
|
if not exc_info:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# vim: se sw=2:
|
# vim: se sw=2:
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -10,6 +10,7 @@ import json
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from . import core
|
from . import core
|
||||||
|
from .util import RichResult
|
||||||
|
|
||||||
logger = structlog.get_logger(logger_name=__name__)
|
logger = structlog.get_logger(logger_name=__name__)
|
||||||
|
|
||||||
|
@ -44,10 +45,11 @@ def take() -> None:
|
||||||
if args.all:
|
if args.all:
|
||||||
oldvers.update(newvers)
|
oldvers.update(newvers)
|
||||||
else:
|
else:
|
||||||
|
name: str
|
||||||
for name in args.names:
|
for name in args.names:
|
||||||
if "=" in name:
|
if "=" in name:
|
||||||
name, newver = name.split("=")
|
name, newver = name.split("=")
|
||||||
oldvers[name] = newver
|
oldvers[name] = RichResult(version=newver)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
oldvers[name] = newvers[name]
|
oldvers[name] = newvers[name]
|
||||||
|
|
|
@ -6,7 +6,9 @@ from nvchecker.api import RichResult
|
||||||
URL = 'https://release-monitoring.org/api/project/{pkg}'
|
URL = 'https://release-monitoring.org/api/project/{pkg}'
|
||||||
|
|
||||||
async def get_version(name, conf, *, cache, **kwargs):
|
async def get_version(name, conf, *, cache, **kwargs):
|
||||||
pkg = conf.get('anitya')
|
pkg = conf.get('anitya_id')
|
||||||
|
if pkg is None:
|
||||||
|
pkg = conf.get('anitya')
|
||||||
url = URL.format(pkg = pkg)
|
url = URL.format(pkg = pkg)
|
||||||
data = await cache.get_json(url)
|
data = await cache.get_json(url)
|
||||||
return RichResult(
|
return RichResult(
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
from nvchecker.api import session, RichResult, GetVersionError
|
from nvchecker.api import session, RichResult, GetVersionError
|
||||||
|
|
||||||
URL = 'https://www.archlinux.org/packages/search/json/'
|
URL = 'https://archlinux.org/packages/search/json/'
|
||||||
|
|
||||||
async def request(pkg):
|
async def request(pkg):
|
||||||
res = await session.get(URL, params={"name": pkg})
|
res = await session.get(URL, params={"name": pkg})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020,2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import Iterable, Dict, List, Tuple, Any, Optional
|
from typing import Iterable, Dict, List, Tuple, Any, Optional
|
||||||
|
|
||||||
|
@ -95,7 +95,8 @@ async def _run_batch_impl(
|
||||||
|
|
||||||
version = result['Version']
|
version = result['Version']
|
||||||
if use_last_modified:
|
if use_last_modified:
|
||||||
version += '-' + datetime.utcfromtimestamp(result['LastModified']).strftime('%Y%m%d%H%M%S')
|
dt = datetime.fromtimestamp(result['LastModified'], timezone.utc)
|
||||||
|
version += '-' + dt.strftime('%Y%m%d%H%M%S')
|
||||||
if strip_release and '-' in version:
|
if strip_release and '-' in version:
|
||||||
version = version.rsplit('-', 1)[0]
|
version = version.rsplit('-', 1)[0]
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,40 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import structlog
|
||||||
|
|
||||||
from nvchecker.api import RichResult
|
from nvchecker.api import RichResult
|
||||||
|
|
||||||
|
logger = structlog.get_logger(logger_name=__name__)
|
||||||
|
|
||||||
|
|
||||||
API_URL = 'https://crates.io/api/v1/crates/%s'
|
API_URL = 'https://crates.io/api/v1/crates/%s'
|
||||||
|
# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||||
|
VERSION_PATTERN = r'^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
|
||||||
|
|
||||||
|
|
||||||
async def get_version(name, conf, *, cache, **kwargs):
|
async def get_version(name, conf, *, cache, **kwargs):
|
||||||
name = conf.get('cratesio') or name
|
name = conf.get('cratesio') or name
|
||||||
|
use_pre_release = conf.get('use_pre_release', False)
|
||||||
data = await cache.get_json(API_URL % name)
|
data = await cache.get_json(API_URL % name)
|
||||||
version = [v['num'] for v in data['versions'] if not v['yanked']][0]
|
results = []
|
||||||
return RichResult(
|
for v in data['versions']:
|
||||||
version = version,
|
if v['yanked']:
|
||||||
url = f'https://crates.io/crates/{name}/{version}',
|
continue
|
||||||
)
|
version = v['num']
|
||||||
|
match = re.fullmatch(VERSION_PATTERN, version)
|
||||||
|
if match is None:
|
||||||
|
logger.warning('ignoring invalid version', version=version)
|
||||||
|
continue
|
||||||
|
if not use_pre_release and match.group('prerelease'):
|
||||||
|
continue
|
||||||
|
results.append(
|
||||||
|
RichResult(
|
||||||
|
version=version,
|
||||||
|
url=f'https://crates.io/crates/{name}/{version}',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
|
@ -51,7 +51,7 @@ async def get_version(
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
return RichResult(
|
return RichResult(
|
||||||
version = data[0]['commit']['committer']['date'].split('T', 1)[0].replace('-', ''),
|
version = data[0]['commit']['committer']['date'],
|
||||||
revision = data[0]['sha'],
|
revision = data[0]['sha'],
|
||||||
url = data[0]['html_url'],
|
url = data[0]['html_url'],
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,7 @@ GITHUB_URL = 'https://api.%s/repos/%s/commits'
|
||||||
GITHUB_LATEST_RELEASE = 'https://api.%s/repos/%s/releases/latest'
|
GITHUB_LATEST_RELEASE = 'https://api.%s/repos/%s/releases/latest'
|
||||||
# https://developer.github.com/v3/git/refs/#get-all-references
|
# https://developer.github.com/v3/git/refs/#get-all-references
|
||||||
GITHUB_MAX_TAG = 'https://api.%s/repos/%s/git/refs/tags'
|
GITHUB_MAX_TAG = 'https://api.%s/repos/%s/git/refs/tags'
|
||||||
|
GITHUB_MAX_RELEASE = 'https://api.%s/repos/%s/releases'
|
||||||
GITHUB_GRAPHQL_URL = 'https://api.%s/graphql'
|
GITHUB_GRAPHQL_URL = 'https://api.%s/graphql'
|
||||||
|
|
||||||
async def get_version(name, conf, **kwargs):
|
async def get_version(name, conf, **kwargs):
|
||||||
|
@ -120,8 +121,8 @@ async def get_latest_tag(key: Tuple[str, str, str, str]) -> RichResult:
|
||||||
url = f'https://github.com/{repo}/releases/tag/{version}',
|
url = f'https://github.com/{repo}/releases/tag/{version}',
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_latest_release_with_prereleases(key: Tuple[str, str, str]) -> RichResult:
|
async def get_latest_release_with_prereleases(key: Tuple[str, str, str, str]) -> RichResult:
|
||||||
host, repo, token = key
|
host, repo, token, use_release_name = key
|
||||||
owner, reponame = repo.split('/')
|
owner, reponame = repo.split('/')
|
||||||
headers = {
|
headers = {
|
||||||
'Authorization': f'bearer {token}',
|
'Authorization': f'bearer {token}',
|
||||||
|
@ -143,9 +144,15 @@ async def get_latest_release_with_prereleases(key: Tuple[str, str, str]) -> Rich
|
||||||
if not refs:
|
if not refs:
|
||||||
raise GetVersionError('no release found')
|
raise GetVersionError('no release found')
|
||||||
|
|
||||||
|
tag_name = refs[0]['node']['tag']['name']
|
||||||
|
if use_release_name:
|
||||||
|
version = refs[0]['node']['name']
|
||||||
|
else:
|
||||||
|
version = tag_name
|
||||||
|
|
||||||
return RichResult(
|
return RichResult(
|
||||||
version = refs[0]['node']['name'],
|
version = version,
|
||||||
gitref = refs[0]['node']['tag']['name'],
|
gitref = f"refs/tags/{tag_name}",
|
||||||
revision = refs[0]['node']['tagCommit']['oid'],
|
revision = refs[0]['node']['tagCommit']['oid'],
|
||||||
url = refs[0]['node']['url'],
|
url = refs[0]['node']['url'],
|
||||||
)
|
)
|
||||||
|
@ -174,19 +181,25 @@ async def get_version_real(
|
||||||
|
|
||||||
use_latest_release = conf.get('use_latest_release', False)
|
use_latest_release = conf.get('use_latest_release', False)
|
||||||
include_prereleases = conf.get('include_prereleases', False)
|
include_prereleases = conf.get('include_prereleases', False)
|
||||||
|
use_release_name = conf.get('use_release_name', False)
|
||||||
if use_latest_release and include_prereleases:
|
if use_latest_release and include_prereleases:
|
||||||
if not token:
|
if not token:
|
||||||
raise GetVersionError('token not given but it is required')
|
raise GetVersionError('token not given but it is required')
|
||||||
|
|
||||||
return await cache.get((host, repo, token), get_latest_release_with_prereleases) # type: ignore
|
return await cache.get(
|
||||||
|
(host, repo, token, use_release_name),
|
||||||
|
get_latest_release_with_prereleases) # type: ignore
|
||||||
|
|
||||||
br = conf.get('branch')
|
br = conf.get('branch')
|
||||||
path = conf.get('path')
|
path = conf.get('path')
|
||||||
use_max_tag = conf.get('use_max_tag', False)
|
use_max_tag = conf.get('use_max_tag', False)
|
||||||
|
use_max_release = conf.get('use_max_release', False)
|
||||||
if use_latest_release:
|
if use_latest_release:
|
||||||
url = GITHUB_LATEST_RELEASE % (host, repo)
|
url = GITHUB_LATEST_RELEASE % (host, repo)
|
||||||
elif use_max_tag:
|
elif use_max_tag:
|
||||||
url = GITHUB_MAX_TAG % (host, repo)
|
url = GITHUB_MAX_TAG % (host, repo)
|
||||||
|
elif use_max_release:
|
||||||
|
url = GITHUB_MAX_RELEASE % (host, repo)
|
||||||
else:
|
else:
|
||||||
url = GITHUB_URL % (host, repo)
|
url = GITHUB_URL % (host, repo)
|
||||||
parameters = {}
|
parameters = {}
|
||||||
|
@ -216,11 +229,29 @@ async def get_version_real(
|
||||||
raise GetVersionError('No tag found in upstream repository.')
|
raise GetVersionError('No tag found in upstream repository.')
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
if use_max_release:
|
||||||
|
releases: List[Union[str, RichResult]] = [
|
||||||
|
RichResult(
|
||||||
|
version = ref['name'] if use_release_name else ref['tag_name'],
|
||||||
|
gitref = f"refs/tags/{ref['tag_name']}",
|
||||||
|
url = ref['html_url'],
|
||||||
|
) for ref in data if include_prereleases or not ref['prerelease']
|
||||||
|
]
|
||||||
|
if not releases:
|
||||||
|
raise GetVersionError('No release found in upstream repository.')
|
||||||
|
return releases
|
||||||
|
|
||||||
if use_latest_release:
|
if use_latest_release:
|
||||||
if 'tag_name' not in data:
|
if 'tag_name' not in data:
|
||||||
raise GetVersionError('No release found in upstream repository.')
|
raise GetVersionError('No release found in upstream repository.')
|
||||||
|
|
||||||
|
if use_release_name:
|
||||||
|
version = data['name']
|
||||||
|
else:
|
||||||
|
version = data['tag_name']
|
||||||
|
|
||||||
return RichResult(
|
return RichResult(
|
||||||
version = data['tag_name'],
|
version = version,
|
||||||
gitref = f"refs/tags/{data['tag_name']}",
|
gitref = f"refs/tags/{data['tag_name']}",
|
||||||
url = data['html_url'],
|
url = data['html_url'],
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,23 +4,24 @@
|
||||||
from lxml import html
|
from lxml import html
|
||||||
|
|
||||||
from nvchecker.api import (
|
from nvchecker.api import (
|
||||||
VersionResult, Entry, AsyncCache, KeyManager,
|
RichResult, Entry, AsyncCache, KeyManager,
|
||||||
session, GetVersionError,
|
session, GetVersionError,
|
||||||
)
|
)
|
||||||
|
|
||||||
GO_PKG_URL = 'https://pkg.go.dev/{pkg}?tab=versions'
|
GO_PKG_URL = 'https://pkg.go.dev/{pkg}?tab=versions'
|
||||||
|
GO_PKG_VERSION_URL = 'https://pkg.go.dev/{pkg}@{version}'
|
||||||
|
|
||||||
|
|
||||||
async def get_version(
|
async def get_version(
|
||||||
name: str, conf: Entry, *,
|
name: str, conf: Entry, *,
|
||||||
cache: AsyncCache, keymanager: KeyManager,
|
cache: AsyncCache, keymanager: KeyManager,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> VersionResult:
|
) -> RichResult:
|
||||||
key = tuple(sorted(conf.items()))
|
key = tuple(sorted(conf.items()))
|
||||||
return await cache.get(key, get_version_impl)
|
return await cache.get(key, get_version_impl)
|
||||||
|
|
||||||
|
|
||||||
async def get_version_impl(info) -> VersionResult:
|
async def get_version_impl(info) -> RichResult:
|
||||||
conf = dict(info)
|
conf = dict(info)
|
||||||
pkg_name = conf.get('go')
|
pkg_name = conf.get('go')
|
||||||
|
|
||||||
|
@ -30,7 +31,10 @@ async def get_version_impl(info) -> VersionResult:
|
||||||
|
|
||||||
elements = doc.xpath("//div[@class='Version-tag']/a/text()")
|
elements = doc.xpath("//div[@class='Version-tag']/a/text()")
|
||||||
try:
|
try:
|
||||||
version = elements[0]
|
version = elements[0] # type: ignore
|
||||||
return version
|
return RichResult(
|
||||||
|
version = version, # type: ignore
|
||||||
|
url = GO_PKG_VERSION_URL.format(pkg=pkg_name, version=version),
|
||||||
|
)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise GetVersionError("parse error", pkg_name=pkg_name)
|
raise GetVersionError("parse error", pkg_name=pkg_name)
|
||||||
|
|
20
nvchecker_source/launchpad.py
Normal file
20
nvchecker_source/launchpad.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# MIT Licensed
|
||||||
|
# Copyright (c) 2024 Bert Peters <bertptrs@archlinux.org>, et al.
|
||||||
|
from __future__ import annotations
|
||||||
|
from nvchecker.api import AsyncCache, Entry, RichResult
|
||||||
|
|
||||||
|
PROJECT_INFO_URL = "https://api.launchpad.net/1.0/{launchpad}"
|
||||||
|
|
||||||
|
async def get_version(name: str, conf: Entry, *, cache: AsyncCache, **kwargs):
|
||||||
|
launchpad = conf["launchpad"]
|
||||||
|
|
||||||
|
project_data = await cache.get_json(PROJECT_INFO_URL.format(launchpad=launchpad))
|
||||||
|
data = await cache.get_json(project_data['releases_collection_link'])
|
||||||
|
|
||||||
|
return [
|
||||||
|
RichResult(version=entry["version"], url=entry["web_link"])
|
||||||
|
for entry in data["entries"]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
71
nvchecker_source/opam.py
Normal file
71
nvchecker_source/opam.py
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2024 Daniel Peukert <daniel@peukert.cc>, et al.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from io import BytesIO
|
||||||
|
import tarfile
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from nvchecker.api import (
|
||||||
|
session, VersionResult,
|
||||||
|
Entry, AsyncCache,
|
||||||
|
KeyManager, RichResult
|
||||||
|
)
|
||||||
|
|
||||||
|
OPAM_REPO_INDEX_URL = "%s/index.tar.gz"
|
||||||
|
OPAM_VERSION_PATH_PREFIX = "packages/%s/%s."
|
||||||
|
OPAM_VERSION_PATH_SUFFIX = "/opam"
|
||||||
|
|
||||||
|
OPAM_DEFAULT_REPO = 'https://opam.ocaml.org'
|
||||||
|
OPAM_DEFAULT_REPO_VERSION_URL = "%s/packages/%s/%s.%s"
|
||||||
|
|
||||||
|
def _decompress_and_list_files(data: bytes) -> List[str]:
|
||||||
|
# Convert the bytes to a file object and get a list of files
|
||||||
|
archive = tarfile.open(mode='r', fileobj=BytesIO(data))
|
||||||
|
return archive.getnames()
|
||||||
|
|
||||||
|
async def get_files(url: str) -> List[str]:
|
||||||
|
# Download the file and get its contents
|
||||||
|
res = await session.get(url)
|
||||||
|
data = res.body
|
||||||
|
|
||||||
|
# Get the file list of the archive
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
return await loop.run_in_executor(None, _decompress_and_list_files, data)
|
||||||
|
|
||||||
|
async def get_package_versions(files: List[str], pkg: str) -> List[str]:
|
||||||
|
# Prepare the filename prefix based on the package name
|
||||||
|
prefix = OPAM_VERSION_PATH_PREFIX % (pkg , pkg)
|
||||||
|
|
||||||
|
# Only keep opam files that are relevant to the package we're working with
|
||||||
|
filtered_files = []
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
if filename.startswith(prefix) and filename.endswith(OPAM_VERSION_PATH_SUFFIX):
|
||||||
|
filtered_files.append(filename[len(prefix):-1*len(OPAM_VERSION_PATH_SUFFIX)])
|
||||||
|
|
||||||
|
return filtered_files
|
||||||
|
|
||||||
|
async def get_version(
|
||||||
|
name: str, conf: Entry, *,
|
||||||
|
cache: AsyncCache, keymanager: KeyManager,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
pkg = conf.get('pkg', name)
|
||||||
|
repo = conf.get('repo', OPAM_DEFAULT_REPO).rstrip('/')
|
||||||
|
|
||||||
|
# Get the list of files in the repo index (see https://opam.ocaml.org/doc/Manual.html#Repositories for repo structure)
|
||||||
|
files = await cache.get(OPAM_REPO_INDEX_URL % repo, get_files) # type: ignore
|
||||||
|
|
||||||
|
# Parse the version strings from the file names
|
||||||
|
raw_versions = await get_package_versions(files, pkg)
|
||||||
|
|
||||||
|
# Convert the version strings into RichResults
|
||||||
|
versions = []
|
||||||
|
for version in raw_versions:
|
||||||
|
versions.append(RichResult(
|
||||||
|
version = version,
|
||||||
|
# There is no standardised URL scheme, so we only return an URL for the default registry
|
||||||
|
url = OPAM_DEFAULT_REPO_VERSION_URL % (repo, pkg, pkg, version) if repo == OPAM_DEFAULT_REPO else None,
|
||||||
|
))
|
||||||
|
return versions
|
|
@ -1,11 +1,16 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2021 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2021,2023-2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
from packaging.version import Version
|
import structlog
|
||||||
|
from packaging.version import Version, InvalidVersion
|
||||||
|
|
||||||
from nvchecker.api import RichResult
|
from nvchecker.api import RichResult
|
||||||
|
|
||||||
|
logger = structlog.get_logger(logger_name=__name__)
|
||||||
|
|
||||||
async def get_version(name, conf, *, cache, **kwargs):
|
async def get_version(name, conf, *, cache, **kwargs):
|
||||||
|
ret = []
|
||||||
|
|
||||||
package = conf.get('pypi') or name
|
package = conf.get('pypi') or name
|
||||||
use_pre_release = conf.get('use_pre_release', False)
|
use_pre_release = conf.get('use_pre_release', False)
|
||||||
|
|
||||||
|
@ -13,14 +18,26 @@ async def get_version(name, conf, *, cache, **kwargs):
|
||||||
|
|
||||||
data = await cache.get_json(url)
|
data = await cache.get_json(url)
|
||||||
|
|
||||||
if use_pre_release:
|
for version in data['releases'].keys():
|
||||||
version = sorted(
|
# Skip versions that are marked as yanked.
|
||||||
data['releases'].keys(),
|
if (vers := data['releases'][version]) and vers[0]['yanked']:
|
||||||
key = Version,
|
continue
|
||||||
)[-1]
|
|
||||||
else:
|
try:
|
||||||
version = data['info']['version']
|
parsed_version = Version(version)
|
||||||
return RichResult(
|
except InvalidVersion:
|
||||||
version = version,
|
if data['releases'][version]:
|
||||||
url = f'https://pypi.org/project/{package}/{version}/',
|
# emit a warning if there is something under the invalid version
|
||||||
)
|
# sympy has an empty "0.5.13-hg" version
|
||||||
|
logger.warning('ignoring invalid version', version=version)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not use_pre_release and parsed_version.is_prerelease:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ret.append(RichResult(
|
||||||
|
version = version,
|
||||||
|
url = f'https://pypi.org/project/{package}/{version}/',
|
||||||
|
))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
84
nvchecker_source/rpmrepo.py
Normal file
84
nvchecker_source/rpmrepo.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2024 Jakub Ružička <jru@debian.org>, et al.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import gzip
|
||||||
|
import pathlib
|
||||||
|
import urllib
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
import lxml.etree
|
||||||
|
from nvchecker.api import session, AsyncCache, Entry, KeyManager, VersionResult
|
||||||
|
|
||||||
|
|
||||||
|
# XML namespaces used in repodata (dead links haha)
|
||||||
|
NS = {
|
||||||
|
'common': 'http://linux.duke.edu/metadata/common',
|
||||||
|
'repo': 'http://linux.duke.edu/metadata/repo',
|
||||||
|
'rpm': 'http://linux.duke.edu/metadata/rpm'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def get_version(
|
||||||
|
name: str, conf: Entry, *,
|
||||||
|
cache: AsyncCache, keymanager: KeyManager,
|
||||||
|
**kwargs,
|
||||||
|
) -> VersionResult:
|
||||||
|
repo = conf['repo']
|
||||||
|
arch = conf.get('arch', 'binary')
|
||||||
|
pkg = conf.get('pkg')
|
||||||
|
if not pkg:
|
||||||
|
pkg = conf.get('rpmrepo', name)
|
||||||
|
|
||||||
|
repo_url = urllib.parse.urlparse(repo)
|
||||||
|
repo_path = pathlib.PurePosixPath(repo_url.path)
|
||||||
|
|
||||||
|
# get the url of repomd.xml
|
||||||
|
repomd_path = repo_path / 'repodata' / 'repomd.xml'
|
||||||
|
repomd_url = repo_url._replace(path=str(repomd_path)).geturl()
|
||||||
|
# download repomd.xml (use cache)
|
||||||
|
repomd_body = await cache.get(repomd_url, get_file) # type: ignore
|
||||||
|
# parse repomd.xml
|
||||||
|
repomd_xml = lxml.etree.fromstring(repomd_body)
|
||||||
|
|
||||||
|
# get the url of *primary.xml.gz
|
||||||
|
primary_element = repomd_xml.find('repo:data[@type="primary"]/repo:location', namespaces=NS)
|
||||||
|
primary_path = repo_path / primary_element.get('href') # type: ignore
|
||||||
|
primary_url = repo_url._replace(path=str(primary_path)).geturl()
|
||||||
|
# download and decompress *primary.xml.gz (use cache)
|
||||||
|
primary_body = await cache.get(primary_url, get_file_gz) # type: ignore
|
||||||
|
# parse *primary.xml metadata
|
||||||
|
metadata = lxml.etree.fromstring(primary_body)
|
||||||
|
|
||||||
|
# use set to eliminate duplication
|
||||||
|
versions_set: Set[str] = set()
|
||||||
|
# iterate package metadata
|
||||||
|
for el in metadata.findall(f'common:package[common:name="{pkg}"]', namespaces=NS):
|
||||||
|
pkg_arch = el.findtext('common:arch', namespaces=NS)
|
||||||
|
|
||||||
|
# filter bych arch
|
||||||
|
if arch == 'binary':
|
||||||
|
if pkg_arch == 'src':
|
||||||
|
continue
|
||||||
|
elif arch != 'any':
|
||||||
|
if pkg_arch != arch:
|
||||||
|
continue
|
||||||
|
|
||||||
|
version_info = el.find('common:version', namespaces=NS)
|
||||||
|
version = version_info.get('ver') # type: ignore
|
||||||
|
versions_set.add(version) # type: ignore
|
||||||
|
|
||||||
|
versions = list(versions_set)
|
||||||
|
return versions # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
async def get_file(url: str) -> bytes:
|
||||||
|
res = await session.get(url)
|
||||||
|
return res.body
|
||||||
|
|
||||||
|
|
||||||
|
async def get_file_gz(url: str) -> bytes:
|
||||||
|
res = await session.get(url)
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
return await loop.run_in_executor(
|
||||||
|
None, gzip.decompress, res.body)
|
33
nvchecker_source/snapcraft.py
Normal file
33
nvchecker_source/snapcraft.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2025 Maxim Slipenko <maxim@slipenko.com>, et al.
|
||||||
|
|
||||||
|
from nvchecker.api import (
|
||||||
|
GetVersionError
|
||||||
|
)
|
||||||
|
from nvchecker.httpclient.base import HTTPError
|
||||||
|
|
||||||
|
URL="https://api.snapcraft.io/v2/snaps/info/%(snap)s"
|
||||||
|
|
||||||
|
async def get_version(
|
||||||
|
name: str, conf, *,
|
||||||
|
cache, keymanager,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
snap = conf.get("snap")
|
||||||
|
channel = conf.get("channel")
|
||||||
|
|
||||||
|
result = await cache.get_json(
|
||||||
|
URL % { "snap": snap },
|
||||||
|
headers={
|
||||||
|
"Snap-Device-Series": "16",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except HTTPError:
|
||||||
|
raise GetVersionError(f"Failed to request snap info for {snap}")
|
||||||
|
|
||||||
|
for c in result['channel-map']:
|
||||||
|
if c['channel']['name'] == channel:
|
||||||
|
return c['version']
|
||||||
|
|
||||||
|
raise GetVersionError(f"Failed to find version for {snap}")
|
|
@ -5,6 +5,7 @@ build-backend = "setuptools.build_meta"
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
# addopts = -n auto
|
# addopts = -n auto
|
||||||
asyncio_mode = "strict"
|
asyncio_mode = "strict"
|
||||||
|
asyncio_default_fixture_loop_scope = "session"
|
||||||
|
|
||||||
# build and upload
|
# build and upload
|
||||||
# rm -rf dist && python -m build --no-isolation && twine check dist/* && twine upload dist/*
|
# rm -rf dist && python -m build --no-isolation && twine check dist/* && twine upload dist/*
|
||||||
|
|
|
@ -2,11 +2,6 @@
|
||||||
oldver = "old_ver.json"
|
oldver = "old_ver.json"
|
||||||
newver = "new_ver.json"
|
newver = "new_ver.json"
|
||||||
|
|
||||||
[vim]
|
|
||||||
source = "regex"
|
|
||||||
regex = "7\\.3\\.\\d+"
|
|
||||||
url = "http://ftp.vim.org/pub/vim/patches/7.3/"
|
|
||||||
|
|
||||||
[google-chrome]
|
[google-chrome]
|
||||||
source = "cmd"
|
source = "cmd"
|
||||||
cmd = '''wget -qO- http://dl.google.com/linux/chrome/rpm/stable/x86_64/repodata/other.xml.gz | zgrep -A1 "google-chrome-stable" | awk -F\" '/version/ {print $4"-"$6}' '''
|
cmd = '''wget -qO- http://dl.google.com/linux/chrome/rpm/stable/x86_64/repodata/other.xml.gz | zgrep -A1 "google-chrome-stable" | awk -F\" '/version/ {print $4"-"$6}' '''
|
||||||
|
@ -25,17 +20,13 @@ github = "lilydjwg/nvchecker"
|
||||||
[ssed]
|
[ssed]
|
||||||
source = "regex"
|
source = "regex"
|
||||||
regex = "The current version is ([\\d.]+)\\."
|
regex = "The current version is ([\\d.]+)\\."
|
||||||
url = "http://sed.sourceforge.net/grabbag/ssed/"
|
url = "https://sed.sourceforge.net/grabbag/ssed/"
|
||||||
proxy = "http://localhost:8087"
|
proxy = "http://localhost:8087"
|
||||||
|
|
||||||
[PySide]
|
[PySide]
|
||||||
source = "pypi"
|
source = "pypi"
|
||||||
pypi = "PySide"
|
pypi = "nvchecker"
|
||||||
|
|
||||||
[test]
|
[test]
|
||||||
source = "manual"
|
source = "manual"
|
||||||
manual = "0.1"
|
manual = "0.1"
|
||||||
|
|
||||||
["Sparkle Test App"]
|
|
||||||
source = "sparkle"
|
|
||||||
sparkle = "https://sparkle-project.org/files/sparkletestcast.xml"
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ _handler_precedence = (
|
||||||
BOOL_KEYS = [
|
BOOL_KEYS = [
|
||||||
'strip_release', 'use_last_modified',
|
'strip_release', 'use_last_modified',
|
||||||
'use_latest_release', 'use_latest_tag',
|
'use_latest_release', 'use_latest_tag',
|
||||||
'use_max_tag', 'use_pre_release',
|
'use_max_release', 'use_max_tag', 'use_pre_release',
|
||||||
]
|
]
|
||||||
|
|
||||||
INT_KEYS = [
|
INT_KEYS = [
|
||||||
|
|
40
scripts/run_cached_tests
Executable file
40
scripts/run_cached_tests
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
mitmdump=${mitmdump:-mitmdump}
|
||||||
|
|
||||||
|
if [[ -f ~/.mitmproxy/nvdump ]]; then
|
||||||
|
$mitmdump -S ~/.mitmproxy/nvdump -p 7890 --ignore-hosts '127\.0\.0\.1' --server-replay-reuse --server-replay-extra=forward -w newdump >mitmdump_output &
|
||||||
|
else
|
||||||
|
$mitmdump -w ~/.mitmproxy/nvdump -p 7890 --ignore-hosts '127\.0\.0\.1' >mitmdump_output &
|
||||||
|
fi
|
||||||
|
|
||||||
|
mitm_pid=$!
|
||||||
|
|
||||||
|
on_exit () {
|
||||||
|
kill -INT $mitm_pid
|
||||||
|
|
||||||
|
if [[ -s newdump ]]; then
|
||||||
|
cat newdump >> ~/.mitmproxy/nvdump
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat mitmdump_output
|
||||||
|
}
|
||||||
|
|
||||||
|
trap on_exit EXIT
|
||||||
|
|
||||||
|
if [[ -f keyfile.toml ]]; then
|
||||||
|
export KEYFILE=keyfile.toml
|
||||||
|
fi
|
||||||
|
|
||||||
|
for _ in {1..10}; do
|
||||||
|
if [[ -s ~/.mitmproxy/mitmproxy-ca-cert.pem ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
export SSL_CERT_FILE=$HOME/.mitmproxy/mitmproxy-ca-cert.pem
|
||||||
|
export GIT_SSL_CAINFO=$SSL_CERT_FILE
|
||||||
|
export http_proxy=http://localhost:7890 https_proxy=http://localhost:7890
|
||||||
|
|
||||||
|
pytest
|
|
@ -29,6 +29,7 @@ classifiers =
|
||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
Programming Language :: Python :: 3.11
|
Programming Language :: Python :: 3.11
|
||||||
Programming Language :: Python :: 3.12
|
Programming Language :: Python :: 3.12
|
||||||
|
Programming Language :: Python :: 3.13
|
||||||
Topic :: Internet
|
Topic :: Internet
|
||||||
Topic :: Internet :: WWW/HTTP
|
Topic :: Internet :: WWW/HTTP
|
||||||
Topic :: Software Development
|
Topic :: Software Development
|
||||||
|
@ -38,10 +39,10 @@ classifiers =
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
zip_safe = True
|
zip_safe = True
|
||||||
|
python_requires = >=3.8
|
||||||
|
|
||||||
packages = find_namespace:
|
packages = find_namespace:
|
||||||
install_requires =
|
install_requires =
|
||||||
setuptools; python_version<"3.8"
|
|
||||||
tomli; python_version<"3.11"
|
tomli; python_version<"3.11"
|
||||||
structlog
|
structlog
|
||||||
platformdirs
|
platformdirs
|
||||||
|
@ -63,6 +64,8 @@ pypi =
|
||||||
packaging
|
packaging
|
||||||
htmlparser =
|
htmlparser =
|
||||||
lxml
|
lxml
|
||||||
|
rpmrepo =
|
||||||
|
lxml
|
||||||
jq =
|
jq =
|
||||||
jq
|
jq
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import tempfile
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.skipif(shutil.which('makepkg') is None, reason='requires makepkg command'),
|
pytest.mark.skipif(shutil.which('makepkg') is None, reason='requires makepkg command'),
|
||||||
pytest.mark.skipif(shutil.which('repo-add') is None, reason='requires repo-add command')
|
pytest.mark.skipif(shutil.which('repo-add') is None, reason='requires repo-add command')
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,7 @@ import tempfile
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.skipif(shutil.which('pacman') is None, reason='requires pacman command'),
|
pytest.mark.skipif(shutil.which('pacman') is None, reason='requires pacman command'),
|
||||||
pytest.mark.skipif(shutil.which('fakeroot') is None, reason='requires fakeroot command'),
|
pytest.mark.skipif(shutil.which('fakeroot') is None, reason='requires fakeroot command'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
# Copyright (c) 2017 Chih-Hsuan Yen <yan12125 at gmail dot com>
|
# Copyright (c) 2017 Chih-Hsuan Yen <yan12125 at gmail dot com>
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_android_addon(get_version):
|
async def test_android_addon(get_version):
|
||||||
assert await get_version("android-google-play-apk-expansion", {
|
assert await get_version("android-google-play-apk-expansion", {
|
||||||
"source": "android_sdk",
|
"source": "android_sdk",
|
||||||
|
@ -13,11 +14,12 @@ async def test_android_addon(get_version):
|
||||||
}) == "1.r03"
|
}) == "1.r03"
|
||||||
|
|
||||||
async def test_android_package(get_version):
|
async def test_android_package(get_version):
|
||||||
assert await get_version("android-sdk-cmake", {
|
version = await get_version("android-sdk-cmake", {
|
||||||
"source": "android_sdk",
|
"source": "android_sdk",
|
||||||
"android_sdk": "cmake;",
|
"android_sdk": "cmake;",
|
||||||
"repo": "package",
|
"repo": "package",
|
||||||
}) == "3.22.1"
|
})
|
||||||
|
assert version.startswith("3.")
|
||||||
|
|
||||||
|
|
||||||
async def test_android_package_channel(get_version):
|
async def test_android_package_channel(get_version):
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_anitya(get_version):
|
async def test_anitya(get_version):
|
||||||
version = await get_version("shutter", {
|
version = await get_version("shutter", {
|
||||||
|
@ -13,3 +13,10 @@ async def test_anitya(get_version):
|
||||||
"anitya": "fedora/shutter",
|
"anitya": "fedora/shutter",
|
||||||
})
|
})
|
||||||
assert re.match(r"[0-9.]+", version)
|
assert re.match(r"[0-9.]+", version)
|
||||||
|
|
||||||
|
async def test_anitya_by_id(get_version):
|
||||||
|
version = await get_version("shutter", {
|
||||||
|
"source": "anitya",
|
||||||
|
"anitya_id": "4813",
|
||||||
|
})
|
||||||
|
assert re.match(r"[0-9.]+", version)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_apt(get_version):
|
async def test_apt(get_version):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky
|
@pytest.mark.flaky
|
||||||
async def test_archpkg(get_version):
|
async def test_archpkg(get_version):
|
||||||
|
@ -26,9 +26,9 @@ async def test_archpkg_provided(get_version):
|
||||||
|
|
||||||
@pytest.mark.flaky
|
@pytest.mark.flaky
|
||||||
async def test_archpkg_provided_strip(get_version):
|
async def test_archpkg_provided_strip(get_version):
|
||||||
assert await get_version("jsoncpp", {
|
int(await get_version("jsoncpp", {
|
||||||
"source": "archpkg",
|
"source": "archpkg",
|
||||||
"provided": "libjsoncpp.so",
|
"provided": "libjsoncpp.so",
|
||||||
"strip_release": True,
|
"strip_release": True,
|
||||||
}) == "25"
|
}))
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"),
|
pytestmark = [pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net]
|
||||||
pytest.mark.skipif(os.environ.get('TRAVIS') == 'true',
|
|
||||||
reason="fail too often")]
|
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_aur(get_version):
|
async def test_aur(get_version):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_bitbucket(get_version):
|
async def test_bitbucket(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
async def test_cache(run_str_multi):
|
async def test_cache(run_str_multi):
|
||||||
conf = r'''
|
conf = r'''
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
async def test_cmd(get_version):
|
async def test_cmd(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2021 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2021 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
async def test_combiner(run_str_multi):
|
async def test_combiner(run_str_multi):
|
||||||
conf = r'''
|
conf = r'''
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2020 Chih-Hsuan Yen <yan12125 at gmail dot com>
|
# Copyright (c) 2020 Chih-Hsuan Yen <yan12125 at gmail dot com>
|
||||||
|
|
||||||
import pytest
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
|
||||||
|
import pytest
|
||||||
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net,
|
||||||
|
pytest.mark.skipif(bool(os.environ.get('GITHUB_RUN_ID')), reason="400 very often")]
|
||||||
|
|
||||||
async def test_container(get_version):
|
async def test_container(get_version):
|
||||||
assert await get_version("hello-world", {
|
assert await get_version("hello-world", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_cpan(get_version):
|
async def test_cpan(get_version):
|
||||||
assert await get_version("POE-Component-Server-HTTPServer", {
|
assert await get_version("POE-Component-Server-HTTPServer", {
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
# Copyright (c) 2022 Pekka Ristola <pekkarr [at] protonmail [dot] com>, et al.
|
# Copyright (c) 2022 Pekka Ristola <pekkarr [at] protonmail [dot] com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_cran(get_version):
|
async def test_cran(get_version):
|
||||||
assert await get_version("xml2", {
|
assert await get_version("xml2", {
|
||||||
"source": "cran",
|
"source": "cran",
|
||||||
}) == "1.3.6"
|
}) == "1.3.7"
|
||||||
|
|
|
@ -2,9 +2,29 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_cratesio(get_version):
|
async def test_cratesio(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "cratesio",
|
"source": "cratesio",
|
||||||
}) == "1.1.0"
|
}) == "1.1.0"
|
||||||
|
|
||||||
|
async def test_cratesio_list(get_version):
|
||||||
|
assert await get_version("example", {
|
||||||
|
"source": "cratesio",
|
||||||
|
"include_regex": r"^1\.0.*",
|
||||||
|
}) == "1.0.2"
|
||||||
|
|
||||||
|
async def test_cratesio_skip_prerelease(get_version):
|
||||||
|
with pytest.raises(RuntimeError, match='include_regex matched no versions'):
|
||||||
|
await get_version("cargo-lock", {
|
||||||
|
"source": "cratesio",
|
||||||
|
"include_regex": r".*-.*",
|
||||||
|
})
|
||||||
|
|
||||||
|
async def test_cratesio_use_prerelease(get_version):
|
||||||
|
await get_version("cargo-lock", {
|
||||||
|
"source": "cratesio",
|
||||||
|
"use_pre_release": "true",
|
||||||
|
"include_regex": r".*-.*",
|
||||||
|
})
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_debianpkg(get_version):
|
async def test_debianpkg(get_version):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_gems(get_version):
|
async def test_gems(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2020 Felix Yan <felixonmars@archlinux.org>, et al.
|
# Copyright (c) 2020 Felix Yan <felixonmars@archlinux.org>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_git(get_version):
|
async def test_git(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"),
|
pytestmark = [pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net]
|
pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
|
@ -10,8 +10,8 @@ async def test_gitea(get_version):
|
||||||
ver = await get_version("example", {
|
ver = await get_version("example", {
|
||||||
"source": "gitea",
|
"source": "gitea",
|
||||||
"gitea": "gitea/tea"})
|
"gitea": "gitea/tea"})
|
||||||
assert len(ver) == 8
|
assert ver.startswith('20')
|
||||||
assert ver.isdigit()
|
assert 'T' in ver
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_gitea_max_tag_with_include(get_version):
|
async def test_gitea_max_tag_with_include(get_version):
|
||||||
|
|
|
@ -5,7 +5,7 @@ import re
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"),
|
pytestmark = [pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net,
|
||||||
pytest.mark.usefixtures('keyfile')]
|
pytest.mark.usefixtures('keyfile')]
|
||||||
|
|
||||||
|
@ -36,6 +36,22 @@ async def test_github_latest_release_include_prereleases(get_version):
|
||||||
"include_prereleases": True,
|
"include_prereleases": True,
|
||||||
}) == "v0.0.1-pre"
|
}) == "v0.0.1-pre"
|
||||||
|
|
||||||
|
async def test_github_latest_release_with_release_name(get_version):
|
||||||
|
version = await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "mamba-org/mamba",
|
||||||
|
"use_latest_release": True,
|
||||||
|
})
|
||||||
|
assert version.startswith('20') # tag name
|
||||||
|
|
||||||
|
version = await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "mamba-org/mamba",
|
||||||
|
"use_latest_release": True,
|
||||||
|
"use_release_name": True,
|
||||||
|
})
|
||||||
|
assert not version.startswith('20') # release name
|
||||||
|
|
||||||
async def test_github_max_tag(get_version):
|
async def test_github_max_tag(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "github",
|
"source": "github",
|
||||||
|
@ -43,6 +59,20 @@ async def test_github_max_tag(get_version):
|
||||||
"use_max_tag": True,
|
"use_max_tag": True,
|
||||||
}) == "second_release"
|
}) == "second_release"
|
||||||
|
|
||||||
|
async def test_github_max_release(get_version):
|
||||||
|
assert await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "harry-sanabria/ReleaseTestRepo",
|
||||||
|
"use_max_release": True,
|
||||||
|
}) == "second_release"
|
||||||
|
|
||||||
|
assert await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "harry-sanabria/ReleaseTestRepo",
|
||||||
|
"use_max_release": True,
|
||||||
|
"use_release_name": True,
|
||||||
|
}) == "second_release"
|
||||||
|
|
||||||
async def test_github_max_tag_with_ignored(get_version):
|
async def test_github_max_tag_with_ignored(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "github",
|
"source": "github",
|
||||||
|
@ -51,6 +81,21 @@ async def test_github_max_tag_with_ignored(get_version):
|
||||||
"ignored": "second_release release3",
|
"ignored": "second_release release3",
|
||||||
}) == "first_release"
|
}) == "first_release"
|
||||||
|
|
||||||
|
async def test_github_max_release_with_ignored(get_version):
|
||||||
|
assert await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "harry-sanabria/ReleaseTestRepo",
|
||||||
|
"use_max_release": True,
|
||||||
|
"ignored": "second_release release3",
|
||||||
|
}) == "first_release"
|
||||||
|
assert await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "harry-sanabria/ReleaseTestRepo",
|
||||||
|
"use_max_release": True,
|
||||||
|
"ignored": "second_release",
|
||||||
|
"use_release_name": True,
|
||||||
|
}) == "release #3"
|
||||||
|
|
||||||
async def test_github_with_path(get_version):
|
async def test_github_with_path(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "github",
|
"source": "github",
|
||||||
|
@ -75,6 +120,16 @@ async def test_github_max_tag_with_include(get_version):
|
||||||
})
|
})
|
||||||
assert re.match(r'chrome-[\d.]+', version)
|
assert re.match(r'chrome-[\d.]+', version)
|
||||||
|
|
||||||
|
async def test_github_max_release_with_include(get_version):
|
||||||
|
version = await get_version("example", {
|
||||||
|
"source": "github",
|
||||||
|
"github": "EFForg/https-everywhere",
|
||||||
|
"use_max_release": True,
|
||||||
|
"use_release_name": True,
|
||||||
|
"include_regex": r"Release \d.*",
|
||||||
|
})
|
||||||
|
assert re.match(r'Release [\d.]+', version)
|
||||||
|
|
||||||
async def test_github_latest_tag(get_version):
|
async def test_github_latest_tag(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "github",
|
"source": "github",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_gitlab(get_version):
|
async def test_gitlab(get_version):
|
||||||
ver = await get_version("example", {
|
ver = await get_version("example", {
|
||||||
|
|
|
@ -12,17 +12,19 @@ except ImportError:
|
||||||
lxml_available = False
|
lxml_available = False
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net,
|
||||||
pytest.mark.skipif(not lxml_available, reason="needs lxml")
|
pytest.mark.skipif(not lxml_available, reason="needs lxml")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_go(get_version):
|
async def test_go(get_version):
|
||||||
assert await get_version("one version", {
|
ver = await get_version("one version", {
|
||||||
"source": "go",
|
"source": "go",
|
||||||
"go": "github.com/caddyserver/replace-response",
|
"go": "github.com/caddyserver/replace-response",
|
||||||
}) == "v0.0.0-20231221003037-a85d4ddc11d6"
|
})
|
||||||
|
|
||||||
|
assert ver.startswith("v0.0.0-")
|
||||||
|
|
||||||
assert await get_version("multiple version", {
|
assert await get_version("multiple version", {
|
||||||
"source": "go",
|
"source": "go",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_hackage(get_version):
|
async def test_hackage(get_version):
|
||||||
|
|
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
lxml_available = False
|
lxml_available = False
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net,
|
||||||
pytest.mark.skipif(not lxml_available, reason="needs lxml"),
|
pytest.mark.skipif(not lxml_available, reason="needs lxml"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,24 +1,31 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2021 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2021,2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_httpbin
|
|
||||||
assert pytest_httpbin # for pyflakes
|
|
||||||
|
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
httpbin_available = True
|
||||||
|
try:
|
||||||
|
import pytest_httpbin
|
||||||
|
assert pytest_httpbin # for pyflakes
|
||||||
|
except ImportError:
|
||||||
|
httpbin_available = False
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
|
@pytest.mark.needs_net
|
||||||
async def test_redirection(get_version):
|
async def test_redirection(get_version):
|
||||||
assert await get_version("unifiedremote", {
|
assert await get_version("unifiedremote", {
|
||||||
"source": "httpheader",
|
"source": "httpheader",
|
||||||
"url": "https://www.unifiedremote.com/download/linux-x64-deb",
|
"url": "https://www.unifiedremote.com/download/linux-x64-deb",
|
||||||
"regex": r'urserver-([\d.]+).deb',
|
"regex": r'urserver-([\d.]+).deb',
|
||||||
}) is not None
|
}) is not None
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not httpbin_available, reason="needs pytest_httpbin")
|
||||||
async def test_get_version_withtoken(get_version, httpbin):
|
async def test_get_version_withtoken(get_version, httpbin):
|
||||||
assert await get_version("unifiedremote", {
|
assert await get_version("unifiedremote", {
|
||||||
"source": "httpheader",
|
"source": "httpheader",
|
||||||
"url": httpbin.url + "/basic-auth/username/superpassword",
|
"url": httpbin.url + "/basic-auth/username/superpassword",
|
||||||
"httptoken": "Basic dXNlcm5hbWU6c3VwZXJwYXNzd29yZA==",
|
"httptoken": "Basic dXNlcm5hbWU6c3VwZXJwYXNzd29yZA==",
|
||||||
"header": "server",
|
"header": "server",
|
||||||
"regex": r'([0-9.]+)*',
|
"regex": r'([0-9.]+)*',
|
||||||
}) is not None
|
}) is not None
|
||||||
|
|
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
jq_available = False
|
jq_available = False
|
||||||
|
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net,
|
||||||
pytest.mark.skipif(not jq_available, reason="needs jq"),
|
pytest.mark.skipif(not jq_available, reason="needs jq"),
|
||||||
]
|
]
|
||||||
|
|
16
tests/test_launchpad.py
Normal file
16
tests/test_launchpad.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# MIT Licensed
|
||||||
|
# Copyright (c) 2024 Bert Peters <bertptrs@archlinux.org>, et al.
|
||||||
|
import pytest
|
||||||
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
|
@pytest.mark.flaky(reruns=10)
|
||||||
|
async def test_launchpad(get_version):
|
||||||
|
version = await get_version(
|
||||||
|
"sakura",
|
||||||
|
{
|
||||||
|
"source": "launchpad",
|
||||||
|
"launchpad": "sakura",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert version == '3.8.8'
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
async def test_manual(get_version):
|
async def test_manual(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [
|
pytestmark = [
|
||||||
pytest.mark.asyncio(scope="session"),
|
pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net,
|
pytest.mark.needs_net,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
async def test_mercurial(get_version):
|
async def test_mercurial(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "mercurial",
|
"source": "mercurial",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_npm(get_version):
|
async def test_npm(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
25
tests/test_opam.py
Normal file
25
tests/test_opam.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2024 Daniel Peukert <daniel@peukert.cc>, et al.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
|
async def test_opam_official(get_version):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "opam",
|
||||||
|
"pkg": "omigrate",
|
||||||
|
}) == "0.3.2"
|
||||||
|
|
||||||
|
async def test_opam_coq(get_version):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "opam",
|
||||||
|
"repo": "https://coq.inria.fr/opam/released",
|
||||||
|
"pkg": "coq-abp",
|
||||||
|
}) == "8.10.0"
|
||||||
|
|
||||||
|
async def test_opam_coq_trailing_slash(get_version):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "opam",
|
||||||
|
"repo": "https://coq.inria.fr/opam/released/",
|
||||||
|
"pkg": "coq-abp",
|
||||||
|
}) == "8.10.0"
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2021 Th3Whit3Wolf <the.white.wolf.is.1337@gmail.com>, et al.
|
# Copyright (c) 2013-2021 Th3Whit3Wolf <the.white.wolf.is.1337@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_openvsx(get_version):
|
async def test_openvsx(get_version):
|
||||||
assert await get_version("usernamehw.indent-one-space", {
|
assert await get_version("usernamehw.indent-one-space", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_packagist(get_version):
|
async def test_packagist(get_version):
|
||||||
assert await get_version("butterfly/example-web-application", {
|
assert await get_version("butterfly/example-web-application", {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"),
|
pytestmark = [pytest.mark.asyncio,
|
||||||
pytest.mark.skipif(shutil.which("pacman") is None,
|
pytest.mark.skipif(shutil.which("pacman") is None,
|
||||||
reason="requires pacman command"),
|
reason="requires pacman command"),
|
||||||
pytest.mark.skipif(not pathlib.Path("/var/lib/pacman/sync/core.db").exists(),
|
pytest.mark.skipif(not pathlib.Path("/var/lib/pacman/sync/core.db").exists(),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2020 Felix Yan <felixonmars@archlinux.org>, et al.
|
# Copyright (c) 2020 Felix Yan <felixonmars@archlinux.org>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_pagure(get_version):
|
async def test_pagure(get_version):
|
||||||
ver = await get_version("example", {
|
ver = await get_version("example", {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_pypi(get_version):
|
async def test_pypi(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
@ -20,3 +20,20 @@ async def test_pypi_pre_release(get_version):
|
||||||
"source": "pypi",
|
"source": "pypi",
|
||||||
"use_pre_release": 1,
|
"use_pre_release": 1,
|
||||||
}) == "1.0.1a1"
|
}) == "1.0.1a1"
|
||||||
|
|
||||||
|
async def test_pypi_list(get_version):
|
||||||
|
assert await get_version("urllib3", {
|
||||||
|
"source": "pypi",
|
||||||
|
"include_regex": "^1\\..*",
|
||||||
|
}) == "1.26.20"
|
||||||
|
|
||||||
|
async def test_pypi_invalid_version(get_version):
|
||||||
|
await get_version("sympy", {
|
||||||
|
"source": "pypi",
|
||||||
|
})
|
||||||
|
|
||||||
|
async def test_pypi_yanked_version(get_version):
|
||||||
|
assert await get_version("urllib3", {
|
||||||
|
"source": "pypi",
|
||||||
|
"include_regex": "^(1\\..*)|(2\\.0\\.[0,1])",
|
||||||
|
}) == "1.26.20"
|
||||||
|
|
|
@ -1,130 +1,138 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020,2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_httpbin
|
|
||||||
assert pytest_httpbin # for pyflakes
|
|
||||||
|
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
httpbin_available = True
|
||||||
|
try:
|
||||||
|
import pytest_httpbin
|
||||||
|
assert pytest_httpbin # for pyflakes
|
||||||
|
except ImportError:
|
||||||
|
httpbin_available = False
|
||||||
|
|
||||||
|
pytestmark = [
|
||||||
|
pytest.mark.asyncio,
|
||||||
|
pytest.mark.skipif(not httpbin_available, reason="needs pytest_httpbin"),
|
||||||
|
]
|
||||||
|
|
||||||
def base64_encode(s):
|
def base64_encode(s):
|
||||||
return base64.b64encode(s.encode('utf-8')).decode('ascii')
|
return base64.b64encode(s.encode('utf-8')).decode('ascii')
|
||||||
|
|
||||||
async def test_regex_httpbin_default_user_agent(get_version, httpbin):
|
async def test_regex_httpbin_default_user_agent(get_version, httpbin):
|
||||||
ua = await get_version("example", {
|
ua = await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/get",
|
"url": httpbin.url + "/get",
|
||||||
"regex": r'"User-Agent":\s*"([^"]+)"',
|
"regex": r'"User-Agent":\s*"([^"]+)"',
|
||||||
})
|
})
|
||||||
assert ua.startswith("lilydjwg/nvchecker")
|
assert ua.startswith("lilydjwg/nvchecker")
|
||||||
|
|
||||||
async def test_regex_httpbin_user_agent(get_version, httpbin):
|
async def test_regex_httpbin_user_agent(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/get",
|
"url": httpbin.url + "/get",
|
||||||
"regex": r'"User-Agent":\s*"(\w+)"',
|
"regex": r'"User-Agent":\s*"(\w+)"',
|
||||||
"user_agent": "Meow",
|
"user_agent": "Meow",
|
||||||
}) == "Meow"
|
}) == "Meow"
|
||||||
|
|
||||||
async def test_regex(get_version, httpbin):
|
async def test_regex(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/base64/" + base64_encode("version 1.12 released"),
|
"url": httpbin.url + "/base64/" + base64_encode("version 1.12 released"),
|
||||||
"regex": r'version ([0-9.]+)',
|
"regex": r'version ([0-9.]+)',
|
||||||
}) == "1.12"
|
}) == "1.12"
|
||||||
|
|
||||||
async def test_missing_ok(get_version, httpbin):
|
async def test_missing_ok(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/base64/" + base64_encode("something not there"),
|
"url": httpbin.url + "/base64/" + base64_encode("something not there"),
|
||||||
"regex": "foobar",
|
"regex": "foobar",
|
||||||
"missing_ok": True,
|
"missing_ok": True,
|
||||||
}) is None
|
}) is None
|
||||||
|
|
||||||
async def test_missing(get_version, httpbin):
|
async def test_missing(get_version, httpbin):
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
await get_version("example", {
|
await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/base64/" + base64_encode("something not there"),
|
"url": httpbin.url + "/base64/" + base64_encode("something not there"),
|
||||||
"regex": "foobar",
|
"regex": "foobar",
|
||||||
})
|
})
|
||||||
|
|
||||||
async def test_multi_group(get_version, httpbin):
|
async def test_multi_group(get_version, httpbin):
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
await get_version("example", {
|
await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/base64/" + base64_encode("1.2"),
|
"url": httpbin.url + "/base64/" + base64_encode("1.2"),
|
||||||
"regex": r"(\d+)\.(\d+)",
|
"regex": r"(\d+)\.(\d+)",
|
||||||
})
|
})
|
||||||
|
|
||||||
async def test_regex_with_tokenBasic(get_version, httpbin):
|
async def test_regex_with_tokenBasic(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/basic-auth/username/superpassword",
|
"url": httpbin.url + "/basic-auth/username/superpassword",
|
||||||
"httptoken": "Basic dXNlcm5hbWU6c3VwZXJwYXNzd29yZA==",
|
"httptoken": "Basic dXNlcm5hbWU6c3VwZXJwYXNzd29yZA==",
|
||||||
"regex": r'"user":\s*"([a-w]+)"',
|
"regex": r'"user":\s*"([a-w]+)"',
|
||||||
}) == "username"
|
}) == "username"
|
||||||
|
|
||||||
async def test_regex_with_tokenBearer(get_version, httpbin):
|
async def test_regex_with_tokenBearer(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/bearer",
|
"url": httpbin.url + "/bearer",
|
||||||
"httptoken": "Bearer username:password",
|
"httptoken": "Bearer username:password",
|
||||||
"regex": r'"token":\s*"([a-w]+):.*"',
|
"regex": r'"token":\s*"([a-w]+):.*"',
|
||||||
}) == "username"
|
}) == "username"
|
||||||
|
|
||||||
async def test_regex_no_verify_ssl(get_version, httpbin_secure):
|
async def test_regex_no_verify_ssl(get_version, httpbin_secure):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin_secure.url + "/base64/" + base64_encode("version 1.12 released"),
|
"url": httpbin_secure.url + "/base64/" + base64_encode("version 1.12 released"),
|
||||||
"regex": r'version ([0-9.]+)',
|
"regex": r'version ([0-9.]+)',
|
||||||
"verify_cert": False,
|
"verify_cert": False,
|
||||||
}) == "1.12"
|
}) == "1.12"
|
||||||
|
|
||||||
async def test_regex_bad_ssl(get_version, httpbin_secure):
|
async def test_regex_bad_ssl(get_version, httpbin_secure):
|
||||||
try:
|
try:
|
||||||
await get_version("example", {
|
await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin_secure.url + "/base64/" + base64_encode("version 1.12 released"),
|
"url": httpbin_secure.url + "/base64/" + base64_encode("version 1.12 released"),
|
||||||
"regex": r'version ([0-9.]+)',
|
"regex": r'version ([0-9.]+)',
|
||||||
})
|
})
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
assert False, 'certificate should not be trusted'
|
assert False, 'certificate should not be trusted'
|
||||||
|
|
||||||
async def test_regex_post(get_version, httpbin):
|
async def test_regex_post(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/post",
|
"url": httpbin.url + "/post",
|
||||||
"regex": r'"ABCDEF":\s*"(\w+)"',
|
"regex": r'"ABCDEF":\s*"(\w+)"',
|
||||||
"post_data": "ABCDEF=234&CDEFG=xyz"
|
"post_data": "ABCDEF=234&CDEFG=xyz"
|
||||||
}) == "234"
|
}) == "234"
|
||||||
|
|
||||||
async def test_regex_post2(get_version, httpbin):
|
async def test_regex_post2(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/post",
|
"url": httpbin.url + "/post",
|
||||||
"regex": r'"CDEFG":\s*"(\w+)"',
|
"regex": r'"CDEFG":\s*"(\w+)"',
|
||||||
"post_data": "ABCDEF=234&CDEFG=xyz"
|
"post_data": "ABCDEF=234&CDEFG=xyz"
|
||||||
}) == "xyz"
|
}) == "xyz"
|
||||||
|
|
||||||
async def test_regex_post_json(get_version, httpbin):
|
async def test_regex_post_json(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/post",
|
"url": httpbin.url + "/post",
|
||||||
"regex": r'"ABCDEF":\s*(\w+)',
|
"regex": r'"ABCDEF":\s*(\w+)',
|
||||||
"post_data": '{"ABCDEF":234,"CDEFG":"xyz"}',
|
"post_data": '{"ABCDEF":234,"CDEFG":"xyz"}',
|
||||||
"post_data_type": "application/json"
|
"post_data_type": "application/json"
|
||||||
}) == "234"
|
}) == "234"
|
||||||
|
|
||||||
async def test_regex_post_json2(get_version, httpbin):
|
async def test_regex_post_json2(get_version, httpbin):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
"source": "regex",
|
"source": "regex",
|
||||||
"url": httpbin.url + "/post",
|
"url": httpbin.url + "/post",
|
||||||
"regex": r'"CDEFG":\s*"(\w+)"',
|
"regex": r'"CDEFG":\s*"(\w+)"',
|
||||||
"post_data": '{"ABCDEF":234,"CDEFG":"xyz"}',
|
"post_data": '{"ABCDEF":234,"CDEFG":"xyz"}',
|
||||||
"post_data_type": "application/json"
|
"post_data_type": "application/json"
|
||||||
}) == "xyz"
|
}) == "xyz"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2019-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2019-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"),
|
pytestmark = [pytest.mark.asyncio,
|
||||||
pytest.mark.needs_net]
|
pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky(reruns=10)
|
@pytest.mark.flaky(reruns=10)
|
||||||
|
|
19
tests/test_rpmrepo.py
Normal file
19
tests/test_rpmrepo.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2024 Jakub Ružička <jru@debian.org>, et al.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
|
async def test_rpmrepo_fedora(get_version):
|
||||||
|
assert await get_version("knot_fedora-39", {
|
||||||
|
"source": "rpmrepo",
|
||||||
|
"pkg": "knot",
|
||||||
|
"repo": "http://ftp.sh.cvut.cz/fedora/linux/updates/39/Everything/x86_64/",
|
||||||
|
}) == "3.3.9"
|
||||||
|
|
||||||
|
async def test_rpmrepo_alma(get_version):
|
||||||
|
assert await get_version("knot_fedora-39", {
|
||||||
|
"source": "rpmrepo",
|
||||||
|
"pkg": "tmux",
|
||||||
|
"repo": "http://ftp.sh.cvut.cz/almalinux/9.5/BaseOS/x86_64/os/",
|
||||||
|
}) == "3.2a"
|
28
tests/test_snapcraft.py
Normal file
28
tests/test_snapcraft.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# MIT licensed
|
||||||
|
# Copyright (c) 2025 Maxim Slipenko <maxim@slipenko.com>, et al.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
|
async def test_snapcraft(get_version):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "snapcraft",
|
||||||
|
"snap": "test-snapd-public",
|
||||||
|
"channel": "edge",
|
||||||
|
}) == "2.0"
|
||||||
|
|
||||||
|
async def test_snapcraft_non_existent_snap(get_version):
|
||||||
|
with pytest.raises(RuntimeError, match='Failed to request snap info for not-existent-snap'):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "snapcraft",
|
||||||
|
"snap": "not-existent-snap",
|
||||||
|
"channel": "stable",
|
||||||
|
})
|
||||||
|
|
||||||
|
async def test_snapcraft_non_existent_channel(get_version):
|
||||||
|
with pytest.raises(RuntimeError, match='Failed to find version for test-snapd-public'):
|
||||||
|
assert await get_version("test", {
|
||||||
|
"source": "snapcraft",
|
||||||
|
"snap": "test-snapd-public",
|
||||||
|
"channel": "non-existent-channel",
|
||||||
|
})
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2020 Sunlei <guizaicn@gmail.com>
|
# Copyright (c) 2020 Sunlei <guizaicn@gmail.com>
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_sparkle(get_version):
|
async def test_sparkle(get_version):
|
||||||
assert await get_version('example', {
|
assert await get_version('example', {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2013-2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = pytest.mark.asyncio(scope="session")
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
async def test_substitute_prefix(get_version):
|
async def test_substitute_prefix(get_version):
|
||||||
assert await get_version("example", {
|
assert await get_version("example", {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
# MIT licensed
|
# MIT licensed
|
||||||
# Copyright (c) 2020 lilydjwg <lilydjwg@gmail.com>, et al.
|
# Copyright (c) 2020,2024 lilydjwg <lilydjwg@gmail.com>, et al.
|
||||||
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
# Copyright (c) 2017 Felix Yan <felixonmars@archlinux.org>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
@pytest.mark.flaky
|
@pytest.mark.flaky
|
||||||
async def test_ubuntupkg(get_version):
|
async def test_ubuntupkg(get_version):
|
||||||
assert await get_version("sigrok-firmware-fx2lafw", {
|
v = await get_version("sigrok-firmware-fx2lafw", {
|
||||||
"source": "ubuntupkg",
|
"source": "ubuntupkg",
|
||||||
}) == "0.1.7-1"
|
})
|
||||||
|
assert v.startswith("0.1.7-")
|
||||||
|
|
||||||
@pytest.mark.flaky
|
@pytest.mark.flaky
|
||||||
async def test_ubuntupkg_strip_release(get_version):
|
async def test_ubuntupkg_strip_release(get_version):
|
||||||
|
@ -25,7 +26,7 @@ async def test_ubuntupkg_suite(get_version):
|
||||||
"suite": "xenial",
|
"suite": "xenial",
|
||||||
}) == "0.1.2-1"
|
}) == "0.1.2-1"
|
||||||
|
|
||||||
@pytest.mark.flaky
|
@pytest.mark.flaky(reruns=10)
|
||||||
async def test_ubuntupkg_suite_with_paging(get_version):
|
async def test_ubuntupkg_suite_with_paging(get_version):
|
||||||
assert await get_version("ffmpeg", {
|
assert await get_version("ffmpeg", {
|
||||||
"source": "ubuntupkg",
|
"source": "ubuntupkg",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2013-2021 Th3Whit3Wolf <the.white.wolf.is.1337@gmail.com>, et al.
|
# Copyright (c) 2013-2021 Th3Whit3Wolf <the.white.wolf.is.1337@gmail.com>, et al.
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
pytestmark = [pytest.mark.asyncio(scope="session"), pytest.mark.needs_net]
|
pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
|
||||||
|
|
||||||
async def test_vsmarketplace(get_version):
|
async def test_vsmarketplace(get_version):
|
||||||
assert await get_version("usernamehw.indent-one-space", {
|
assert await get_version("usernamehw.indent-one-space", {
|
||||||
|
|
Loading…
Add table
Reference in a new issue