python-gitea 0.0.1__tar.gz → 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {python_gitea-0.0.1 → python_gitea-0.1.0}/.ignore_words.txt +1 -0
  2. {python_gitea-0.0.1 → python_gitea-0.1.0}/PKG-INFO +3 -3
  3. {python_gitea-0.0.1 → python_gitea-0.1.0}/README.md +2 -2
  4. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/gen_ref_pages.py +3 -1
  5. {python_gitea-0.0.1 → python_gitea-0.1.0}/mkdocs.yml +7 -3
  6. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/cli/main.py +40 -5
  7. python_gitea-0.1.0/src/gitea/cli/user/delete_user_level_runner.py +38 -0
  8. python_gitea-0.1.0/src/gitea/cli/user/get_registration_token.py +31 -0
  9. python_gitea-0.1.0/src/gitea/cli/user/get_user.py +39 -0
  10. python_gitea-0.1.0/src/gitea/cli/user/get_user_level_runners.py +34 -0
  11. python_gitea-0.1.0/src/gitea/cli/user/get_workflow_jobs.py +47 -0
  12. python_gitea-0.1.0/src/gitea/cli/user/get_workflow_runs.py +64 -0
  13. python_gitea-0.1.0/src/gitea/cli/user/main.py +34 -0
  14. python_gitea-0.1.0/src/gitea/cli/utils.py +45 -0
  15. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/client/async_gitea.py +10 -5
  16. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/client/base.py +6 -4
  17. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/client/gitea.py +16 -4
  18. python_gitea-0.1.0/src/gitea/resource/async_resource.py +67 -0
  19. python_gitea-0.1.0/src/gitea/resource/resource.py +68 -0
  20. python_gitea-0.1.0/src/gitea/user/__init__.py +0 -0
  21. python_gitea-0.1.0/src/gitea/user/async_user.py +116 -0
  22. python_gitea-0.1.0/src/gitea/user/base.py +73 -0
  23. python_gitea-0.1.0/src/gitea/user/user.py +116 -0
  24. python_gitea-0.1.0/tests/__init__.py +0 -0
  25. python_gitea-0.1.0/tests/cli/__init__.py +0 -0
  26. python_gitea-0.1.0/tests/cli/test_cli_main.py +100 -0
  27. python_gitea-0.1.0/tests/cli/test_cli_utils.py +69 -0
  28. python_gitea-0.1.0/tests/cli/user/__init__.py +0 -0
  29. python_gitea-0.1.0/tests/cli/user/test_cli_user_delete_user_level_runner.py +75 -0
  30. python_gitea-0.1.0/tests/cli/user/test_cli_user_get_registration_token.py +75 -0
  31. python_gitea-0.1.0/tests/cli/user/test_cli_user_get_user.py +100 -0
  32. python_gitea-0.1.0/tests/cli/user/test_cli_user_get_user_level_runners.py +100 -0
  33. python_gitea-0.1.0/tests/cli/user/test_cli_user_get_workflow_jobs.py +102 -0
  34. python_gitea-0.1.0/tests/cli/user/test_cli_user_get_workflow_runs.py +123 -0
  35. python_gitea-0.1.0/tests/cli/user/test_cli_user_main.py +52 -0
  36. python_gitea-0.1.0/tests/client/__init__.py +0 -0
  37. python_gitea-0.1.0/tests/resource/__init__.py +0 -0
  38. python_gitea-0.1.0/tests/resource/test_resource_async_resource.py +65 -0
  39. python_gitea-0.1.0/tests/resource/test_resource_resource.py +61 -0
  40. python_gitea-0.1.0/tests/test_main.py +25 -0
  41. python_gitea-0.1.0/tests/test_version.py +38 -0
  42. python_gitea-0.1.0/tests/user/__init__.py +0 -0
  43. python_gitea-0.1.0/tests/user/test_user_async_user.py +110 -0
  44. python_gitea-0.1.0/tests/user/test_user_base.py +102 -0
  45. python_gitea-0.1.0/tests/user/test_user_user.py +102 -0
  46. python_gitea-0.1.0/tests/utils/__init__.py +0 -0
  47. python_gitea-0.1.0/tests/utils/test_utils_log.py +105 -0
  48. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/dependabot.yml +0 -0
  49. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/CI.yml +0 -0
  50. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/create_tag.yml +0 -0
  51. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/documentation.yml +0 -0
  52. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/draft_release.yml +0 -0
  53. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/publish.yml +0 -0
  54. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/publish_testpypi.yml +0 -0
  55. {python_gitea-0.0.1 → python_gitea-0.1.0}/.github/workflows/release.yml +0 -0
  56. {python_gitea-0.0.1 → python_gitea-0.1.0}/.gitignore +0 -0
  57. {python_gitea-0.0.1 → python_gitea-0.1.0}/.markdownlint.yaml +0 -0
  58. {python_gitea-0.0.1 → python_gitea-0.1.0}/.pre-commit-config.yaml +0 -0
  59. {python_gitea-0.0.1 → python_gitea-0.1.0}/.pypirc +0 -0
  60. {python_gitea-0.0.1 → python_gitea-0.1.0}/CITATION.cff +0 -0
  61. {python_gitea-0.0.1 → python_gitea-0.1.0}/CODE_OF_CONDUCT.md +0 -0
  62. {python_gitea-0.0.1 → python_gitea-0.1.0}/CONTRIBUTING.md +0 -0
  63. {python_gitea-0.0.1 → python_gitea-0.1.0}/LICENSE +0 -0
  64. {python_gitea-0.0.1 → python_gitea-0.1.0}/SECURITY.md +0 -0
  65. {python_gitea-0.0.1 → python_gitea-0.1.0}/SUPPORT.md +0 -0
  66. {python_gitea-0.0.1 → python_gitea-0.1.0}/cliff.toml +0 -0
  67. {python_gitea-0.0.1 → python_gitea-0.1.0}/commitlint.config.js +0 -0
  68. {python_gitea-0.0.1 → python_gitea-0.1.0}/cspell.json +0 -0
  69. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/dev/troubleshooting.md +0 -0
  70. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/index.md +0 -0
  71. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/javascripts/mathjax.js +0 -0
  72. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/style/api.css +0 -0
  73. {python_gitea-0.0.1 → python_gitea-0.1.0}/docs/user_guide/installation.md +0 -0
  74. {python_gitea-0.0.1 → python_gitea-0.1.0}/package.json +0 -0
  75. {python_gitea-0.0.1 → python_gitea-0.1.0}/pyproject.toml +0 -0
  76. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/__init__.py +0 -0
  77. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/__main__.py +0 -0
  78. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/cli/__init__.py +0 -0
  79. {python_gitea-0.0.1/tests → python_gitea-0.1.0/src/gitea/cli/user}/__init__.py +0 -0
  80. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/client/__init__.py +0 -0
  81. {python_gitea-0.0.1/tests/client → python_gitea-0.1.0/src/gitea/resource}/__init__.py +0 -0
  82. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/utils/__init__.py +0 -0
  83. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/utils/log.py +0 -0
  84. {python_gitea-0.0.1 → python_gitea-0.1.0}/src/gitea/version.py +0 -0
  85. {python_gitea-0.0.1 → python_gitea-0.1.0}/tests/client/test_client_async_gitea.py +0 -0
  86. {python_gitea-0.0.1 → python_gitea-0.1.0}/tests/client/test_client_base.py +0 -0
  87. {python_gitea-0.0.1 → python_gitea-0.1.0}/tests/client/test_client_gitea.py +0 -0
  88. {python_gitea-0.0.1 → python_gitea-0.1.0}/tests/conftest.py +0 -0
  89. {python_gitea-0.0.1 → python_gitea-0.1.0}/tests/test_import.py +0 -0
