diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f53b8f9c..09e109f7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -8,6 +8,10 @@ on: - '*' - '!*rc*' +permissions: + contents: read + packages: write + jobs: docker-image: diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index 082b6ad1..665d2e0a 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -2,6 +2,9 @@ name: Regress on: workflow_dispatch +permissions: + contents: read + jobs: run-regress-tests: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6168ce89..702b61bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,6 +5,9 @@ on: tags: - '*' +permissions: + contents: write + jobs: make-release: diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml index 1ea9e21e..f19431fe 100644 --- a/.github/workflows/setup.yml +++ b/.github/workflows/setup.yml @@ -8,6 +8,9 @@ on: branches: - master +permissions: + contents: read + jobs: run-setup-minimal: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5c21751f..3074672e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,6 +10,9 @@ on: schedule: - cron: 1 0 * * * +permissions: + contents: read + jobs: run-tests: diff --git a/.readthedocs.yml b/.readthedocs.yml index 6ffd1fe1..ba02e805 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -9,13 +9,7 @@ build: python: install: - - method: pip - path: . - extra_requirements: - - docs - - s3 - - validator - - web + - requirements: docs/requirements.txt formats: - pdf diff --git a/docs/conf.py b/docs/conf.py index b1be93c0..79d1ad16 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,9 +15,8 @@ import sys from pathlib import Path -from ahriman import __version__ - +# support package imports basedir = Path(__file__).resolve().parent.parent / "src" sys.path.insert(0, str(basedir)) @@ -29,6 +28,7 @@ copyright = f"2021-{datetime.date.today().year}, ahriman team" author = "ahriman team" # The full version, including alpha/beta/rc tags +from ahriman import __version__ release = __version__ @@ -91,7 +91,13 @@ autoclass_content = "both" autodoc_member_order = "groupwise" -autodoc_mock_imports = ["cryptography", "pyalpm"] +autodoc_mock_imports = [ + "aioauth_client", + "aiohttp_security", + "aiohttp_session", + "cryptography", + "pyalpm", +] autodoc_default_options = { "no-undoc-members": True, diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..9fc2635b --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,128 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --group ../pyproject.toml:docs --extra s3 --extra validator --extra web --output-file ../docs/requirements.txt ../pyproject.toml +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.11.18 + # via + # ahriman (../pyproject.toml) + # aiohttp-cors + # aiohttp-jinja2 +aiohttp-cors==0.8.1 + # via ahriman (../pyproject.toml) +aiohttp-jinja2==1.6 + # via ahriman (../pyproject.toml) +aiosignal==1.3.2 + # via aiohttp +alabaster==1.0.0 + # via sphinx +argparse-manpage==4.6 + # via ahriman (../pyproject.toml:docs) +attrs==25.3.0 + # via aiohttp +babel==2.17.0 + # via sphinx +bcrypt==4.3.0 + # via ahriman (../pyproject.toml) +boto3==1.38.11 + # via ahriman (../pyproject.toml) +botocore==1.38.11 + # via + # boto3 + # s3transfer +cerberus==1.3.7 + # via ahriman (../pyproject.toml) +certifi==2025.4.26 + # via requests +charset-normalizer==3.4.2 + # via requests +docutils==0.21.2 + # via + # sphinx + # sphinx-argparse + # sphinx-rtd-theme +frozenlist==1.6.0 + # via + # aiohttp + # aiosignal +idna==3.10 + # via + # requests + # yarl +imagesize==1.4.1 + # via sphinx +inflection==0.5.1 + # via ahriman (../pyproject.toml) +jinja2==3.1.6 + # via + # aiohttp-jinja2 + # sphinx +jmespath==1.0.1 + # via + # boto3 + # botocore +markupsafe==3.0.2 + # via jinja2 +multidict==6.4.3 + # via + # aiohttp + # yarl +packaging==25.0 + # via sphinx +propcache==0.3.1 + # via + # aiohttp + # yarl +pydeps==3.0.1 + # via ahriman (../pyproject.toml:docs) +pyelftools==0.32 + # via ahriman (../pyproject.toml) +pygments==2.19.1 + # via sphinx +python-dateutil==2.9.0.post0 + # via botocore +requests==2.32.3 + # via + # ahriman (../pyproject.toml) + # sphinx +roman-numerals-py==3.1.0 + # via sphinx +s3transfer==0.12.0 + # via boto3 +shtab==1.7.2 + # via ahriman (../pyproject.toml:docs) +six==1.17.0 + # via python-dateutil +snowballstemmer==3.0.0.1 + # via sphinx +sphinx==8.2.3 + # via + # ahriman (../pyproject.toml:docs) + # sphinx-argparse + # sphinx-rtd-theme + # sphinxcontrib-jquery +sphinx-argparse==0.5.2 + # via ahriman (../pyproject.toml:docs) +sphinx-rtd-theme==3.0.2 + # via ahriman (../pyproject.toml:docs) +sphinxcontrib-applehelp==2.0.0 + # via sphinx +sphinxcontrib-devhelp==2.0.0 + # via sphinx +sphinxcontrib-htmlhelp==2.1.0 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==2.0.0 + # via sphinx +sphinxcontrib-serializinghtml==2.0.0 + # via sphinx +stdlib-list==0.11.1 + # via pydeps +urllib3==2.4.0 + # via + # botocore + # requests +yarl==1.20.0 + # via aiohttp diff --git a/pyproject.toml b/pyproject.toml index 99a0b8c3..91bf2970 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,15 +25,64 @@ dependencies = [ dynamic = ["version"] +[project.optional-dependencies] +journald = [ + "systemd-python", +] +# FIXME technically this dependency is required, but in some cases we do not have access to +# the libalpm which is required in order to install the package. Thus in case if we do not +# really need to run the application we can move it to "optional" dependencies +pacman = [ + "pyalpm", +] +reports = [ + "Jinja2", +] +s3 = [ + "boto3", +] +shell = [ + "IPython" +] +stats = [ + "matplotlib", +] +unixsocket = [ + "requests-unixsocket2", # required by unix socket support +] +validator = [ + "cerberus", +] +web = [ + "aiohttp", + "aiohttp_cors", + "aiohttp_jinja2", +] +web_api-docs = [ + "ahriman[web]", + "aiohttp-apispec", + "setuptools", # required by aiohttp-apispec +] +web_auth = [ + "ahriman[web]", + "aiohttp_session", + "aiohttp_security", + "cryptography", +] +web_oauth2 = [ + "ahriman[web_auth]", + "aioauth-client", +] + +[project.scripts] +ahriman = "ahriman.application.ahriman:run" + [project.urls] Documentation = "https://ahriman.readthedocs.io/" Repository = "https://github.com/arcan1s/ahriman" Changelog = "https://github.com/arcan1s/ahriman/releases" -[project.scripts] -ahriman = "ahriman.application.ahriman:run" - -[project.optional-dependencies] +[dependency-groups] check = [ "autopep8", "bandit", @@ -47,24 +96,6 @@ docs = [ "shtab", "sphinx-argparse", "sphinx-rtd-theme>=1.1.1", # https://stackoverflow.com/a/74355734 - ] -journald = [ - "systemd-python", -] -# FIXME technically this dependency is required, but in some cases we do not have access to -# the libalpm which is required in order to install the package. Thus in case if we do not -# really need to run the application we can move it to "optional" dependencies -pacman = [ - "pyalpm", -] -s3 = [ - "boto3", -] -shell = [ - "IPython" -] -stats = [ - "matplotlib", ] tests = [ "pytest", @@ -75,22 +106,6 @@ tests = [ "pytest-resource-path", "pytest-spec", ] -validator = [ - "cerberus", -] -web = [ - "Jinja2", - "aioauth-client", - "aiohttp", - "aiohttp-apispec", - "aiohttp_cors", - "aiohttp_jinja2", - "aiohttp_session", - "aiohttp_security", - "cryptography", - "requests-unixsocket2", # required by unix socket support - "setuptools", # required by aiohttp-apispec -] [tool.flit.sdist] include = [ diff --git a/tox.ini b/tox.ini index 73b3e2cf..b240f694 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] envlist = check, tests -isolated_build = True +isolated_build = true labels = release = version, docs, publish -dependencies = -e .[journald,pacman,s3,shell,stats,validator,web] +dependencies = -e .[journald,pacman,reports,s3,shell,stats,unixsocket,validator,web,web_api-docs,web_auth,web_oauth2] project_name = ahriman [mypy] @@ -24,10 +24,13 @@ commands = [testenv:check] description = Run common checks like linter, mypy, etc +dependency_groups = + check deps = {[tox]dependencies} - -e .[check] +pip_pre = true setenv = + CFLAGS="-Wno-unterminated-string-initialization" MYPYPATH=src commands = autopep8 --exit-code --max-line-length 120 -aa -i -j 0 -r "src/{[tox]project_name}" "tests/{[tox]project_name}" @@ -38,16 +41,19 @@ commands = [testenv:docs] description = Generate source files for documentation -depends = - version -deps = - {[tox]dependencies} - -e .[docs] -changedir = src allowlist_externals = bash find mv +changedir = src +dependency_groups = + docs +depends = + version +deps = + {[tox]dependencies} + uv +pip_pre = true setenv = SPHINX_APIDOC_OPTIONS=members,no-undoc-members,show-inheritance commands = @@ -59,22 +65,26 @@ commands = # remove autogenerated modules rst files find ../docs -type f -name "{[tox]project_name}*.rst" -delete sphinx-apidoc -o ../docs . + # compile list of dependencies for rtd.io + uv pip compile --group ../pyproject.toml:docs --extra s3 --extra validator --extra web --output-file ../docs/requirements.txt --quiet ../pyproject.toml [testenv:html] description = Generate html documentation +dependency_groups = + docs deps = {[tox]dependencies} - -e .[docs] -recreate = True +pip_pre = true +recreate = true commands = sphinx-build -b html -a -j auto -W docs {envtmpdir}{/}html [testenv:publish] description = Create and publish release to GitHub -depends = - docs allowlist_externals = git +depends = + docs passenv = SSH_AUTH_SOCK commands = @@ -86,18 +96,22 @@ commands = [testenv:tests] description = Run tests +dependency_groups = + tests deps = {[tox]dependencies} - -e .[tests] +pip_pre = true +setenv = + CFLAGS="-Wno-unterminated-string-initialization" commands = pytest {posargs} [testenv:version] description = Bump package version -deps = - packaging allowlist_externals = sed +deps = + packaging commands = # check if version is set and validate it {envpython} -c 'from packaging.version import Version; Version("{posargs}")'