jemo-admin 0.1.4__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,52 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write # Required for trusted publishing
11
+
12
+ jobs:
13
+ release:
14
+ name: Create Release
15
+ runs-on: ubuntu-latest
16
+ environment:
17
+ name: pypi
18
+ url: https://pypi.org/p/jemo-admin
19
+
20
+ steps:
21
+ - name: Checkout code
22
+ uses: actions/checkout@v4
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v5
28
+
29
+ - name: Set up Python
30
+ run: uv python install
31
+
32
+ - name: Build package
33
+ run: uv build
34
+
35
+ - name: Publish to PyPI
36
+ run: uv publish
37
+
38
+ - name: Get version from tag
39
+ id: get_version
40
+ run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
41
+
42
+ - name: Create GitHub Release
43
+ uses: softprops/action-gh-release@v1
44
+ with:
45
+ name: Release ${{ steps.get_version.outputs.VERSION }}
46
+ draft: false
47
+ prerelease: false
48
+ files: |
49
+ dist/*.whl
50
+ dist/*.tar.gz
51
+ env:
52
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,28 @@
1
+ name : put on pypi
2
+ on :
3
+ push :
4
+ branches :
5
+ - main
6
+ jobs:
7
+ publish:
8
+ name: Build and publish to PyPI
9
+ runs-on: ubuntu-latest
10
+ # Required for Trusted Publishing
11
+ permissions:
12
+ id-token: write
13
+ contents: read
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+
21
+ - name: Set up Python
22
+ run: uv python install
23
+
24
+ - name: Build package
25
+ run: uv build
26
+
27
+ - name: Publish package
28
+ run: uv publish --token ${{ secrets.PYPI_TOKEN }}
@@ -0,0 +1 @@
1
+ .env
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: jemo-admin
3
+ Version: 0.1.4
4
+ Summary: A CLI tool to scaffold modern web projects with FastAPI, Django, Convex, Next.js, SvelteKit, or TanStack Start.
5
+ Project-URL: Homepage, https://github.com/jemo/jemo-admin
6
+ Project-URL: Repository, https://github.com/jemo/jemo-admin
7
+ Project-URL: Issues, https://github.com/jemo/jemo-admin/issues
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: questionary>=2.1.1
10
+ Requires-Dist: rich>=14.3.2
11
+ Requires-Dist: typer>=0.23.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Jemo Admin CLI
15
+
16
+ A powerful CLI tool to scaffold modern web projects with your favorite stack.
17
+
18
+ ## Supported Stacks
19
+
20
+ **Backend:**
21
+ - **FastAPI** (with Tortoise ORM & Aerich)
22
+ - **Django**
23
+ - **Convex** (Serverless)
24
+
25
+ **Frontend:**
26
+ - **Next.js**
27
+ - **SvelteKit**
28
+ - **TanStack Start**
29
+
30
+ ## Installation
31
+
32
+ You can install `jemo-admin` using `pipx`:
33
+
34
+ ```bash
35
+ pipx install .
36
+ # Or from a git repo:
37
+ # pipx install git+https://github.com/Jemo69/create-jemo-app.git
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Create a new project interactively:
43
+
44
+ ```bash
45
+ jemo-admin create
46
+ ```
47
+
48
+ Or specify the project name directly:
49
+
50
+ ```bash
51
+ jemo-admin create my-awesome-app
52
+ ```
53
+
54
+ Follow the interactive prompts to select your backend and frontend framework.
55
+
56
+ ## Requirements
57
+
58
+ - **Python 3.12+**
59
+ - **Bun** (for frontend package management)
60
+ - **UV** (for Python package management)
61
+ Note : it does not work on Windows.
@@ -0,0 +1,48 @@
1
+ # Jemo Admin CLI
2
+
3
+ A powerful CLI tool to scaffold modern web projects with your favorite stack.
4
+
5
+ ## Supported Stacks
6
+
7
+ **Backend:**
8
+ - **FastAPI** (with Tortoise ORM & Aerich)
9
+ - **Django**
10
+ - **Convex** (Serverless)
11
+
12
+ **Frontend:**
13
+ - **Next.js**
14
+ - **SvelteKit**
15
+ - **TanStack Start**
16
+
17
+ ## Installation
18
+
19
+ You can install `jemo-admin` using `pipx`:
20
+
21
+ ```bash
22
+ pipx install .
23
+ # Or from a git repo:
24
+ # pipx install git+https://github.com/Jemo69/create-jemo-app.git
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Create a new project interactively:
30
+
31
+ ```bash
32
+ jemo-admin create
33
+ ```
34
+
35
+ Or specify the project name directly:
36
+
37
+ ```bash
38
+ jemo-admin create my-awesome-app
39
+ ```
40
+
41
+ Follow the interactive prompts to select your backend and frontend framework.
42
+
43
+ ## Requirements
44
+
45
+ - **Python 3.12+**
46
+ - **Bun** (for frontend package management)
47
+ - **UV** (for Python package management)
48
+ Note : it does not work on Windows.
@@ -0,0 +1,163 @@
1
+ from pathlib import Path
2
+ import subprocess
3
+ import shutil
4
+ from rich.console import Console
5
+
6
+ console = Console()
7
+
8
+
9
+ def run_command(command, cwd=None, shell=False):
10
+ """Run a shell command."""
11
+ try:
12
+ # Capture output to show on error
13
+ subprocess.run(command, cwd=cwd, shell=shell, check=True, capture_output=False)
14
+ except subprocess.CalledProcessError as e:
15
+ console.print(f"[red]Error executing command: {command}[/red]")
16
+ console.print(f"[red]Exit Code: {e.returncode}[/red]")
17
+ if e.stdout:
18
+ console.print(f"[red]Stdout: {e.stdout.decode()}[/red]")
19
+ if e.stderr:
20
+ console.print(f"[red]Stderr: {e.stderr.decode()}[/red]")
21
+ raise e
22
+
23
+
24
+ def create_fastapi(project_dir: Path, separate_folders: bool = True):
25
+ """Scaffold a FastAPI project with Tortoise ORM and Aerich."""
26
+
27
+ backend_dir = project_dir / "backend"
28
+ if separate_folders:
29
+ backend_dir.mkdir(parents=True, exist_ok=True)
30
+ else:
31
+ backend_dir = project_dir # If not separate folders, use project dir directly (uncommon for backend+frontend combo)
32
+
33
+ console.print(
34
+ f"[bold cyan]Initializing FastAPI backend in {backend_dir}...[/bold cyan]"
35
+ )
36
+
37
+ # Initialize UV project
38
+ # Use --no-workspace to ensure we create a standalone project
39
+ run_command(["uv", "init", "--app", "--no-workspace"], cwd=backend_dir)
40
+
41
+ # Add dependencies
42
+ console.print(
43
+ "[bold]Adding dependencies: fastapi, uvicorn, tortoise-orm, aerich...[/bold]"
44
+ )
45
+ run_command(
46
+ ["uv", "add", "fastapi", "uvicorn", "tortoise-orm", "aerich"], cwd=backend_dir
47
+ )
48
+
49
+ # Create main.py
50
+ main_py_content = """
51
+ from fastapi import FastAPI
52
+ from tortoise import Tortoise
53
+ from tortoise.contrib.fastapi import register_tortoise
54
+
55
+ app = FastAPI(title="Jemo Admin API")
56
+
57
+ @app.get("/")
58
+ async def read_root():
59
+ return {"message": "Welcome to Jemo Admin FastAPI Backend with Tortoise ORM!"}
60
+
61
+ # Database Configuration
62
+ TORTOISE_ORM = {
63
+ "connections": {"default": "sqlite://db.sqlite3"},
64
+ "apps": {
65
+ "models": {
66
+ "models": ["aerich.models", "models"], # Add your models here
67
+ "default_connection": "default",
68
+ },
69
+ },
70
+ }
71
+
72
+ register_tortoise(
73
+ app,
74
+ config=TORTOISE_ORM,
75
+ generate_schemas=True,
76
+ add_exception_handlers=True,
77
+ )
78
+ """
79
+ (backend_dir / "main.py").write_text(main_py_content)
80
+
81
+ # Create models.py
82
+ models_py_content = """
83
+ from tortoise import fields, models
84
+
85
+ class User(models.Model):
86
+ id = fields.IntField(pk=True)
87
+ username = fields.CharField(max_length=50, unique=True)
88
+ email = fields.CharField(max_length=255, unique=True)
89
+ created_at = fields.DatetimeField(auto_now_add=True)
90
+
91
+ def __str__(self):
92
+ return self.username
93
+ """
94
+ (backend_dir / "models.py").write_text(models_py_content)
95
+
96
+ # Create tortoise_conf.py for Aerich
97
+ tortoise_conf_content = """
98
+ TORTOISE_ORM = {
99
+ "connections": {"default": "sqlite://db.sqlite3"},
100
+ "apps": {
101
+ "models": {
102
+ "models": ["aerich.models", "models"],
103
+ "default_connection": "default",
104
+ },
105
+ },
106
+ }
107
+ """
108
+ (backend_dir / "tortoise_conf.py").write_text(tortoise_conf_content)
109
+
110
+ console.print("[green]FastAPI backend setup complete![/green]")
111
+
112
+
113
+ def create_django(project_dir: Path, separate_folders: bool = True):
114
+ """Scaffold a Django project."""
115
+
116
+ backend_dir = project_dir / "backend"
117
+ if separate_folders:
118
+ backend_dir.mkdir(parents=True, exist_ok=True)
119
+ else:
120
+ backend_dir = project_dir
121
+
122
+ console.print(
123
+ f"[bold cyan]Initializing Django backend in {backend_dir}...[/bold cyan]"
124
+ )
125
+
126
+ # Initialize UV project
127
+ # Use --no-workspace to ensure we create a standalone project
128
+ run_command(["uv", "init", "--app", "--no-workspace"], cwd=backend_dir)
129
+
130
+ # Add Django
131
+ console.print("[bold]Adding dependencies: django...[/bold]")
132
+ run_command(["uv", "add", "django"], cwd=backend_dir)
133
+
134
+ # Create Django Project
135
+ # We use 'config' as the project name usually, or 'core'. Let's use 'config'.
136
+ console.print("[bold]Running django-admin startproject...[/bold]")
137
+ run_command(
138
+ ["uv", "run", "django-admin", "startproject", "config", "."], cwd=backend_dir
139
+ )
140
+
141
+ console.print("[green]Django backend setup complete![/green]")
142
+
143
+
144
+ def create_convex_standalone(project_dir: Path):
145
+ """Initialize Convex in a standalone directory (rarely used without frontend)."""
146
+ console.print(f"[bold cyan]Initializing Convex in {project_dir}...[/bold cyan]")
147
+
148
+ project_dir.mkdir(parents=True, exist_ok=True)
149
+
150
+ # Check if npm/bun init is needed first
151
+ if not (project_dir / "package.json").exists():
152
+ run_command(["bun", "init", "-y"], cwd=project_dir)
153
+
154
+ run_command(["bun", "add", "convex"], cwd=project_dir)
155
+ run_command(
156
+ ["npx", "convex", "dev"], cwd=project_dir
157
+ ) # This is interactive usually!
158
+ # Wait, 'npx convex dev' is interactive and blocking. We probably shouldn't run it here.
159
+ # We should just install it and tell user to run it.
160
+
161
+ console.print(
162
+ "[green]Convex setup complete! Run 'npx convex dev' to start.[/green]"
163
+ )
@@ -0,0 +1,186 @@
1
+ from pathlib import Path
2
+ import subprocess
3
+ import shutil
4
+ from rich.console import Console
5
+
6
+ console = Console()
7
+
8
+
9
+ def run_command(command, cwd=None, capture_output=False):
10
+ """Run a shell command."""
11
+ try:
12
+ result = subprocess.run(
13
+ command, cwd=cwd, check=True, capture_output=capture_output, text=True
14
+ )
15
+ return result
16
+ except subprocess.CalledProcessError as e:
17
+ console.print(f"[red]Error executing command: {' '.join(command)}[/red]")
18
+ if e.stderr:
19
+ console.print(f"[red]{e.stderr}[/red]")
20
+ raise e
21
+
22
+
23
+ def add_dependency(package_manager, package, cwd, dev=False):
24
+ """Add a dependency."""
25
+ cmd = [package_manager, "add", "-d" if dev else "", package]
26
+ cmd = [c for c in cmd if c]
27
+ subprocess.run(cmd, cwd=cwd, check=True)
28
+
29
+
30
+ def install_tailwind(project_dir: Path, framework: str):
31
+ """Install and configure Tailwind CSS."""
32
+ console.print(f"[bold]Setting up Tailwind CSS for {framework}...[/bold]")
33
+
34
+ if framework == "nextjs":
35
+ # Next.js with --yes already includes Tailwind by default
36
+ console.print(
37
+ "[green]Tailwind CSS already included with Next.js defaults[/green]"
38
+ )
39
+ return
40
+
41
+ # For other frameworks, install Tailwind v4 (zero config)
42
+ try:
43
+ # Install tailwindcss v4
44
+ run_command(
45
+ ["bun", "add", "-d", "tailwindcss"],
46
+ cwd=project_dir,
47
+ )
48
+
49
+ console.print("[green]Tailwind CSS v4 installed (zero config mode)[/green]")
50
+ console.print("[yellow]Note: Import Tailwind in your CSS file:[/yellow]")
51
+ console.print(' @import "tailwindcss";')
52
+ except Exception as e:
53
+ console.print(
54
+ f"[yellow]Warning: Could not auto-configure Tailwind. You may need to set it up manually.[/yellow]"
55
+ )
56
+
57
+
58
+ def create_nextjs(
59
+ project_dir: Path, subfolder: str = "frontend", use_convex: bool = False
60
+ ):
61
+ """Scaffold a Next.js project with Tailwind CSS."""
62
+ target_dir = project_dir / subfolder if subfolder != "." else project_dir
63
+ console.print(f"[bold cyan]Initializing Next.js in {target_dir}...[/bold cyan]")
64
+
65
+ if not project_dir.exists():
66
+ project_dir.mkdir(parents=True)
67
+
68
+ # Use --yes for non-interactive mode with defaults (includes Tailwind)
69
+ cmd = ["bun", "create", "next-app", subfolder if subfolder != "." else ".", "--yes"]
70
+ try:
71
+ run_command(cmd, cwd=project_dir)
72
+ except Exception:
73
+ console.print("[red]Failed to create Next.js project[/red]")
74
+ return
75
+
76
+ if not target_dir.exists():
77
+ console.print(f"[red]Error: Directory {target_dir} was not created.[/red]")
78
+ return
79
+
80
+ # Tailwind is already included with --yes flag (default Next.js setup includes it)
81
+ console.print("[green]Next.js with Tailwind CSS created successfully![/green]")
82
+
83
+ if use_convex:
84
+ console.print("[bold]Adding Convex to Next.js...[/bold]")
85
+ add_dependency("bun", "convex", cwd=target_dir)
86
+ console.print(
87
+ "[yellow]Note: Run 'npx convex dev' in the frontend directory to configure Convex.[/yellow]"
88
+ )
89
+
90
+
91
+ def create_sveltekit(
92
+ project_dir: Path, subfolder: str = "frontend", use_convex: bool = False
93
+ ):
94
+ """Scaffold a SvelteKit project with Tailwind CSS."""
95
+ target_dir = project_dir / subfolder if subfolder != "." else project_dir
96
+ console.print(f"[bold cyan]Initializing SvelteKit in {target_dir}...[/bold cyan]")
97
+
98
+ if not project_dir.exists():
99
+ project_dir.mkdir(parents=True)
100
+
101
+ # Use npx sv create with flags for non-interactive mode
102
+ folder_arg = subfolder if subfolder != "." else "."
103
+ cmd = [
104
+ "npx",
105
+ "sv",
106
+ "create",
107
+ folder_arg,
108
+ "--template",
109
+ "demo", # Use demo template (includes more features)
110
+ "--types",
111
+ "ts", # TypeScript
112
+ "--no-add-ons", # Don't prompt for add-ons
113
+ "--install",
114
+ "bun", # Use bun to install
115
+ ]
116
+
117
+ try:
118
+ run_command(cmd, cwd=project_dir)
119
+ except Exception:
120
+ console.print("[red]Failed to create SvelteKit project[/red]")
121
+ return
122
+
123
+ if not target_dir.exists():
124
+ console.print(
125
+ f"[red]Error: Directory {target_dir} was not created. Skipping subsequent steps.[/red]"
126
+ )
127
+ return
128
+
129
+ console.print("[bold]Installing dependencies...[/bold]")
130
+ run_command(["bun", "install"], cwd=target_dir)
131
+
132
+ # Add Tailwind CSS
133
+ install_tailwind(target_dir, "sveltekit")
134
+
135
+ if use_convex:
136
+ console.print("[bold]Adding Convex to SvelteKit...[/bold]")
137
+ add_dependency("bun", "convex", cwd=target_dir)
138
+ console.print(
139
+ "[yellow]Note: Run 'npx convex dev' in the frontend directory to configure Convex.[/yellow]"
140
+ )
141
+
142
+
143
+ def create_tanstack(
144
+ project_dir: Path, subfolder: str = "frontend", use_convex: bool = False
145
+ ):
146
+ """Scaffold a TanStack Start project with Tailwind CSS."""
147
+ target_dir = project_dir / subfolder if subfolder != "." else project_dir
148
+ console.print(
149
+ f"[bold cyan]Initializing TanStack Start in {target_dir}...[/bold cyan]"
150
+ )
151
+
152
+ if not project_dir.exists():
153
+ project_dir.mkdir(parents=True)
154
+
155
+ # Use create subcommand (required for @tanstack/start v1)
156
+ folder_arg = subfolder if subfolder != "." else "."
157
+ cmd = [
158
+ "bun",
159
+ "create",
160
+ "@tanstack/start",
161
+ "create", # Subcommand required
162
+ folder_arg,
163
+ "--package-manager",
164
+ "bun",
165
+ "--no-git", # We'll handle git separately
166
+ ]
167
+
168
+ try:
169
+ run_command(cmd, cwd=project_dir)
170
+ except Exception:
171
+ console.print("[red]Failed to create TanStack Start project[/red]")
172
+ return
173
+
174
+ if not target_dir.exists():
175
+ console.print(f"[red]Error: Directory {target_dir} was not created.[/red]")
176
+ return
177
+
178
+ # Add Tailwind CSS
179
+ install_tailwind(target_dir, "tanstack")
180
+
181
+ if use_convex:
182
+ console.print("[bold]Adding Convex to TanStack Start...[/bold]")
183
+ add_dependency("bun", "convex", cwd=target_dir)
184
+ console.print(
185
+ "[yellow]Note: Run 'npx convex dev' in the frontend directory to configure Convex.[/yellow]"
186
+ )
@@ -0,0 +1,42 @@
1
+ from pathlib import Path
2
+ import subprocess
3
+ from rich.console import Console
4
+
5
+ console = Console()
6
+
7
+
8
+ def run_command(command, cwd=None):
9
+ """Run a shell command."""
10
+ try:
11
+ subprocess.run(command, cwd=cwd, check=True, stdout=subprocess.DEVNULL)
12
+ except subprocess.CalledProcessError as e:
13
+ console.print(f"[red]Error executing command: {' '.join(command)}[/red]")
14
+ # Don't raise, just warn for VCS
15
+ console.print(
16
+ f"[yellow]VCS initialization failed. You may need to install the tool or init manually.[/yellow]"
17
+ )
18
+
19
+
20
+ def init_git(project_dir: Path):
21
+ """Initialize a Git repository."""
22
+ console.print(
23
+ f"[bold cyan]Initializing Git repository in {project_dir}...[/bold cyan]"
24
+ )
25
+ run_command(["git", "init"], cwd=project_dir)
26
+ # create .gitignore if it doesn't exist?
27
+ # Usually frameworks create their own .gitignores.
28
+ # We might want to stage files.
29
+ # run_command(["git", "add", "."], cwd=project_dir)
30
+ # console.print("[green]Git initialized.[/green]")
31
+
32
+
33
+ def init_jj(project_dir: Path):
34
+ """Initialize a Jujutsu repository (git-backed)."""
35
+ console.print(
36
+ f"[bold cyan]Initializing Jujutsu (jj) repository in {project_dir}...[/bold cyan]"
37
+ )
38
+
39
+ # 'jj git init' creates a repo backed by git, which is most common for interop.
40
+ run_command(["jj", "git", "init"], cwd=project_dir)
41
+
42
+ console.print("[green]Jujutsu initialized.[/green]")