diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index c62a2ed0..187dc132 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,6 +1,7 @@
version: 2
-formats: all
+formats:
+ - pdf
build:
os: ubuntu-20.04
@@ -10,6 +11,7 @@ build:
sphinx:
builder: html
configuration: docs/conf.py
+ fail_on_warning: true
python:
install:
diff --git a/docs/conf.py b/docs/conf.py
index 3656b997..beca9e87 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -27,6 +27,8 @@ on_rtd = os.environ.get("READTHEDOCS", None) == "True"
for module in (
"pyalpm",
):
+ if module in sys.modules:
+ continue
sys.modules[module] = mock.Mock()
@@ -77,7 +79,7 @@ html_theme = "default" if on_rtd else "alabaster"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
+html_static_path = []
add_module_names = False
diff --git a/src/ahriman/web/views/service/add.py b/src/ahriman/web/views/service/add.py
index 5992d64e..d25fb018 100644
--- a/src/ahriman/web/views/service/add.py
+++ b/src/ahriman/web/views/service/add.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from aiohttp.web import HTTPAccepted
+from aiohttp.web import HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -40,16 +40,31 @@ class AddView(BaseView):
JSON body must be supplied, the following model is used::
{
- "packages": "ahriman" # either list of packages or package name as in AUR
+ "packages": ["ahriman"] # either list of packages or package name as in AUR
}
Raises:
- HTTPAccepted: in case of success response
- HTTPBadRequest: if bad data is supplied
+ HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/add' -d '{"packages": ["ahriman"]}'
+ > POST /api/v1/service/add HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 25
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 18:44:21 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
data = await self.extract_data(["packages"])
packages = data.get("packages", [])
self.spawner.packages_add(packages, now=True)
- raise HTTPAccepted()
+ raise HTTPNoContent()
diff --git a/src/ahriman/web/views/service/remove.py b/src/ahriman/web/views/service/remove.py
index c6f74f5a..4aa0bdbe 100644
--- a/src/ahriman/web/views/service/remove.py
+++ b/src/ahriman/web/views/service/remove.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from aiohttp.web import HTTPAccepted, HTTPBadRequest
+from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -40,12 +40,28 @@ class RemoveView(BaseView):
JSON body must be supplied, the following model is used::
{
- "packages": "ahriman", # either list of packages or package name
+ "packages": ["ahriman"] # either list of packages or package name
}
Raises:
- HTTPAccepted: in case of success response
HTTPBadRequest: if bad data is supplied
+ HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/remove' -d '{"packages": ["ahriman"]}'
+ > POST /api/v1/service/remove HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 25
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 18:57:56 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
try:
data = await self.extract_data(["packages"])
@@ -55,4 +71,4 @@ class RemoveView(BaseView):
self.spawner.packages_remove(packages)
- raise HTTPAccepted()
+ raise HTTPNoContent()
diff --git a/src/ahriman/web/views/service/request.py b/src/ahriman/web/views/service/request.py
index 5b6c8e3b..07bef5ff 100644
--- a/src/ahriman/web/views/service/request.py
+++ b/src/ahriman/web/views/service/request.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from aiohttp.web import HTTPAccepted, HTTPBadRequest
+from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -40,12 +40,28 @@ class RequestView(BaseView):
JSON body must be supplied, the following model is used::
{
- "packages": "ahriman" # either list of packages or package name as in AUR
+ "packages": ["ahriman"] # either list of packages or package name as in AUR
}
Raises:
- HTTPAccepted: in case of success response
HTTPBadRequest: if bad data is supplied
+ HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/request' -d '{"packages": ["ahriman"]}'
+ > POST /api/v1/service/request HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 25
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 18:59:32 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
try:
data = await self.extract_data(["packages"])
@@ -55,4 +71,4 @@ class RequestView(BaseView):
self.spawner.packages_add(packages, now=False)
- raise HTTPAccepted()
+ raise HTTPNoContent()
diff --git a/src/ahriman/web/views/service/search.py b/src/ahriman/web/views/service/search.py
index d82fe146..7cb4cbf7 100644
--- a/src/ahriman/web/views/service/search.py
+++ b/src/ahriman/web/views/service/search.py
@@ -39,15 +39,30 @@ class SearchView(BaseView):
async def get(self) -> Response:
"""
- search packages in AUR
-
- search string (non empty) must be supplied as ``for`` parameter
+ search packages in AUR. Search string (non-empty) must be supplied as ``for`` parameter
Returns:
Response: 200 with found package bases and descriptions sorted by base
Raises:
HTTPNotFound: if no packages found
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/service/search?for=ahriman'
+ > GET /api/v1/service/search?for=ahriman HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: application/json
+ >
+ < HTTP/1.1 200 OK
+ < Content-Type: application/json; charset=utf-8
+ < Content-Length: 148
+ < Date: Wed, 23 Nov 2022 19:07:13 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ [{"package": "ahriman", "description": "ArcH linux ReposItory MANager"}, {"package": "ahriman-git", "description": "ArcH Linux ReposItory MANager"}]
"""
search: List[str] = self.request.query.getall("for", default=[])
packages = AUR.multisearch(*search, pacman=self.service.repository.pacman)
diff --git a/src/ahriman/web/views/status/logs.py b/src/ahriman/web/views/status/logs.py
index 4dbcf9dc..e48f911d 100644
--- a/src/ahriman/web/views/status/logs.py
+++ b/src/ahriman/web/views/status/logs.py
@@ -46,6 +46,20 @@ class LogsView(BaseView):
Raises:
HTTPNoContent: on success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -XDELETE 'http://example.com/api/v1/packages/ahriman/logs'
+ > DELETE /api/v1/packages/ahriman/logs HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:26:40 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
package_base = self.request.match_info["package"]
self.service.remove_logs(package_base, None)
@@ -58,6 +72,23 @@ class LogsView(BaseView):
Returns:
Response: 200 with package logs on success
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages/ahriman/logs'
+ > GET /api/v1/packages/ahriman/logs HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: application/json
+ >
+ < HTTP/1.1 200 OK
+ < Content-Type: application/json; charset=utf-8
+ < Content-Length: 100112
+ < Date: Wed, 23 Nov 2022 19:24:14 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ {"package_base": "ahriman", "status": {"status": "success", "timestamp": 1669231136}, "logs": "[2022-11-23 19:17:32] clone remote https://aur.archlinux.org/ahriman.git to /tmp/tmpy9j6fq9p using branch master"}
"""
package_base = self.request.match_info["package"]
@@ -89,6 +120,22 @@ class LogsView(BaseView):
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/packages/ahriman/logs' -d '{"created": 1669231764.042444, "message": "my log message", "process_id": 1}'
+ > POST /api/v1/packages/ahriman/logs HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 76
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:30:45 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
package_base = self.request.match_info["package"]
data = await self.extract_data()
diff --git a/src/ahriman/web/views/status/package.py b/src/ahriman/web/views/status/package.py
index f6258563..0b92ae1c 100644
--- a/src/ahriman/web/views/status/package.py
+++ b/src/ahriman/web/views/status/package.py
@@ -46,6 +46,20 @@ class PackageView(BaseView):
Raises:
HTTPNoContent: on success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -XDELETE 'http://example.com/api/v1/packages/ahriman'
+ > DELETE /api/v1/packages/ahriman HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:43:40 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
package_base = self.request.match_info["package"]
self.service.remove(package_base)
@@ -61,6 +75,23 @@ class PackageView(BaseView):
Raises:
HTTPNotFound: if no package was found
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages/ahriman'
+ > GET /api/v1/packages/ahriman HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: application/json
+ >
+ < HTTP/1.1 200 OK
+ < Content-Type: application/json; charset=utf-8
+ < Content-Length: 743
+ < Date: Wed, 23 Nov 2022 19:41:01 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ [{"package": {"base": "ahriman", "version": "2.3.0-1", "remote": {"git_url": "https://aur.archlinux.org/ahriman.git", "web_url": "https://aur.archlinux.org/packages/ahriman", "path": ".", "branch": "master", "source": "aur"}, "packages": {"ahriman": {"architecture": "any", "archive_size": 247573, "build_date": 1669231069, "depends": ["devtools", "git", "pyalpm", "python-inflection", "python-passlib", "python-requests", "python-setuptools", "python-srcinfo"], "description": "ArcH linux ReposItory MANager", "filename": "ahriman-2.3.0-1-any.pkg.tar.zst", "groups": [], "installed_size": 1676153, "licenses": ["GPL3"], "provides": [], "url": "https://github.com/arcan1s/ahriman"}}}, "status": {"status": "success", "timestamp": 1669231136}}]
"""
package_base = self.request.match_info["package"]
@@ -85,13 +116,29 @@ class PackageView(BaseView):
{
"status": "unknown", # package build status string, must be valid ``BuildStatusEnum``
- "package": {} # package body (use ``dataclasses.asdict`` to generate one), optional.
- # Must be supplied in case if package base is unknown
+ "package": {} # package body (use ``dataclasses.asdict`` to generate one), optional.
+ # Must be supplied in case if package base is unknown
}
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/packages/ahriman' -d '{"status": "success"}'
+ > POST /api/v1/packages/ahriman HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 21
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:42:49 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
package_base = self.request.match_info["package"]
data = await self.extract_data()
diff --git a/src/ahriman/web/views/status/packages.py b/src/ahriman/web/views/status/packages.py
index 7d786b47..667a68d6 100644
--- a/src/ahriman/web/views/status/packages.py
+++ b/src/ahriman/web/views/status/packages.py
@@ -42,6 +42,23 @@ class PackagesView(BaseView):
Returns:
Response: 200 with package description on success
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages'
+ > GET /api/v1/packages HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: application/json
+ >
+ < HTTP/1.1 200 OK
+ < Content-Type: application/json; charset=utf-8
+ < Content-Length: 2687
+ < Date: Wed, 23 Nov 2022 19:35:24 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ [{"package": {"base": "ahriman", "version": "2.3.0-1", "remote": {"git_url": "https://aur.archlinux.org/ahriman.git", "web_url": "https://aur.archlinux.org/packages/ahriman", "path": ".", "branch": "master", "source": "aur"}, "packages": {"ahriman": {"architecture": "any", "archive_size": 247573, "build_date": 1669231069, "depends": ["devtools", "git", "pyalpm", "python-inflection", "python-passlib", "python-requests", "python-setuptools", "python-srcinfo"], "description": "ArcH linux ReposItory MANager", "filename": "ahriman-2.3.0-1-any.pkg.tar.zst", "groups": [], "installed_size": 1676153, "licenses": ["GPL3"], "provides": [], "url": "https://github.com/arcan1s/ahriman"}}}, "status": {"status": "success", "timestamp": 1669231136}}]
"""
response = [
{
@@ -57,6 +74,20 @@ class PackagesView(BaseView):
Raises:
HTTPNoContent: on success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -XPOST 'http://example.com/api/v1/packages'
+ > POST /api/v1/packages HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:38:06 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
self.service.load()
diff --git a/src/ahriman/web/views/status/status.py b/src/ahriman/web/views/status/status.py
index 9fb7f308..4e32c326 100644
--- a/src/ahriman/web/views/status/status.py
+++ b/src/ahriman/web/views/status/status.py
@@ -46,6 +46,23 @@ class StatusView(BaseView):
Returns:
Response: 200 with service status object
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/status'
+ > GET /api/v1/status HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: application/json
+ >
+ < HTTP/1.1 200 OK
+ < Content-Type: application/json; charset=utf-8
+ < Content-Length: 222
+ < Date: Wed, 23 Nov 2022 19:32:31 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ {"status": {"status": "success", "timestamp": 1669231237}, "architecture": "x86_64", "packages": {"total": 4, "unknown": 0, "pending": 0, "building": 0, "failed": 0, "success": 4}, "repository": "repo", "version": "2.3.0"}
"""
counters = Counters.from_packages(self.service.packages)
status = InternalStatus(
@@ -70,6 +87,22 @@ class StatusView(BaseView):
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNoContent: in case of success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/status' -d '{"status": "success"}'
+ > POST /api/v1/status HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 21
+ >
+ < HTTP/1.1 204 No Content
+ < Date: Wed, 23 Nov 2022 19:33:57 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
"""
try:
data = await self.extract_data()
diff --git a/src/ahriman/web/views/user/login.py b/src/ahriman/web/views/user/login.py
index c57249d9..ba7d07ea 100644
--- a/src/ahriman/web/views/user/login.py
+++ b/src/ahriman/web/views/user/login.py
@@ -41,12 +41,17 @@ class LoginView(BaseView):
OAuth2 response handler
In case if code provided it will do a request to get user email. In case if no code provided it will redirect
- to authorization url provided by OAuth client
+ to authorization url provided by OAuth client.
+
+ The authentication session will be passed in ``Set-Cookie`` header.
Raises:
HTTPFound: on success response
HTTPMethodNotAllowed: in case if method is used, but OAuth is disabled
HTTPUnauthorized: if case of authorization error
+
+ Examples:
+ This request must not be used directly.
"""
from ahriman.core.auth import OAuth
@@ -78,9 +83,32 @@ class LoginView(BaseView):
"password": "pa55w0rd" # password to use for login
}
+ The authentication session will be passed in ``Set-Cookie`` header.
+
Raises:
HTTPFound: on success response
HTTPUnauthorized: if case of authorization error
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/login' -d '{"username": "test", "password": "test"}'
+ > POST /api/v1/login HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ > Content-Type: application/json
+ > Content-Length: 40
+ >
+ < HTTP/1.1 302 Found
+ < Content-Type: text/plain; charset=utf-8
+ < Location: /
+ < Content-Length: 10
+ < Set-Cookie: ...
+ < Date: Wed, 23 Nov 2022 17:51:27 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ 302: Found
"""
data = await self.extract_data()
username = data.get("username")
diff --git a/src/ahriman/web/views/user/logout.py b/src/ahriman/web/views/user/logout.py
index 471ac732..3ab32c87 100644
--- a/src/ahriman/web/views/user/logout.py
+++ b/src/ahriman/web/views/user/logout.py
@@ -37,10 +37,31 @@ class LogoutView(BaseView):
async def post(self) -> None:
"""
- logout user from the service. No parameters supported here
+ logout user from the service. No parameters supported here.
+
+ The server will respond with ``Set-Cookie`` header, in which API session cookie will be nullified.
Raises:
HTTPFound: on success response
+
+ Examples:
+ Example of command by using curl::
+
+ $ curl -v -XPOST 'http://example.com/api/v1/logout'
+ > POST /api/v1/logout HTTP/1.1
+ > Host: example.com
+ > User-Agent: curl/7.86.0
+ > Accept: */*
+ >
+ < HTTP/1.1 302 Found
+ < Content-Type: text/plain; charset=utf-8
+ < Location: /
+ < Content-Length: 10
+ < Set-Cookie: ...
+ < Date: Wed, 23 Nov 2022 19:10:51 GMT
+ < Server: Python/3.10 aiohttp/3.8.3
+ <
+ 302: Found
"""
try:
await check_authorized(self.request)
diff --git a/tox.ini b/tox.ini
index 57c57964..98449b02 100644
--- a/tox.ini
+++ b/tox.ini
@@ -44,7 +44,7 @@ deps =
{[tox]dependencies}
-e .[docs]
commands =
- sphinx-build -b html -a -j auto docs docs/html
+ sphinx-build -b html -a -j auto -W docs docs/html
[testenv:tests]
deps =