gitea-cli 0.12.3__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.
@@ -0,0 +1,23 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include requirements.txt
5
+ include pyproject.toml
6
+ include setup.py
7
+ include setup.cfg
8
+ recursive-include src *.py
9
+ recursive-include docs *.rst *.md
10
+ recursive-exclude * __pycache__
11
+ recursive-exclude * *.py[co]
12
+ recursive-exclude * .DS_Store
13
+ prune tests
14
+ prune .git
15
+ prune .github
16
+ global-exclude *.pyc *.pyo
17
+
18
+ # Added entries (2 items) - 2026-08-31 03:15:31
19
+ exclude gitea_cli.ini.sha256
20
+ prune gitignore_backup
21
+
22
+ # Added entries (1 items) - 2026-08-31 03:16:03
23
+ exclude gitea_cli.ini
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitea-cli
3
+ Version: 0.12.3
4
+ Summary: A production-grade CLI tool for interacting with Gitea API (Migration, Mirroring, Forking, Polling).
5
+ Home-page: https://github.com/cumulus13/gitea_cli
6
+ Author: Hadi Cahyadi
7
+ Author-email: cumulus13@gmail.com
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/cumulus13/gitea_cli
10
+ Project-URL: Repository, https://github.com/cumulus13/gitea_cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Version Control :: Git
21
+ Requires-Python: >=3.7
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: requests>=2.28.0
24
+ Requires-Dist: rich>=12.0.0
25
+ Requires-Dist: rich-argparse>=1.0.0
26
+ Requires-Dist: configset>=0.2.0
27
+ Requires-Dist: clipboard>=0.0.4
28
+ Dynamic: author-email
29
+ Dynamic: home-page
30
+ Dynamic: requires-python
31
+
32
+ # Gitea CLI
33
+
34
+ Simple gitea cli
35
+
36
+ ## 👤 Author
37
+
38
+ [Hadi Cahyadi](mailto:cumulus13@gmail.com)
39
+
40
+
41
+ [![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/cumulus13)
42
+
43
+ [![Donate via Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/cumulus13)
44
+
45
+ [Support me on Patreon](https://www.patreon.com/cumulus13)
@@ -0,0 +1,14 @@
1
+ # Gitea CLI
2
+
3
+ Simple gitea cli
4
+
5
+ ## 👤 Author
6
+
7
+ [Hadi Cahyadi](mailto:cumulus13@gmail.com)
8
+
9
+
10
+ [![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/cumulus13)
11
+
12
+ [![Donate via Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/cumulus13)
13
+
14
+ [Support me on Patreon](https://www.patreon.com/cumulus13)
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # File: gitea_cli/__init__.py
4
+ # Author: Hadi Cahyadi <cumulus13@gmail.com>
5
+ # Date: 2026-08-31
6
+ # Description: Gitea CLI - Interactive tool for Gitea API operations.
7
+ # License: MIT
8
+
9
+ """
10
+ Gitea CLI - Interactive tool for Gitea API operations.
11
+ """
12
+
13
+ from pathlib import Path
14
+ import traceback
15
+ import os
16
+
17
+ # Read version from __init__.py
18
+ def get_version():
19
+ """
20
+ Get the version.
21
+ Version is taken from the __version__.py file if it exists.
22
+ The content of __version__.py should be:
23
+ version = "0.33"
24
+ """
25
+ try:
26
+ version_file = Path(__file__).parent / "__version__.py"
27
+ if not version_file.is_file():
28
+ version_file = Path(__file__).parent.parent / "__version__.py"
29
+ if version_file.is_file():
30
+ with open(version_file, "r") as f:
31
+ for line in f:
32
+ if line.strip().startswith("version"):
33
+ parts = line.split("=")
34
+ if len(parts) == 2:
35
+ return parts[1].strip().strip('"').strip("'")
36
+ else:
37
+ print("No __version__ file found for __init__")
38
+
39
+ except Exception as e:
40
+ if os.getenv('TRACEBACK') and os.getenv('TRACEBACK') in ('1', 'true', 'True'):
41
+ print(traceback.format_exc())
42
+ else:
43
+ print(f"ERROR: {e}")
44
+
45
+ return "0.1.0"
46
+
47
+ __version__ = get_version()
@@ -0,0 +1 @@
1
+ version = "0.12.3"
@@ -0,0 +1,439 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # File: gitea_cli/main.py
4
+ # Author: Hadi Cahyadi <cumulus13@gmail.com>
5
+ # Date: 2026-08-31
6
+ # Description: Simple gitea cli
7
+ # License: MIT
8
+
9
+ import argparse
10
+ import getpass
11
+ import os
12
+ import sys
13
+ import time
14
+ from pathlib import Path
15
+ from typing import ClassVar, Optional
16
+
17
+ import clipboard
18
+ import requests
19
+ from configset import configset # type: ignore
20
+ from rich.console import Console
21
+ from rich_argparse import RichHelpFormatter, _lazy_rich as rr
22
+
23
+ console = Console()
24
+
25
+
26
+ class CustomRichHelpFormatter(RichHelpFormatter):
27
+ """A custom RichHelpFormatter with modified styles."""
28
+
29
+ styles: ClassVar[dict[str, rr.StyleType]] = {
30
+ "argparse.args": "bold #FFFF00",
31
+ "argparse.groups": "#AA55FF",
32
+ "argparse.help": "bold #00FFFF",
33
+ "argparse.metavar": "bold #FF00FF",
34
+ "argparse.syntax": "underline",
35
+ "argparse.text": "white",
36
+ "argparse.prog": "bold #00AAFF italic",
37
+ "argparse.default": "bold",
38
+ }
39
+
40
+
41
+ class CLI:
42
+ """A command-line interface for interacting with Gitea API."""
43
+
44
+ CONFIGFILE = str(Path.home() / ".gitea_cli.ini")
45
+ CONFIG = configset(CONFIGFILE)
46
+
47
+ @classmethod
48
+ def setup_parser(cls):
49
+ subparsers = cls.parser.add_subparsers(dest="command", required=True)
50
+
51
+ # REPO subparser
52
+ repo_parser = subparsers.add_parser(
53
+ "repo",
54
+ help="Repository operations",
55
+ formatter_class=CustomRichHelpFormatter,
56
+ )
57
+ repo_parser.add_argument(
58
+ "-a", "--add", metavar="REPO_NAME", help="Create new repository"
59
+ )
60
+ repo_parser.add_argument(
61
+ "-l", "--list", action="store_true", help="List repositories"
62
+ )
63
+ repo_parser.add_argument(
64
+ "-rm", "--remove", metavar="REPO_NAME", help="Remove repository"
65
+ )
66
+
67
+ # Migration and Mirroring
68
+ repo_parser.add_argument(
69
+ "-m",
70
+ "--migrate",
71
+ metavar="REMOTE_URL",
72
+ help="Migrate/clone repository from remote server (GitHub, GitLab, Gogs, private Git)",
73
+ )
74
+ repo_parser.add_argument(
75
+ "--service",
76
+ choices=["git", "github", "gitlab", "gogs", "gitea", "codeberg"],
77
+ default="git",
78
+ help="Remote Git service type (default: git)",
79
+ )
80
+ repo_parser.add_argument(
81
+ "--mirror",
82
+ action="store_true",
83
+ help="Set repository as a continuously syncing mirror",
84
+ )
85
+ repo_parser.add_argument(
86
+ "-n",
87
+ "--name",
88
+ metavar="REPO_NAME",
89
+ help="Target repository name on Gitea",
90
+ )
91
+ repo_parser.add_argument(
92
+ "--organization",
93
+ metavar="ORG_NAME",
94
+ help="Target organization on Gitea (optional)",
95
+ )
96
+ repo_parser.add_argument(
97
+ "--private",
98
+ action="store_true",
99
+ help="Make target repository private on Gitea",
100
+ )
101
+
102
+ # Forking
103
+ repo_parser.add_argument(
104
+ "-fk",
105
+ "--fork",
106
+ metavar="OWNER/REPO",
107
+ help="Fork repository (e.g. owner/repo_name)",
108
+ )
109
+
110
+ # Source Authentication Flags
111
+ auth_group = repo_parser.add_argument_group("Source Repository Credentials")
112
+ auth_group.add_argument(
113
+ "--clone-user",
114
+ help="Username for remote repo authentication (HTTPS Basic Auth)",
115
+ )
116
+ auth_group.add_argument(
117
+ "--clone-pass",
118
+ help="Password for remote repo authentication",
119
+ )
120
+ auth_group.add_argument(
121
+ "--clone-token",
122
+ help="Personal Access Token for remote repo (GitHub/GitLab/Gitea token)",
123
+ )
124
+
125
+ # Migration Scope Toggles
126
+ toggle_group = repo_parser.add_argument_group("Migration Scope Options")
127
+ toggle_group.add_argument("--no-wiki", action="store_true", help="Do not migrate wiki")
128
+ toggle_group.add_argument("--no-labels", action="store_true", help="Do not migrate labels")
129
+ toggle_group.add_argument("--no-issues", action="store_true", help="Do not migrate issues")
130
+ toggle_group.add_argument("--no-pull-requests", action="store_true", help="Do not migrate pull requests")
131
+ toggle_group.add_argument("--no-releases", action="store_true", help="Do not migrate releases")
132
+ toggle_group.add_argument("--no-milestones", action="store_true", help="Do not migrate milestones")
133
+
134
+ @classmethod
135
+ def usage(cls):
136
+ cls.parser = argparse.ArgumentParser(
137
+ prog="gitea-cli",
138
+ description="Gitea CLI - Interact with Gitea API",
139
+ formatter_class=CustomRichHelpFormatter,
140
+ )
141
+ cls.parser.add_argument("-u", "--username", help="Gitea username")
142
+ cls.parser.add_argument("-p", "--password", help="Gitea password")
143
+ cls.parser.add_argument(
144
+ "--api",
145
+ help="Gitea API token/key",
146
+ default=cls.CONFIG.get_config("api", "key", ""),
147
+ )
148
+ cls.parser.add_argument(
149
+ "--url",
150
+ help="Gitea API endpoint URL",
151
+ default=cls.CONFIG.get_config("api", "url", "http://localhost:3000/api/v1"),
152
+ )
153
+ cls.setup_parser()
154
+
155
+ if len(sys.argv) == 1:
156
+ cls.parser.print_help()
157
+ return
158
+
159
+ args = cls.parser.parse_args()
160
+ cls.handle_args(args)
161
+
162
+ @classmethod
163
+ def get_auth_headers(cls, args):
164
+ api_key = args.api or cls.CONFIG.get_config("api", "key", "")
165
+ headers = {"Authorization": f"token {api_key}"} if api_key else {}
166
+ auth = None
167
+ if not api_key:
168
+ username = args.username or cls.CONFIG.get_config("auth", "username", "")
169
+ password = args.password or cls.CONFIG.get_config("auth", "password", "")
170
+ if username and not password:
171
+ password = getpass.getpass(f"Enter password for Gitea user '{username}': ")
172
+ if username and password:
173
+ auth = (username, password)
174
+ return auth, headers
175
+
176
+ @classmethod
177
+ def get_current_user(cls, args) -> Optional[dict]:
178
+ """Fetch details of authenticated user."""
179
+ url = f"{args.url.rstrip('/')}/user"
180
+ auth, headers = cls.get_auth_headers(args)
181
+ try:
182
+ r = requests.get(url, auth=auth, headers=headers, timeout=15)
183
+ if r.status_code == 200:
184
+ return r.json()
185
+ console.print(
186
+ f"❌ [red]Failed to get current user: {r.status_code} {r.text}[/]"
187
+ )
188
+ return None
189
+ except Exception as e:
190
+ console.print(f"❌ [red]Error fetching user details:[/] {e}")
191
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
192
+ console.print_exception()
193
+ return None
194
+
195
+ @classmethod
196
+ def poll_repo_completion(
197
+ cls, args, owner: str, repo_name: str, timeout: int = 600, interval: int = 4
198
+ ) -> bool:
199
+ """Poll repo state until asynchronous migration, mirror, or fork action completes."""
200
+ url = f"{args.url.rstrip('/')}/repos/{owner}/{repo_name}"
201
+ auth, headers = cls.get_auth_headers(args)
202
+ start_time = time.time()
203
+
204
+ with console.status(
205
+ f"[bold yellow]Waiting for task completion on '{owner}/{repo_name}'...[/]"
206
+ ) as status:
207
+ while time.time() - start_time < timeout:
208
+ try:
209
+ r = requests.get(url, auth=auth, headers=headers, timeout=15)
210
+ if r.status_code == 200:
211
+ data = r.json()
212
+ if not data.get("empty", True) or data.get("size", 0) > 0:
213
+ status.stop()
214
+ console.print(
215
+ f"✅ [bold green]Repository '{owner}/{repo_name}' is ready![/]"
216
+ )
217
+ return True
218
+ except Exception:
219
+ pass
220
+ time.sleep(interval)
221
+
222
+ console.print(
223
+ f"⚠️ [bold yellow]Polling timed out for '{owner}/{repo_name}'. Check Gitea Web UI.[/]"
224
+ )
225
+ return False
226
+
227
+ @classmethod
228
+ def handle_args(cls, args):
229
+ if args.command == "repo":
230
+ if args.add:
231
+ cls.create_repo(args)
232
+ elif args.list:
233
+ cls.list_repos(args)
234
+ elif args.remove:
235
+ cls.remove_repo(args)
236
+ elif args.migrate:
237
+ repo_name = (
238
+ args.name
239
+ or args.migrate.rstrip("/").split("/")[-1].replace(".git", "")
240
+ )
241
+ cls.migrate_repo(
242
+ args,
243
+ repo_name=repo_name,
244
+ remote_url=args.migrate,
245
+ )
246
+ elif args.fork:
247
+ cls.fork_repo(args)
248
+ else:
249
+ console.print("⚠️ [red]No repo action specified.[/]")
250
+ sys.exit(1)
251
+
252
+ @classmethod
253
+ def migrate_repo(cls, args, repo_name: str, remote_url: str):
254
+ """Migrate or Mirror a remote repository with full auth and service options."""
255
+ action_label = "Mirroring" if args.mirror else "Migrating"
256
+ console.print(
257
+ f"🚩 [#FFFF00]{action_label} repository[/] [bold #00FFFF]'{repo_name}'[/] from [bold #00FFAA]{remote_url}[/]..."
258
+ )
259
+
260
+ user_info = cls.get_current_user(args)
261
+ if not user_info:
262
+ return
263
+
264
+ owner = args.organization or user_info.get("login") or user_info.get("username")
265
+ uid = user_info.get("id")
266
+
267
+ url = f"{args.url.rstrip('/')}/repos/migrate"
268
+ auth, headers = cls.get_auth_headers(args)
269
+
270
+ payload = {
271
+ "clone_addr": remote_url,
272
+ "repo_name": repo_name,
273
+ "service": args.service,
274
+ "mirror": args.mirror,
275
+ "private": args.private,
276
+ "wiki": not args.no_wiki,
277
+ "labels": not args.no_labels,
278
+ "issues": not args.no_issues,
279
+ "pull_requests": not args.no_pull_requests,
280
+ "releases": not args.no_releases,
281
+ "milestones": not args.no_milestones,
282
+ }
283
+
284
+ if args.organization:
285
+ payload["repo_owner"] = args.organization
286
+ else:
287
+ payload["uid"] = uid
288
+
289
+ if args.clone_token:
290
+ payload["auth_token"] = args.clone_token
291
+ elif args.clone_user:
292
+ clone_pass = args.clone_pass or getpass.getpass(f"Enter password for remote user '{args.clone_user}': ")
293
+ payload["auth_username"] = args.clone_user
294
+ payload["auth_password"] = clone_pass
295
+
296
+ try:
297
+ r = requests.post(url, auth=auth, headers=headers, json=payload, timeout=30)
298
+ if r.status_code in (201, 202):
299
+ console.print(
300
+ "🔄 [#00FFAA]Task accepted by Gitea. Polling migration status...[/]"
301
+ )
302
+ cls.poll_repo_completion(args, owner=owner, repo_name=repo_name)
303
+ else:
304
+ console.print(
305
+ f"❌ [red]Failed to start migration:[/] [#FFFF00]{r.status_code}[/] [#00FFFF]{r.text}[/]"
306
+ )
307
+ except Exception as e:
308
+ console.print(f"❌ [red]Migration Request Error:[/] {e}")
309
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
310
+ console.print_exception()
311
+
312
+ @classmethod
313
+ def fork_repo(cls, args):
314
+ """Fork an existing repository."""
315
+ parts = args.fork.strip("/").split("/")
316
+ if len(parts) != 2:
317
+ console.print(
318
+ "❌ [red]Invalid fork target format. Use 'owner/repo' (e.g. upstream_user/target_repo).[/]"
319
+ )
320
+ return
321
+
322
+ src_owner, src_repo = parts[0], parts[1]
323
+ user_info = cls.get_current_user(args)
324
+ if not user_info:
325
+ return
326
+
327
+ target_owner = args.organization or user_info.get("login") or user_info.get("username")
328
+ target_name = args.name or src_repo
329
+
330
+ url = f"{args.url.rstrip('/')}/repos/{src_owner}/{src_repo}/forks"
331
+ auth, headers = cls.get_auth_headers(args)
332
+
333
+ payload = {}
334
+ if args.organization:
335
+ payload["organization"] = args.organization
336
+ if args.name:
337
+ payload["name"] = args.name
338
+
339
+ console.print(
340
+ f"🍴 [#FFFF00]Forking[/] [bold #00FFFF]'{src_owner}/{src_repo}'[/] to [bold #00FFAA]'{target_owner}/{target_name}'[/]..."
341
+ )
342
+
343
+ try:
344
+ r = requests.post(url, auth=auth, headers=headers, json=payload, timeout=30)
345
+ if r.status_code in (201, 202):
346
+ console.print("🔄 [#00FFAA]Fork task accepted. Polling status...[/]")
347
+ cls.poll_repo_completion(args, owner=target_owner, repo_name=target_name)
348
+ else:
349
+ console.print(
350
+ f"❌ [red]Failed to fork repo:[/] [#FFFF00]{r.status_code}[/] [#00FFFF]{r.text}[/]"
351
+ )
352
+ except Exception as e:
353
+ console.print(f"❌ [red]Fork Error:[/] {e}")
354
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
355
+ console.print_exception()
356
+
357
+ @classmethod
358
+ def create_repo(cls, args):
359
+ url = f"{args.url.rstrip('/')}/user/repos"
360
+ auth, headers = cls.get_auth_headers(args)
361
+ data = {"name": args.add, "private": args.private}
362
+ try:
363
+ r = requests.post(url, auth=auth, headers=headers, json=data, timeout=15)
364
+ if r.status_code == 201:
365
+ console.print(
366
+ f"✅ [green]Repository '{args.add}' created successfully.[/]"
367
+ )
368
+ else:
369
+ console.print(
370
+ f"❌ [red]Failed to create repo: {r.status_code} {r.text}[/]"
371
+ )
372
+ except Exception as e:
373
+ console.print(f"❌ [red]Error creating repository:[/] {e}")
374
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
375
+ console.print_exception()
376
+
377
+ @classmethod
378
+ def list_repos(cls, args):
379
+ url = f"{args.url.rstrip('/')}/user/repos"
380
+ auth, headers = cls.get_auth_headers(args)
381
+ r = None
382
+ try:
383
+ r = requests.get(url, auth=auth, headers=headers, timeout=15)
384
+ if r.status_code == 200:
385
+ repos = r.json()
386
+ if repos:
387
+ console.print("🔄 [bold green]Repositories:[/]")
388
+ for repo in repos:
389
+ console.print(f"- {repo['full_name']}")
390
+ else:
391
+ console.print("⚠️ [yellow]No repositories found.[/]")
392
+ else:
393
+ console.print(
394
+ f"❌ [red]Failed to list repos: {r.status_code} {r.text}[/]"
395
+ )
396
+ except Exception as e:
397
+ console.print(f"❌ [red]Error listing repositories:[/] {e}")
398
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
399
+ console.print_exception()
400
+ if r:
401
+ clipboard.copy(r.content.decode())
402
+
403
+ @classmethod
404
+ def remove_repo(cls, args):
405
+ user_info = cls.get_current_user(args)
406
+ if not user_info:
407
+ console.print("\n❌ [red]Cannot determine owner from API credentials.[/]")
408
+ return
409
+
410
+ owner = user_info.get("login") or user_info.get("username")
411
+ url = f"{args.url.rstrip('/')}/repos/{owner}/{args.remove}"
412
+ auth, headers = cls.get_auth_headers(args)
413
+
414
+ try:
415
+ r = requests.delete(url, auth=auth, headers=headers, timeout=15)
416
+ if r.status_code == 204:
417
+ console.print(
418
+ f"🚩 [green]Repository '{args.remove}' deleted successfully.[/]"
419
+ )
420
+ elif r.status_code == 404:
421
+ console.print(
422
+ f"⚠️ [yellow]Repository '{args.remove}' not found.[/]"
423
+ )
424
+ else:
425
+ console.print(
426
+ f"❌ [red]Failed to delete repo: {r.status_code} {r.text}[/]"
427
+ )
428
+ except Exception as e:
429
+ console.print(f"❌ [red]Error deleting repository:[/] {e}")
430
+ if os.getenv("TRACEBACK", "").lower() in ["1", "true"]:
431
+ console.print_exception()
432
+
433
+
434
+ def main():
435
+ CLI.usage()
436
+
437
+
438
+ if __name__ == "__main__":
439
+ main()
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitea-cli
3
+ Version: 0.12.3
4
+ Summary: A production-grade CLI tool for interacting with Gitea API (Migration, Mirroring, Forking, Polling).
5
+ Home-page: https://github.com/cumulus13/gitea_cli
6
+ Author: Hadi Cahyadi
7
+ Author-email: cumulus13@gmail.com
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/cumulus13/gitea_cli
10
+ Project-URL: Repository, https://github.com/cumulus13/gitea_cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Version Control :: Git
21
+ Requires-Python: >=3.7
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: requests>=2.28.0
24
+ Requires-Dist: rich>=12.0.0
25
+ Requires-Dist: rich-argparse>=1.0.0
26
+ Requires-Dist: configset>=0.2.0
27
+ Requires-Dist: clipboard>=0.0.4
28
+ Dynamic: author-email
29
+ Dynamic: home-page
30
+ Dynamic: requires-python
31
+
32
+ # Gitea CLI
33
+
34
+ Simple gitea cli
35
+
36
+ ## 👤 Author
37
+
38
+ [Hadi Cahyadi](mailto:cumulus13@gmail.com)
39
+
40
+
41
+ [![Buy Me a Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/cumulus13)
42
+
43
+ [![Donate via Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/cumulus13)
44
+
45
+ [Support me on Patreon](https://www.patreon.com/cumulus13)
@@ -0,0 +1,13 @@
1
+ MANIFEST.in
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ gitea_cli/__init__.py
6
+ gitea_cli/__version__.py
7
+ gitea_cli/main.py
8
+ gitea_cli.egg-info/PKG-INFO
9
+ gitea_cli.egg-info/SOURCES.txt
10
+ gitea_cli.egg-info/dependency_links.txt
11
+ gitea_cli.egg-info/entry_points.txt
12
+ gitea_cli.egg-info/requires.txt
13
+ gitea_cli.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gitea-cli = gitea_cli.main:main
@@ -0,0 +1,5 @@
1
+ requests>=2.28.0
2
+ rich>=12.0.0
3
+ rich-argparse>=1.0.0
4
+ configset>=0.2.0
5
+ clipboard>=0.0.4
@@ -0,0 +1 @@
1
+ gitea_cli
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=61.0",
4
+ "wheel",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "gitea-cli"
10
+ version = "0.12.3"
11
+ description = "A production-grade CLI tool for interacting with Gitea API (Migration, Mirroring, Forking, Polling)."
12
+ readme = "README.md"
13
+ authors = [
14
+ { name = "Hadi Cahyadi" },
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Version Control :: Git",
27
+ ]
28
+ requires-python = ">=3.9"
29
+ dependencies = [
30
+ "requests>=2.28.0",
31
+ "rich>=12.0.0",
32
+ "rich-argparse>=1.0.0",
33
+ "configset>=0.2.0",
34
+ "clipboard>=0.0.4",
35
+ ]
36
+
37
+ [project.license]
38
+ text = "MIT"
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/cumulus13/gitea_cli"
42
+ Repository = "https://github.com/cumulus13/gitea_cli"
43
+
44
+ [project.scripts]
45
+ gitea-cli = "gitea_cli.main:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python
2
+
3
+ from setuptools import setup, find_packages
4
+ import os
5
+ import shutil
6
+ from pathlib import Path
7
+ import traceback
8
+
9
+ NAME = "gitea_cli"
10
+ this_directory = os.path.abspath(os.path.dirname(__file__))
11
+
12
+ if (Path(__file__).parent / '__version__.py').is_file():
13
+ shutil.copy(str((Path(__file__).parent / '__version__.py')), os.path.join(this_directory, NAME, '__version__.py'))
14
+
15
+ # Read the contents of README file
16
+ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
17
+ long_description = f.read()
18
+
19
+ # Read version from __init__.py
20
+ def get_version():
21
+ """
22
+ Get the version.
23
+ Version is taken from the __version__.py file if it exists.
24
+ The content of __version__.py should be:
25
+ version = "0.33"
26
+ """
27
+ try:
28
+ version_file = Path(__file__).parent / "__version__.py"
29
+ if not version_file.is_file():
30
+ version_file = Path(__file__).parent / NAME / "__version__.py"
31
+ if version_file.is_file():
32
+ with open(version_file, "r") as f:
33
+ for line in f:
34
+ if line.strip().startswith("version"):
35
+ parts = line.split("=")
36
+ if len(parts) == 2:
37
+ return parts[1].strip().strip('"').strip("'")
38
+ except Exception as e:
39
+ if os.getenv('TRACEBACK') and os.getenv('TRACEBACK') in ['1', 'true', 'True']:
40
+ print(traceback.format_exc())
41
+ else:
42
+ print(f"ERROR: {e}")
43
+
44
+ return "0.0.0"
45
+
46
+ print(f"NAME : {NAME}")
47
+ print(f"VERSION: {get_version()}")
48
+
49
+ setup(
50
+ name=NAME,
51
+ version=get_version(),
52
+ author="Hadi Cahyadi",
53
+ author_email="cumulus13@gmail.com",
54
+ description="simple gitea cli",
55
+ long_description=long_description,
56
+ long_description_content_type="text/markdown",
57
+ url=f"https://github.com/cumulus13/{NAME}",
58
+ # packages=find_packages(),
59
+ packages=[NAME],
60
+ classifiers=[
61
+ "Development Status :: 4 - Beta",
62
+ "Intended Audience :: Developers",
63
+ "License :: OSI Approved :: MIT License",
64
+ "Operating System :: OS Independent",
65
+ "Programming Language :: Python :: 3",
66
+ "Programming Language :: Python :: 3.7",
67
+ "Programming Language :: Python :: 3.8",
68
+ "Programming Language :: Python :: 3.9",
69
+ "Programming Language :: Python :: 3.10",
70
+ "Programming Language :: Python :: 3.11",
71
+ "Programming Language :: Python :: 3.12",
72
+ "Topic :: Software Development :: Libraries :: Python Modules",
73
+ "Topic :: System :: Logging",
74
+ "Topic :: Utilities",
75
+ ],
76
+ python_requires=">=3.7",
77
+ install_requires=[
78
+ "rich>=10.0.0",
79
+ "rich_argparse",
80
+ "configset",
81
+ "clipboard"
82
+ ],
83
+ entry_points = {
84
+ "console_scripts":
85
+ [
86
+ "gitea-cli = gitea_cli.main:main",
87
+ ]
88
+ },
89
+ keywords="gitea tools",
90
+ project_urls={
91
+ "Bug Reports": f"https://github.com/cumulus13/{NAME}/issues",
92
+ "Source": f"https://github.com/cumulus13/{NAME}",
93
+ "Documentation": f"https://github.com/cumulus13/{NAME}#readme",
94
+ },
95
+ )