@@ -69,3 +69,4 @@ testpypi
69
69
  tkinter
70
70
  venv
71
71
  xunit
72
+ zenodo
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-gitea
3
- Version: 0.0.1
3
+ Version: 0.1.0
4
4
  Summary: A Python package for interacting with the Gitea API, offering a simple interface to access repositories, users, organizations, issues, and more for automation and data management.
5
5
  Project-URL: Documentation, https://isaac-cf-wong.github.io/python-gitea
6
6
  Project-URL: Source, https://github.com/isaac-cf-wong/python-gitea
@@ -59,10 +59,10 @@ Description-Content-Type: text/markdown
59
59
  [![Documentation Status](https://github.com/isaac-cf-wong/python-gitea/actions/workflows/documentation.yml/badge.svg)](https://isaac-cf-wong.github.io/python-gitea/)
60
60
  [![codecov](https://codecov.io/gh/isaac-cf-wong/python-gitea/graph/badge.svg?token=COF8341N60)](https://codecov.io/gh/isaac-cf-wong/python-gitea)
61
61
  [![PyPI Version](https://img.shields.io/pypi/v/python-gitea)](https://pypi.org/project/python-gitea/)
62
- [![Python Versions](https://img.shields.io/pypi/pyversions/package-name-placeholder)](https://pypi.org/project/package-name-placeholder/)
62
+ [![Python Versions](https://img.shields.io/pypi/pyversions/python-gitea)](https://pypi.org/project/python-gitea/)
63
63
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
64
64
  [![Security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
65
- [![DOI](https://zenodo.org/badge/924023559.svg)](https://doi.org/10.5281/zenodo.18017404)
65
+ [![DOI](https://zenodo.org/badge/1129170965.svg)](https://doi.org/10.5281/zenodo.18211496)
66
66
 
67
67
  **Note:** This project is still in progress. The promised features are not fully ready yet, and APIs are subject to change.
68
68
 
@@ -5,10 +5,10 @@
5
5
  [![Documentation Status](https://github.com/isaac-cf-wong/python-gitea/actions/workflows/documentation.yml/badge.svg)](https://isaac-cf-wong.github.io/python-gitea/)
6
6
  [![codecov](https://codecov.io/gh/isaac-cf-wong/python-gitea/graph/badge.svg?token=COF8341N60)](https://codecov.io/gh/isaac-cf-wong/python-gitea)
7
7
  [![PyPI Version](https://img.shields.io/pypi/v/python-gitea)](https://pypi.org/project/python-gitea/)
8
- [![Python Versions](https://img.shields.io/pypi/pyversions/package-name-placeholder)](https://pypi.org/project/package-name-placeholder/)
8
+ [![Python Versions](https://img.shields.io/pypi/pyversions/python-gitea)](https://pypi.org/project/python-gitea/)
9
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
10
  [![Security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit)
11
- [![DOI](https://zenodo.org/badge/924023559.svg)](https://doi.org/10.5281/zenodo.18017404)
11
+ [![DOI](https://zenodo.org/badge/1129170965.svg)](https://doi.org/10.5281/zenodo.18211496)
12
12
 
13
13
  **Note:** This project is still in progress. The promised features are not fully ready yet, and APIs are subject to change.
14
14
 
@@ -65,11 +65,13 @@ for path in sorted(src.rglob("*.py")):
65
65
  elif parts[-1] == "__main__":
66
66
  continue
67
67
 
68
- # Skip private modules and test files
68
+ # Skip private modules, test files, and CLI module
69
69
  if any(part.startswith("_") and part != "__init__" for part in parts):
70
70
  continue
71
71
  if parts and parts[-1].startswith("test_"):
72
72
  continue
73
+ if "cli" in parts: # Skip CLI module
74
+ continue
73
75
 
74
76
  # Skip empty parts (from root __init__)
75
77
  if not parts:
@@ -78,9 +78,13 @@ nav:
78
78
  - Base: reference/gitea/client/base.md
79
79
  - AsyncGitea: reference/gitea/client/async_gitea.md
80
80
  - Gitea: reference/gitea/client/gitea.md
81
- - CLI:
82
- - Overview: reference/gitea/cli/index.md
83
- - Main: reference/gitea/cli/main.md
81
+ - Resource:
82
+ - Overview: reference/gitea/resource/index.md
83
+ - Resource: reference/gitea/resource/resource.md
84
+ - AsyncResource: reference/gitea/resource/async_resource.md
85
+ - User:
86
+ - Overview: reference/gitea/user/index.md
87
+ - User: reference/gitea/user/user.md
84
88
  - Utils:
85
89
  - Overview: reference/gitea/utils/index.md
86
90
  - Logging: reference/gitea/utils/log.md
@@ -1,9 +1,9 @@
1
- # ruff: noqa PLC0415
2
1
  """Main entry point for the python-gitea CLI application."""
3
2
 
4
3
  from __future__ import annotations
5
4
 
6
5
  import enum
6
+ from pathlib import Path
7
7
  from typing import Annotated
8
8
 
9
9
  import typer
@@ -34,10 +34,10 @@ def setup_logging(level: LoggingLevel = LoggingLevel.INFO) -> None:
34
34
  Args:
35
35
  level: Logging level.
36
36
  """
37
- import logging
37
+ import logging # noqa: PLC0415
38
38
 
39
- from rich.console import Console
40
- from rich.logging import RichHandler
39
+ from rich.console import Console # noqa: PLC0415
40
+ from rich.logging import RichHandler # noqa: PLC0415
41
41
 
42
42
  logger = logging.getLogger("python-gitea")
43
43
 
@@ -68,7 +68,30 @@ def setup_logging(level: LoggingLevel = LoggingLevel.INFO) -> None:
68
68
 
69
69
 
70
70
  @app.callback()
71
- def main(
71
+ def main( # noqa: PLR0913
72
+ ctx: typer.Context,
73
+ output: Annotated[Path | None, typer.Option("--output", "-o", help="Output file name.")] = None,
74
+ token: Annotated[
75
+ str | None, typer.Option("--token", "-t", help="Gitea API token.", envvar="GITEA_API_TOKEN")
76
+ ] = None,
77
+ base_url: Annotated[
78
+ str,
79
+ typer.Option(
80
+ "--base-url",
81
+ "-b",
82
+ help="Base URL of the Gitea instance.",
83
+ envvar="GITEA_BASE_URL",
84
+ show_default=True,
85
+ ),
86
+ ] = "https://gitea.com",
87
+ timeout: Annotated[
88
+ int,
89
+ typer.Option(
90
+ "--timeout",
91
+ help="Timeout for API requests in seconds.",
92
+ show_default=True,
93
+ ),
94
+ ] = 30,
72
95
  verbose: Annotated[
73
96
  LoggingLevel,
74
97
  typer.Option("--verbose", "-v", help="Set verbosity level."),
@@ -77,13 +100,25 @@ def main(
77
100
  """Main entry point for the CLI application.
78
101
 
79
102
  Args:
103
+ ctx: Typer context.
104
+ token: Gitea API token.
105
+ base_url: Base URL of the Gitea instance.
80
106
  verbose: Verbosity level for logging.
81
107
  """
82
108
  setup_logging(verbose)
109
+ ctx.obj = {
110
+ "output": output,
111
+ "token": token,
112
+ "base_url": base_url,
113
+ "timeout": timeout,
114
+ }
83
115
 
84
116
 
85
117
  def register_commands() -> None:
86
118
  """Register CLI commands."""
119
+ from gitea.cli.user.main import user_app # noqa: PLC0415
120
+
121
+ app.add_typer(user_app, name="user", help="Commands for managing Gitea users.")
87
122
 
88
123
 
89
124
  register_commands()
@@ -0,0 +1,38 @@
1
+ """Delete user-level runner command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+
10
+ def delete_user_level_runner_command(
11
+ ctx: typer.Context,
12
+ runner_id: Annotated[str, typer.Option("--runner-id", help="The ID of the runner to delete.")],
13
+ ) -> None:
14
+ """Delete a user-level runner for the authenticated user.
15
+
16
+ Args:
17
+ runner_id: The ID of the runner to delete.
18
+ """
19
+ from typing import Any # noqa: PLC0415
20
+
21
+ import gitea.cli.utils # noqa: PLC0415
22
+ import gitea.client.gitea # noqa: PLC0415
23
+
24
+ token: str | None = ctx.obj.get("token")
25
+ base_url: str = ctx.obj.get("base_url")
26
+ timeout: int = ctx.obj.get("timeout")
27
+
28
+ def api_call() -> dict[str, Any] | None:
29
+ """
30
+ API call to delete a user-level runner.
31
+
32
+ Returns:
33
+ A dictionary containing the result of the deletion.
34
+ """
35
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
36
+ return client.user.delete_user_level_runner(runner_id=runner_id, timeout=timeout)
37
+
38
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="delete-user-level-runner")
@@ -0,0 +1,31 @@
1
+ """Get registration token command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+
8
+ def get_registration_token_command(
9
+ ctx: typer.Context,
10
+ ) -> None:
11
+ """Get registration token for the authenticated user."""
12
+ from typing import Any # noqa: PLC0415
13
+
14
+ import gitea.cli.utils # noqa: PLC0415
15
+ import gitea.client.gitea # noqa: PLC0415
16
+
17
+ token: str | None = ctx.obj.get("token")
18
+ base_url: str = ctx.obj.get("base_url")
19
+ timeout: int = ctx.obj.get("timeout")
20
+
21
+ def api_call() -> dict[str, Any] | None:
22
+ """
23
+ API call to get the registration token.
24
+
25
+ Returns:
26
+ A dictionary containing the registration token.
27
+ """
28
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
29
+ return client.user.get_registration_token(timeout=timeout)
30
+
31
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="get-registration-token")
@@ -0,0 +1,39 @@
1
+ """Get user information command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+
10
+ def get_user_command(
11
+ ctx: typer.Context,
12
+ username: Annotated[
13
+ str | None, "The username of the user to retrieve. If None, retrieves the authenticated user."
14
+ ] = None,
15
+ ) -> None:
16
+ """Get user information.
17
+
18
+ Args:
19
+ username: The username of the user to retrieve. If None, retrieves the authenticated user.
20
+ """
21
+ from typing import Any # noqa: PLC0415
22
+
23
+ import gitea.cli.utils # noqa: PLC0415
24
+ import gitea.client.gitea # noqa: PLC0415
25
+
26
+ token: str | None = ctx.obj.get("token")
27
+ base_url: str = ctx.obj.get("base_url")
28
+ timeout: int = ctx.obj.get("timeout")
29
+
30
+ def api_call() -> dict[str, Any] | None:
31
+ """API call to get user information.
32
+
33
+ Returns:
34
+ The user information as a dictionary.
35
+ """
36
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
37
+ return client.user.get_user(username=username, timeout=timeout)
38
+
39
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="get-user")
@@ -0,0 +1,34 @@
1
+ """Get user-level runners command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+
10
+ def get_user_level_runners_command(
11
+ ctx: typer.Context,
12
+ runner_id: Annotated[str | None, typer.Option("--runner-id", help="The ID of the runner to retrieve.")] = None,
13
+ ) -> None:
14
+ """Get user-level runners for the authenticated user."""
15
+ from typing import Any # noqa: PLC0415
16
+
17
+ import gitea.cli.utils # noqa: PLC0415
18
+ import gitea.client.gitea # noqa: PLC0415
19
+
20
+ token: str | None = ctx.obj.get("token")
21
+ base_url: str = ctx.obj.get("base_url")
22
+ timeout: int = ctx.obj.get("timeout")
23
+
24
+ def api_call() -> dict[str, Any] | None:
25
+ """
26
+ API call to get user-level runners.
27
+
28
+ Returns:
29
+ A dictionary containing the user-level runners.
30
+ """
31
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
32
+ return client.user.get_user_level_runners(runner_id=runner_id, timeout=timeout)
33
+
34
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="get-user-level-runners")
@@ -0,0 +1,47 @@
1
+ """Get workflow jobs command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated, Literal
6
+
7
+ import typer
8
+
9
+
10
+ def get_workflow_jobs_command(
11
+ ctx: typer.Context,
12
+ status: Annotated[
13
+ Literal["pending", "queued", "in_progress", "failure", "success", "skipped"],
14
+ typer.Option(
15
+ "--status",
16
+ help="The status to filter workflow jobs by. Options: pending, queued, in_progress, failure, success, skipped.",
17
+ ),
18
+ ],
19
+ page: Annotated[int | None, typer.Option("--page", help="The page number for pagination.")] = None,
20
+ limit: Annotated[int | None, typer.Option("--limit", help="The number of items per page for pagination.")] = None,
21
+ ) -> None:
22
+ """Get workflow jobs for the authenticated user filtered by status.
23
+
24
+ Args:
25
+ status: The status to filter workflow jobs by. Options: pending, queued, in_progress, failure, success, skipped.
26
+ page: The page number for pagination.
27
+ limit: The number of items per page for pagination.
28
+ """
29
+ from typing import Any # noqa: PLC0415
30
+
31
+ import gitea.cli.utils # noqa: PLC0415
32
+ import gitea.client.gitea # noqa: PLC0415
33
+
34
+ token: str | None = ctx.obj.get("token")
35
+ base_url: str = ctx.obj.get("base_url")
36
+ timeout: int = ctx.obj.get("timeout")
37
+
38
+ def api_call() -> dict[str, Any] | None:
39
+ """API call to get workflow jobs.
40
+
41
+ Returns:
42
+ A dictionary containing the workflow jobs with the specified status.
43
+ """
44
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
45
+ return client.user.get_workflow_jobs(status=status, page=page, limit=limit, timeout=timeout)
46
+
47
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="get-workflow-jobs")
@@ -0,0 +1,64 @@
1
+ """Get workflow runs command for Gitea CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Annotated, Literal
6
+
7
+ import typer
8
+
9
+
10
+ def get_workflow_runs_command( # noqa: PLR0913
11
+ ctx: typer.Context,
12
+ event: Annotated[str | None, typer.Option("--event", help="Workflow event name.")] = None,
13
+ branch: Annotated[str | None, typer.Option("--branch", help="Workflow branch.")] = None,
14
+ status: Annotated[
15
+ Literal["pending", "queued", "in_progress", "failure", "success", "skipped"] | None,
16
+ typer.Option(
17
+ "--status",
18
+ help="Workflow status.",
19
+ ),
20
+ ] = None,
21
+ actor: Annotated[str | None, typer.Option("--actor", help="Triggered by user.")] = None,
22
+ head_sha: Annotated[str | None, typer.Option("--head-sha", help="Triggering sha of the workflow run.")] = None,
23
+ page: Annotated[int | None, typer.Option("--page", help="Page number of results to return.")] = None,
24
+ limit: Annotated[int | None, typer.Option("--limit", help="Page size of results.")] = None,
25
+ ) -> None:
26
+ """Get workflow runs for the authenticated user filtered by various parameters.
27
+
28
+ Args:
29
+ event: The event that triggered the workflow run.
30
+ branch: The branch name to filter workflow runs.
31
+ status: The status to filter workflow jobs by. Options: pending, queued, in_progress, failure, success, skipped.
32
+ actor: The actor who triggered the workflow run.
33
+ head_sha: The head SHA to filter workflow runs.
34
+ page: The page number for pagination.
35
+ limit: The number of items per page for pagination.
36
+ """
37
+ from typing import Any # noqa: PLC0415
38
+
39
+ import gitea.cli.utils # noqa: PLC0415
40
+ import gitea.client.gitea # noqa: PLC0415
41
+
42
+ token: str | None = ctx.obj.get("token")
43
+ base_url: str = ctx.obj.get("base_url")
44
+ timeout: int = ctx.obj.get("timeout")
45
+
46
+ def api_call() -> dict[str, Any] | None:
47
+ """API call to get workflow runs.
48
+
49
+ Returns:
50
+ A dictionary containing the workflow runs.
51
+ """
52
+ with gitea.client.gitea.Gitea(token=token, base_url=base_url) as client:
53
+ return client.user.get_workflow_runs(
54
+ event=event,
55
+ branch=branch,
56
+ status=status,
57
+ actor=actor,
58
+ head_sha=head_sha,
59
+ page=page,
60
+ limit=limit,
61
+ timeout=timeout,
62
+ )
63
+
64
+ gitea.cli.utils.execute_api_command(ctx=ctx, api_call=api_call, command_name="get-workflow-runs")
@@ -0,0 +1,34 @@
1
+ # ruff: noqa PLC0415
2
+
3
+ """CLI commands for managing Gitea users."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import typer
8
+
9
+ user_app = typer.Typer(
10
+ name="user",
11
+ help="Commands for managing Gitea users.",
12
+ rich_markup_mode="rich",
13
+ )
14
+
15
+
16
+ def register_commands() -> None:
17
+ """Register user-related commands to the user_app."""
18
+
19
+ from gitea.cli.user.get_user import get_user_command
20
+ from gitea.cli.user.get_workflow_jobs import get_workflow_jobs_command
21
+ from gitea.cli.user.get_user_level_runners import get_user_level_runners_command
22
+ from gitea.cli.user.get_registration_token import get_registration_token_command
23
+ from gitea.cli.user.delete_user_level_runner import delete_user_level_runner_command
24
+ from gitea.cli.user.get_workflow_runs import get_workflow_runs_command
25
+
26
+ user_app.command("get-user")(get_user_command)
27
+ user_app.command("get-workflow-jobs")(get_workflow_jobs_command)
28
+ user_app.command("get-user-level-runners")(get_user_level_runners_command)
29
+ user_app.command("get-registration-token")(get_registration_token_command)
30
+ user_app.command("delete-user-level-runner")(delete_user_level_runner_command)
31
+ user_app.command("get-workflow-runs")(get_workflow_runs_command)
32
+
33
+
34
+ register_commands()
@@ -0,0 +1,45 @@
1
+ """CLI utility functions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections.abc import Callable
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import typer
11
+ from rich.console import Console
12
+
13
+
14
+ def execute_api_command(
15
+ ctx: typer.Context,
16
+ api_call: Callable[[], dict[str, Any] | None],
17
+ command_name: str = "Command",
18
+ ) -> None:
19
+ """Execute an API command and output results.
20
+
21
+ Args:
22
+ ctx: Typer context containing token, base_url, and output.
23
+ api_call: Callable that executes the API call and returns the result.
24
+ command_name: Name of the command for error messages.
25
+ """
26
+ output: Path | None = ctx.obj.get("output")
27
+ console = Console()
28
+
29
+ try:
30
+ result = api_call()
31
+
32
+ if result is None:
33
+ console.print(f"{command_name} executed successfully. No content returned.")
34
+ return
35
+
36
+ json_output = json.dumps(result, indent=4)
37
+
38
+ if output:
39
+ Path(output).write_text(json_output)
40
+ console.print(f"Output saved to {output}")
41
+ else:
42
+ console.print_json(json_output)
43
+ except Exception as e:
44
+ console.print(f"Error executing {command_name}: {e}", style="red")
45
+ raise typer.Exit(1) from e
@@ -12,7 +12,7 @@ from gitea.client.base import Client
12
12
  class AsyncGitea(Client): # pylint: disable=too-few-public-methods
13
13
  """Asynchronous Gitea API client."""
14
14
 
15
- def __init__(self, token: str, base_url: str = "https://gitea.com") -> None:
15
+ def __init__(self, token: str | None = None, base_url: str = "https://gitea.com") -> None:
16
16
  """Initialize the asynchronous Gitea client.
17
17
 
18
18
  Args:
@@ -45,7 +45,7 @@ class AsyncGitea(Client): # pylint: disable=too-few-public-methods
45
45
  await self.session.close()
46
46
  self.session = None
47
47
 
48
- def _get_session(self, headers: dict | None = None, **kwargs) -> ClientSession:
48
+ def _get_session(self, headers: dict | None = None, **kwargs: Any) -> ClientSession:
49
49
  """Get or create the aiohttp ClientSession.
50
50
 
51
51
  Args:
@@ -58,8 +58,8 @@ class AsyncGitea(Client): # pylint: disable=too-few-public-methods
58
58
  return ClientSession(headers=headers, **kwargs)
59
59
 
60
60
  async def _request(
61
- self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs
62
- ) -> dict[str, Any]:
61
+ self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs: Any
62
+ ) -> dict[str, Any] | None:
63
63
  """Make an asynchronous HTTP request to the Gitea API.
64
64
 
65
65
  Args:
@@ -70,7 +70,7 @@ class AsyncGitea(Client): # pylint: disable=too-few-public-methods
70
70
  **kwargs: Additional arguments for the request.
71
71
 
72
72
  Returns:
73
- The JSON response as a dictionary.
73
+ The JSON response from the API. None for 204 No Content responses.
74
74
  """
75
75
  if self.session is None:
76
76
  raise RuntimeError(
@@ -85,4 +85,9 @@ class AsyncGitea(Client): # pylint: disable=too-few-public-methods
85
85
  method=method, url=url, headers=request_headers, timeout=timeout_obj, **kwargs
86
86
  ) as response:
87
87
  response.raise_for_status()
88
+
89
+ # Handle 204 No Content responses
90
+ if response.status == 204: # noqa: PLR2004
91
+ return None
92
+
88
93
  return await response.json()
@@ -2,11 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import Any
6
+
5
7
 
6
8
  class Client: # pylint: disable=too-few-public-methods
7
9
  """Abstract base class for Gitea clients."""
8
10
 
9
- def __init__(self, token: str, base_url: str) -> None:
11
+ def __init__(self, token: str | None, base_url: str) -> None:
10
12
  """Construct the base client.
11
13
 
12
14
  Args:
@@ -15,9 +17,9 @@ class Client: # pylint: disable=too-few-public-methods
15
17
  """
16
18
  self.token = token
17
19
  self.base_url = base_url.rstrip("/")
18
- self.headers = {
19
- "Authorization": f"token {self.token}",
20
- }
20
+ self.headers: dict[str, Any] = {}
21
+ if self.token:
22
+ self.headers["Authorization"] = f"token {self.token}"
21
23
 
22
24
  @property
23
25
  def api_url(self) -> str:
@@ -7,12 +7,13 @@ from typing import Any
7
7
  import requests
8
8
 
9
9
  from gitea.client.base import Client
10
+ from gitea.user.user import User
10
11
 
11
12
 
12
13
  class Gitea(Client): # pylint: disable=too-few-public-methods
13
14
  """Synchronous Gitea API client."""
14
15
 
15
- def __init__(self, token: str, base_url: str = "https://gitea.com") -> None:
16
+ def __init__(self, token: str | None = None, base_url: str = "https://gitea.com") -> None:
16
17
  """Initialize the Gitea client.
17
18
 
18
19
  Args:
@@ -21,6 +22,7 @@ class Gitea(Client): # pylint: disable=too-few-public-methods
21
22
  """
22
23
  super().__init__(token=token, base_url=base_url)
23
24
  self.session: requests.Session | None = None
25
+ self.user = User(client=self)
24
26
 
25
27
  def __enter__(self) -> Gitea:
26
28
  """Enter the context manager.
@@ -46,8 +48,8 @@ class Gitea(Client): # pylint: disable=too-few-public-methods
46
48
  self.session = None
47
49
 
48
50
  def _request(
49
- self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs
50
- ) -> dict[str, Any]:
51
+ self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs: Any
52
+ ) -> dict[str, Any] | None:
51
53
  """Make an HTTP request to the Gitea API.
52
54
 
53
55
  Args:
@@ -58,11 +60,21 @@ class Gitea(Client): # pylint: disable=too-few-public-methods
58
60
  **kwargs: Additional arguments for the request.
59
61
 
60
62
  Returns:
61
- The JSON response from the API.
63
+ The JSON response from the API. None for 204 No Content responses.
62
64
  """
65
+ if self.session is None:
66
+ raise RuntimeError(
67
+ "Gitea must be used as a context manager. "
68
+ + "Use 'with Gitea(...) as client:' to ensure proper resource cleanup."
69
+ )
63
70
  url = self._build_url(endpoint=endpoint)
64
71
  response = self.session.request(
65
72
  method, url, headers={**self.headers, **(headers or {})}, timeout=timeout, **kwargs
66
73
  )
67
74
  response.raise_for_status()
75
+
76
+ # Handle 204 No Content responses
77
+ if response.status_code == 204: # noqa: PLR2004
78
+ return None
79
+
68
80
  return response.json()