chore: cli tools

main
NoahLan 1 week ago
parent 30f477550a
commit f64b361d3b

@ -58,21 +58,22 @@ iTi-Flask 是 FastAPI 后端框架基座。
- `copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-project/SKILL.md.jinja`
- 需要保持一致的已生成项目 skill 副本
- 生成项目必须保留 `.copier-answers.yml`,否则不能用 `copier update` 同步模板。
- 已生成项目同步框架依赖用 `./app.sh framework-sync`。
- 已生成项目检查和同步模板用 `./app.sh template-check`、`./app.sh template-update`。
- 已生成项目同步框架依赖用 `iticli sync flask`。
- 已生成项目检查和同步模板用 `iticli template check`、`iticli template update`。
- 模板项目的 Alembic 命令必须显式使用 `-c migrations/alembic.ini`
- 模板项目的测试命令使用 `uv run --extra dev pytest -q`,避免未安装 dev extra 时找不到 pytest。
## 命令
- 安装框架开发依赖:`./scripts/iti.sh install`
- 运行框架测试:`./scripts/iti.sh test`
- 运行检查:`./scripts/iti.sh check`
- 启动最小应用:`./scripts/iti.sh serve 8000`
- 生成业务项目:`./scripts/iti.sh make-app ../my-business-app my-business-app`
- 生成带系统包的业务项目:`./scripts/iti.sh make-system-app ../my-system-app my-system-app`
- 安装框架开发依赖:`iticli install`
- 运行框架测试:`iticli test`
- 启动最小应用:`iticli run dev 8000`
- 生成业务项目:`iticli create ../my-business-app`
- 生成带系统包的业务项目:`iticli create --with-system ../my-system-app`
- 发布框架:`iticli release`
Windows 使用 `scripts\iti.cmd`
框架仓库不再维护 `.sh` / `.cmd` 脚本。
模板生成业务项目不再包含 `app.sh`、`app.cmd`。
## 文档

@ -32,13 +32,13 @@ AI 修改框架代码或文档时优先读:
框架本地开发:
```bash
./iti.sh install
iticli install
```
Windows
```bat
iti.cmd install
iticli install
```
业务项目依赖:
@ -66,7 +66,7 @@ app = create_app(
运行:
```bash
./iti.sh serve 8000
iticli run dev 8000
```
该命令会启动框架最小应用,可用于验证 `/health`、`/ready`。
@ -74,47 +74,47 @@ app = create_app(
## 业务项目生成
```bash
./iti.sh make-app ../my-business-app my-business-app
iticli create ../my-business-app
cd ../my-business-app
./app.sh init
./app.sh serve 8000
iticli init
iticli run dev 8000
```
同步框架依赖和模板骨架:
```bash
./app.sh framework-sync
./app.sh template-check
./app.sh template-update
iticli sync flask
iticli template check
iticli template update
```
`iti-system`
```bash
./iti.sh make-system-app ../my-system-app my-system-app
iticli create --with-system ../my-system-app
cd ../my-system-app
./app.sh init-system
iticli init system
```
所有脚本都带中文 help
新生成的业务项目不再生成 `app.sh`、`app.cmd`。
命令入口:
```bash
./iti.sh help
./app.sh help
iticli help
```
发布框架:
```bash
./iti.sh release
./iti.sh release v0.2.4
iticli release
iticli release v0.2.4
```
Windows:
```bat
iti.cmd release
iti.cmd release v0.2.4
iticli release
iticli release v0.2.4
```
## 文档

@ -1,6 +1,6 @@
---
name: {{ project_slug | lower | replace('_', '-') }}-project
description: "{{ project_name }} 业务项目 skill。用于当前由 iTi-Flask Copier 模板生成的业务后端项目,包括 main.py、config.py、app.sh/app.cmd、pyproject.toml、migrations、tests、modules、models、服务客户端、iTi-Flask 集成{% if include_system %}、iTi-System 注册{% endif %}和项目本地文档。不要写入具体业务域知识。"
description: "{{ project_name }} 业务项目 skill。用于当前由 iTi-Flask Copier 模板生成的业务后端项目,包括 main.py、config.py、pyproject.toml、migrations、tests、modules、models、服务客户端、iTi-Flask 集成{% if include_system %}、iTi-System 注册{% endif %}和项目本地文档。不要写入具体业务域知识。"
---
# {{ project_name }} 业务项目
@ -22,8 +22,8 @@ description: "{{ project_name }} 业务项目 skill。用于当前由 iTi-Flask
- 当前项目未默认注册 iTi-System。需要系统域能力时再显式引入。
{% endif -%}
- 修改代码、架构、目录结构、脚本命令或测试方式后,同步更新这个 skill。
- 同步框架依赖用 `./app.sh framework-sync`。
- 检查和同步框架模板用 `./app.sh template-check`、`./app.sh template-update`。
- 同步框架依赖用 `iticli sync flask`。
- 检查和同步框架模板用 `iticli template check`、`iticli template update`。
## 项目结构
@ -34,8 +34,6 @@ description: "{{ project_name }} 业务项目 skill。用于当前由 iTi-Flask
- `app/models/`:项目 SQLAlchemy 模型。
- `migrations/`:项目自己的 Alembic migration 流。
- `tests/`pytest 路由和行为测试。
- `app.sh`Linux/macOS/Git Bash 命令入口。
- `app.cmd`Windows CMD 命令入口。
- `Dockerfile`:容器镜像构建入口。
- `docker-compose.yml`:本地 Compose 部署入口。
- `docker-compose.with-db.yml`:本地 MySQL 叠加部署入口。
@ -69,23 +67,22 @@ description: "{{ project_name }} 业务项目 skill。用于当前由 iTi-Flask
## 命令
- 安装开发依赖:`./app.sh install`
- 同步框架依赖:`./app.sh framework-sync`
- 检查模板更新:`./app.sh template-check`
- 同步模板骨架:`./app.sh template-update`
- 运行测试:`./app.sh test`
- 本地启动:`./app.sh serve 8000`
- 构建 Docker 镜像:`./app.sh docker-build`
- 启动 Docker Compose`./app.sh docker-up`
- 启动 Docker Compose 和 MySQL`./app.sh docker-up-db`
- 停止 Docker Compose`./app.sh docker-down`
- 停止 Docker Compose 和 MySQL`./app.sh docker-down-db`
- 查看应用容器日志:`./app.sh docker-logs`
- 创建 migration`./app.sh migration "alice add order table"`
- 执行 migration`./app.sh migrate`
- 查看 Alembic heads`./app.sh heads`
- 查看当前 Alembic 版本:`./app.sh current`
- 初始化项目:`./app.sh init`
{{ "系统包相关命令:\n\n- 同步系统 migration`./app.sh system-sync`\n- 初始化或更新系统 seed`./app.sh system-seed`\n- 初始化系统项目:`./app.sh init-system`\n\n" if include_system else "" -}}
Windows 使用 `app.cmd`。
- 安装开发依赖:`iticli install`
- 同步框架依赖:`iticli sync flask`
- 检查模板更新:`iticli template check`
- 同步模板骨架:`iticli template update`
- 运行测试:`iticli test`
- 本地启动:`iticli run dev 8000`
- 构建 Docker 镜像:`iticli docker build`
- 启动 Docker Compose`iticli docker up`
- 启动 Docker Compose 和 MySQL`iticli docker up --db`
- 停止 Docker Compose`iticli docker down`
- 停止 Docker Compose 和 MySQL`iticli docker down --db`
- 查看应用容器日志:`iticli docker logs`
- 创建 migration`iticli migrate revision "alice add order table"`
- 执行 migration`iticli migrate`
- 查看 Alembic heads`iticli migrate heads`
- 查看当前 Alembic 版本:`iticli migrate current`
- 初始化项目:`iticli init`
{{ "系统包相关命令:\n\n- 同步系统 migration`iticli sync system`\n- 初始化系统项目:`iticli init system`\n\n" if include_system else "" -}}

@ -22,59 +22,59 @@ AI 修改本项目时优先读:
```bash
cp .env.example .env
./app.sh init
iticli init
```
Windows
```bat
app.cmd init
iticli init
```
{% if include_system %}
同步系统 migration 和 seed
```bash
./app.sh init-system
iticli init system
```
Windows
```bat
app.cmd init-system
iticli init system
```
{% endif %}
## 开发
```bash
./app.sh serve
./app.sh test
iticli run dev
iticli test
```
不同环境直接在命令前设 `APP_ENV`,或把环境名作为 `serve` 的第一个参数:
不同环境直接在命令前设 `APP_ENV`,或把环境名作为 `run` 的第一个参数:
```bash
./app.sh serve
./app.sh serve test 8000
APP_ENV=prod ./app.sh migrate
iticli run dev
iticli run test 8000
APP_ENV=prod iticli migrate
```
## Docker
```bash
cp .env.example .env
./app.sh docker-up
./app.sh docker-logs
./app.sh docker-down
iticli docker up
iticli docker logs
iticli docker down
```
`docker-compose.yml` 默认只启动应用,数据库使用外部 MySQL。
需要本地 MySQL 时使用:
```bash
./app.sh docker-up-db
./app.sh docker-down-db
iticli docker up --db
iticli docker down --db
```
应用容器启动时会先执行 migration{% if include_system %} 和系统 seed{% endif %}。
@ -85,22 +85,22 @@ cp .env.example .env
同步框架包:
```bash
./app.sh framework-sync
iticli sync flask
```
检查模板:
```bash
./app.sh template-check
iticli template check
```
按模板更新项目骨架:
```bash
./app.sh template-update
iticli template update
```
模板更新会改 `main.py`、`app/app_factory.py`、`config.py`、`Dockerfile`、`docker-compose.yml`、`docker-compose.with-db.yml`、`.dockerignore`、`.env.example`、`.vscode/launch.json`、`app.sh`、`app.cmd`、示例模块、测试和项目 skill 等模板拥有的文件。
模板更新会改 `main.py`、`app/app_factory.py`、`config.py`、`Dockerfile`、`docker-compose.yml`、`docker-compose.with-db.yml`、`.dockerignore`、`.env.example`、`.vscode/launch.json`、示例模块、测试和项目 skill 等模板拥有的文件。
该命令跟随模板仓库 `HEAD`。
执行前先提交或暂存当前项目改动,执行后检查 diff。
@ -112,8 +112,8 @@ cp .env.example .env
## 数据库迁移
```bash
./app.sh migration "alice add example table"
./app.sh migrate
iticli migrate revision "alice add example table"
iticli migrate
```
规则:

@ -1,222 +0,0 @@
@echo off
setlocal enabledelayedexpansion
set "SCRIPT_DIR=%~dp0"
set "ROOT_DIR=%SCRIPT_DIR%"
pushd "%ROOT_DIR%" >nul
set "UV_NO_SOURCES_PACKAGE=iti-flask"
set "PROJECT_VENV=%ROOT_DIR%.venv"
if defined VIRTUAL_ENV (
if /I not "%VIRTUAL_ENV%"=="%PROJECT_VENV%" (
if /I not "%VIRTUAL_ENV%"=="%PROJECT_VENV%\" set "VIRTUAL_ENV="
)
)
set "COMMAND=%~1"
if "%COMMAND%"=="" set "COMMAND=help"
shift /1
if "%COMMAND%"=="help" goto help
if "%COMMAND%"=="-h" goto help
if "%COMMAND%"=="--help" goto help
if "%COMMAND%"=="install" goto install
if "%COMMAND%"=="framework-sync" goto framework_sync
if "%COMMAND%"=="template-check" (
call uvx copier update --defaults --pretend --vcs-ref HEAD "%ROOT_DIR%"
set "EXIT_CODE=!ERRORLEVEL!"
popd >nul
exit /b !EXIT_CODE!
)
if "%COMMAND%"=="template-update" (
call uvx copier update --defaults --vcs-ref HEAD "%ROOT_DIR%"
set "EXIT_CODE=!ERRORLEVEL!"
popd >nul
exit /b !EXIT_CODE!
)
if "%COMMAND%"=="test" goto test
if "%COMMAND%"=="serve" goto serve
if "%COMMAND%"=="docker-build" goto docker_build
if "%COMMAND%"=="docker-up" goto docker_up
if "%COMMAND%"=="docker-up-db" goto docker_up_db
if "%COMMAND%"=="docker-down" goto docker_down
if "%COMMAND%"=="docker-down-db" goto docker_down_db
if "%COMMAND%"=="docker-logs" goto docker_logs
if "%COMMAND%"=="migrate" goto migrate
if "%COMMAND%"=="migration" goto migration
if "%COMMAND%"=="heads" goto heads
if "%COMMAND%"=="current" goto current
{% if include_system %}if "%COMMAND%"=="system-sync" goto system_sync
if "%COMMAND%"=="system-seed" goto system_seed
if "%COMMAND%"=="init-system" goto init_system
{% endif %}if "%COMMAND%"=="init" goto init
echo 未知命令:%COMMAND% 1>&2
echo. 1>&2
goto help_error
:help
echo {{ project_name }} 项目脚本
echo.
echo 用法:
echo app.cmd ^<命令^> [参数]
echo.
echo 常用命令:
echo help 显示帮助
echo install 安装开发依赖uv sync --extra dev
echo framework-sync 同步 iTi-Flask{% if include_system %} / iTi-System{% endif %} 依赖
echo template-check 检查 Copier 模板是否有更新
echo template-update 按 Copier 模板更新项目骨架
echo test 运行测试uv run --extra dev pytest -q
echo serve [环境] [端口] 本地启动,默认 dev / 8000
echo docker-build 构建 Docker 镜像
echo docker-up 启动 Docker Compose 应用
echo docker-up-db 启动 Docker Compose 应用和 MySQL
echo docker-down 停止 Docker Compose 应用
echo docker-down-db 停止 Docker Compose 应用和 MySQL
echo docker-logs 查看应用容器日志
echo migrate 执行 Alembic upgrade head
echo migration ^<说明^> 生成 migration说明建议以作者名开头
echo heads 查看 Alembic heads
echo current 查看当前 Alembic 版本
{% if include_system %}echo system-sync 同步 iti-system migration 到当前项目
echo system-seed 初始化 / 更新系统 seed
echo init-system system-sync + migrate + system-seed
{% endif %}echo init install + migrate{% if include_system %} + system-seed{% endif %}
echo.
echo 示例:
echo app.cmd install
echo app.cmd serve
echo app.cmd docker-up
echo app.cmd serve test 8000
echo set APP_ENV=prod ^&^& app.cmd migrate
echo app.cmd migration "alice add order table"
{% if include_system %}echo app.cmd init-system
{% endif %}popd >nul
exit /b 0
:help_error
call :help
exit /b 2
:install
uv sync --extra dev
goto end
:framework_sync
uv sync --extra dev --upgrade-package iti-flask{% if include_system %} --upgrade-package iti-system{% endif %}
goto end
:test
uv run --extra dev pytest -q
goto end
:serve
set "ENV_NAME=%APP_ENV%"
if not defined ENV_NAME set "ENV_NAME=dev"
set "PORT=8000"
set "ARG1=%~1"
if /I "%ARG1%"=="dev" (
set "ENV_NAME=dev"
set "PORT=%~2"
) else if /I "%ARG1%"=="test" (
set "ENV_NAME=test"
set "PORT=%~2"
) else if /I "%ARG1%"=="prod" (
set "ENV_NAME=prod"
set "PORT=%~2"
) else if /I "%ARG1%"=="default" (
set "ENV_NAME=dev"
set "PORT=%~2"
) else if not "%ARG1%"=="" (
echo(%ARG1%| findstr /r "^[0-9][0-9]*$" >nul
if errorlevel 1 (
set "ENV_NAME=%ARG1%"
set "PORT=%~2"
) else (
set "PORT=%ARG1%"
)
)
if "%PORT%"=="" set "PORT=8000"
set "APP_ENV=%ENV_NAME%"
uv run uvicorn main:app --reload --port "%PORT%"
goto end
:docker_build
docker compose build
goto end
:docker_up
docker compose up -d --build
goto end
:docker_up_db
docker compose -f docker-compose.yml -f docker-compose.with-db.yml up -d --build
goto end
:docker_down
docker compose down
goto end
:docker_down_db
docker compose -f docker-compose.yml -f docker-compose.with-db.yml down
goto end
:docker_logs
docker compose logs -f app
goto end
:migrate
uv run alembic -c migrations/alembic.ini upgrade head
goto end
:migration
set "MESSAGE=%~1"
if "%MESSAGE%"=="" (
echo 缺少 migration 说明。示例app.cmd migration "alice add order table" 1>&2
exit /b 2
)
uv run alembic -c migrations/alembic.ini revision --autogenerate -m "%MESSAGE%"
goto end
:heads
uv run alembic -c migrations/alembic.ini heads
goto end
:current
uv run alembic -c migrations/alembic.ini current
goto end
{% if include_system %}:system_sync
uv run iti-system migrations sync --target migrations/versions
goto end
:system_seed
set "PYTHONPATH=."
uv run iti-system seed system app:create_app
goto end
:init_system
uv run iti-system migrations sync --target migrations/versions
if errorlevel 1 goto end
uv run alembic -c migrations/alembic.ini upgrade head
if errorlevel 1 goto end
set "PYTHONPATH=."
uv run iti-system seed system app:create_app
goto end
{% endif %}:init
uv sync --extra dev
if errorlevel 1 goto end
{% if include_system %}uv run iti-system migrations sync --target migrations/versions
if errorlevel 1 goto end
{% endif %}uv run alembic -c migrations/alembic.ini upgrade head
if errorlevel 1 goto end
{% if include_system %}set "PYTHONPATH=."
uv run iti-system seed system app:create_app
{% endif %}goto end
:end
set "EXIT_CODE=%ERRORLEVEL%"
popd >nul
exit /b %EXIT_CODE%

@ -1,162 +0,0 @@
#!/usr/bin/env sh
set -eu
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
cd "$ROOT_DIR"
export UV_NO_SOURCES_PACKAGE=iti-flask
PROJECT_VENV="$ROOT_DIR/.venv"
case "${VIRTUAL_ENV:-}" in
""|"$PROJECT_VENV"|"$PROJECT_VENV/")
;;
*)
unset VIRTUAL_ENV
;;
esac
show_help() {
cat <<'EOF'
{{ project_name }} 项目脚本
用法:
./app.sh <命令> [参数]
常用命令:
help 显示帮助
install 安装开发依赖uv sync --extra dev
framework-sync 同步 iTi-Flask{% if include_system %} / iTi-System{% endif %} 依赖
template-check 检查 Copier 模板是否有更新
template-update 按 Copier 模板更新项目骨架
test 运行测试uv run --extra dev pytest -q
serve [环境] [端口] 本地启动,默认 dev / 8000
docker-build 构建 Docker 镜像
docker-up 启动 Docker Compose 应用
docker-up-db 启动 Docker Compose 应用和 MySQL
docker-down 停止 Docker Compose 应用
docker-down-db 停止 Docker Compose 应用和 MySQL
docker-logs 查看应用容器日志
migrate 执行 Alembic upgrade head
migration <说明> 生成 migration说明建议以作者名开头
heads 查看 Alembic heads
current 查看当前 Alembic 版本
{% if include_system %} system-sync 同步 iti-system migration 到当前项目
system-seed 初始化 / 更新系统 seed
init-system system-sync + migrate + system-seed
{% endif %} init install + migrate{% if include_system %} + system-seed{% endif %}
示例:
./app.sh install
./app.sh serve
./app.sh docker-up
./app.sh serve test 8000
APP_ENV=prod ./app.sh migrate
./app.sh migration "alice add order table"
{% if include_system %} ./app.sh init-system
{% endif %}
EOF
}
command=${1:-help}
shift || true
case "$command" in
help|-h|--help)
show_help
;;
install)
uv sync --extra dev
;;
framework-sync)
uv sync --extra dev --upgrade-package iti-flask{% if include_system %} --upgrade-package iti-system{% endif %}
;;
template-check)
exec uvx copier update --defaults --pretend --vcs-ref HEAD "$ROOT_DIR"
;;
template-update)
exec uvx copier update --defaults --vcs-ref HEAD "$ROOT_DIR"
;;
test)
uv run --extra dev pytest -q
;;
serve)
env_name=${APP_ENV:-dev}
port=8000
if [ $# -gt 0 ]; then
case "$1" in
dev|test|prod|default)
env_name=$1
port=${2:-8000}
;;
''|*[!0-9]*)
env_name=$1
port=${2:-8000}
;;
*)
port=$1
;;
esac
fi
if [ "$env_name" = default ]; then
env_name=dev
fi
APP_ENV="$env_name" uv run uvicorn main:app --reload --port "$port"
;;
docker-build)
docker compose build
;;
docker-up)
docker compose up -d --build
;;
docker-up-db)
docker compose -f docker-compose.yml -f docker-compose.with-db.yml up -d --build
;;
docker-down)
docker compose down
;;
docker-down-db)
docker compose -f docker-compose.yml -f docker-compose.with-db.yml down
;;
docker-logs)
docker compose logs -f app
;;
migrate)
uv run alembic -c migrations/alembic.ini upgrade head
;;
migration)
message=${1:-}
if [ -z "$message" ]; then
echo "缺少 migration 说明。示例:./app.sh migration \"alice add order table\"" >&2
exit 2
fi
uv run alembic -c migrations/alembic.ini revision --autogenerate -m "$message"
;;
heads)
uv run alembic -c migrations/alembic.ini heads
;;
current)
uv run alembic -c migrations/alembic.ini current
;;
{% if include_system %} system-sync)
uv run iti-system migrations sync --target migrations/versions
;;
system-seed)
PYTHONPATH=. uv run iti-system seed system app:create_app
;;
init-system)
uv run iti-system migrations sync --target migrations/versions
uv run alembic -c migrations/alembic.ini upgrade head
PYTHONPATH=. uv run iti-system seed system app:create_app
;;
{% endif %} init)
uv sync --extra dev
{% if include_system %} uv run iti-system migrations sync --target migrations/versions
{% endif %} uv run alembic -c migrations/alembic.ini upgrade head
{% if include_system %} PYTHONPATH=. uv run iti-system seed system app:create_app
{% endif %} ;;
*)
echo "未知命令:$command" >&2
echo >&2
show_help >&2
exit 2
;;
esac

@ -23,20 +23,20 @@ copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-pro
## 生成
```bash
./iti.sh make-app ../my-business-app my-business-app
iticli create ../my-business-app
cd ../my-business-app
cp .env.example .env
./app.sh init
./app.sh serve 8000
iticli init
iticli run dev 8000
```
Windows
```bat
iti.cmd make-app ..\my-business-app my-business-app
iticli create ..\my-business-app
cd ..\my-business-app
app.cmd init
app.cmd serve 8000
iticli init
iticli run dev 8000
```
## 参数
@ -70,8 +70,6 @@ app.cmd serve 8000
- 示例 FastAPI 模块
- 示例 SQLAlchemy 模型
- 示例测试
- `app.sh`
- `app.cmd`
## 系统业务
@ -79,46 +77,40 @@ app.cmd serve 8000
生成后执行:
```bash
./app.sh init-system
iticli init system
```
Windows
```bat
app.cmd init-system
iticli init system
```
## 生成项目脚本
模板会生成两份脚本:
- `app.sh`Linux / macOS / Git Bash。
- `app.cmd`Windows CMD。
## 命令
常用命令:
```bash
./app.sh help
./app.sh install
./app.sh test
./app.sh serve 8000
./app.sh docker-up
./app.sh docker-up-db
./app.sh docker-logs
./app.sh docker-down
./app.sh docker-down-db
./app.sh migration "alice add order table"
./app.sh migrate
iticli help
iticli install
iticli test
iticli run dev 8000
iticli docker up
iticli docker up --db
iticli docker logs
iticli docker down
iticli docker down --db
iticli migrate revision "alice add order table"
iticli migrate
```
`app.sh` / `app.cmd` 内部使用项目自己的 `migrations/alembic.ini`
`iticli migrate` 在业务项目内使用项目自己的 `migrations/alembic.ini`
`iti-system` 的项目还会有:
```bash
./app.sh system-sync
./app.sh system-seed
./app.sh init-system
iticli sync system
iticli init system
```
## 同步更新
@ -126,16 +118,16 @@ app.cmd init-system
业务项目同步框架依赖:
```bash
./app.sh framework-sync
iticli sync flask
```
该命令执行 `uv sync --upgrade-package iti-flask`
`iti-system` 的模板项目会同时升级 `iti-system`。
需要同时升级框架和系统包时使用 `iticli sync all`。
业务项目检查模板版本:
```bash
./app.sh template-check
iticli template check
```
该命令执行 `uvx copier update --defaults --pretend --vcs-ref HEAD`
@ -143,7 +135,7 @@ app.cmd init-system
业务项目按模板更新项目骨架:
```bash
./app.sh template-update
iticli template update
```
该命令执行 `uvx copier update --defaults --vcs-ref HEAD`
@ -151,7 +143,7 @@ app.cmd init-system
模板更新前,业务项目工作区必须干净。
执行后检查 diff再运行测试。
模板拥有的文件包括 `main.py`、`app/app_factory.py`、`config.py`、`Dockerfile`、`docker-compose.yml`、`docker-compose.with-db.yml`、`.dockerignore`、`.env.example`、`.vscode/launch.json`、`app.sh`、`app.cmd`、`pyproject.toml`、`migrations/`、示例模块、示例测试、README 和项目 skill。
模板拥有的文件包括 `main.py`、`app/app_factory.py`、`config.py`、`Dockerfile`、`docker-compose.yml`、`docker-compose.with-db.yml`、`.dockerignore`、`.env.example`、`.vscode/launch.json`、`pyproject.toml`、`migrations/`、示例模块、示例测试、README 和项目 skill。
业务项目自己的模块、模型、API 文档和业务 README 由业务项目维护。
## Docker

@ -16,10 +16,9 @@ AI 修改框架时优先读 `.codex/skills/iti-flask-framework/SKILL.md`。
## 命令
```bash
./iti.sh install
./iti.sh test
./iti.sh check
./iti.sh make-app ../my-business-app my-business-app
./iti.sh make-system-app ../my-system-app my-system-app
./iti.sh release
iticli install
iticli test
iticli create ../my-business-app
iticli create --with-system ../my-system-app
iticli release
```

@ -52,16 +52,16 @@ curl http://127.0.0.1:8000/ready
```bash
cp .env.example .env
./app.sh docker-up
./app.sh docker-logs
./app.sh docker-down
iticli docker up
iticli docker logs
iticli docker down
```
如需本地 MySQL
```bash
./app.sh docker-up-db
./app.sh docker-down-db
iticli docker up --db
iticli docker down --db
```
服务容器使用:

@ -1,6 +0,0 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
call "%SCRIPT_DIR%scripts\iti.cmd" %*
exit /b %ERRORLEVEL%

@ -1,5 +0,0 @@
#!/usr/bin/env sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
exec sh "$SCRIPT_DIR/scripts/iti.sh" "$@"

@ -1,155 +0,0 @@
@echo off
setlocal enabledelayedexpansion
set "SCRIPT_DIR=%~dp0"
set "ROOT_DIR=%SCRIPT_DIR%.."
pushd "%ROOT_DIR%" >nul
set "ROOT_DIR=%CD%"
set "PROJECT_VENV=%ROOT_DIR%\.venv"
if defined VIRTUAL_ENV (
if /I not "%VIRTUAL_ENV%"=="%PROJECT_VENV%" (
if /I not "%VIRTUAL_ENV%"=="%PROJECT_VENV%\" set "VIRTUAL_ENV="
)
)
set "COMMAND=%~1"
if "%COMMAND%"=="" set "COMMAND=help"
shift /1
if "%COMMAND%"=="help" goto help
if "%COMMAND%"=="-h" goto help
if "%COMMAND%"=="--help" goto help
if "%COMMAND%"=="install" goto install
if "%COMMAND%"=="test" goto test
if "%COMMAND%"=="check" goto check
if "%COMMAND%"=="serve" goto serve
if "%COMMAND%"=="migrate" goto migrate
if "%COMMAND%"=="migration" goto migration
if "%COMMAND%"=="heads" goto heads
if "%COMMAND%"=="current" goto current
if "%COMMAND%"=="release" goto release
if "%COMMAND%"=="make-app" goto make_app
if "%COMMAND%"=="make-system-app" goto make_system_app
echo 未知命令:%COMMAND% 1>&2
echo. 1>&2
goto help_error
:help
echo iTi-Flask 开发脚本
echo.
echo 用法:
echo iti.cmd ^<命令^> [参数]
echo.
echo 常用命令:
echo help 显示帮助
echo install 安装开发依赖uv sync --extra dev
echo test 运行测试uv run pytest -q
echo check 运行测试和 mypy
echo serve [端口] 启动框架示例应用,默认 8000
echo migrate 执行当前仓库 Alembic upgrade head
echo migration ^<说明^> 生成 migration说明建议以作者名开头
echo heads 查看 Alembic heads
echo current 查看当前 Alembic 版本
echo make-app ^<目录^> [发行名] 从当前框架仓库模板生成业务项目
echo make-system-app ^<目录^> [发行名] 生成带 iti-system 的业务项目
echo release [版本] 发布框架:测试、改版本、提交、打 tag、推送
echo.
echo 示例:
echo iti.cmd install
echo iti.cmd test
echo iti.cmd serve 8000
echo iti.cmd make-app ..\hsyh-erp-phase2 hsyh-erp-phase2
echo iti.cmd make-system-app ..\hsyh-mes-phase2 hsyh-mes-phase2
popd >nul
exit /b 0
:help_error
call :help
exit /b 2
:install
uv sync --extra dev
goto end
:test
uv run pytest -q
goto end
:check
uv run pytest -q
if errorlevel 1 goto end
uv run mypy
goto end
:serve
set "PORT=%~1"
if "%PORT%"=="" set "PORT=8000"
uv run uvicorn iti.app:create_app --factory --reload --port "%PORT%"
goto end
:migrate
uv run alembic upgrade head
goto end
:migration
set "MESSAGE=%~1"
if "%MESSAGE%"=="" (
echo 缺少 migration 说明。示例iti.cmd migration "alice add order table" 1>&2
exit /b 2
)
uv run alembic revision --autogenerate -m "%MESSAGE%"
goto end
:heads
uv run alembic heads
goto end
:current
uv run alembic current
goto end
:release
set "SHELL_CMD="
where sh >nul 2>nul && set "SHELL_CMD=sh"
if not defined SHELL_CMD (
where bash >nul 2>nul && set "SHELL_CMD=bash"
)
if not defined SHELL_CMD (
echo 找不到 sh 或 bash无法运行 release 脚本 1>&2
exit /b 1
)
if "%~1"=="" (
"%SHELL_CMD%" scripts/release.sh
) else (
"%SHELL_CMD%" scripts/release.sh %*
)
goto end
:make_app
set "INCLUDE_SYSTEM=false"
goto make_project
:make_system_app
set "INCLUDE_SYSTEM=true"
goto make_project
:make_project
set "TARGET=%~1"
set "DIST_NAME=%~2"
if "%TARGET%"=="" (
echo 缺少目标目录。示例iti.cmd make-app ..\my-app my-app 1>&2
exit /b 2
)
if "%DIST_NAME%"=="" (
for %%I in ("%TARGET%") do set "DIST_NAME=%%~nxI"
)
for %%I in ("%TARGET%") do set "PROJECT_NAME=%%~nxI"
uvx copier copy --defaults --vcs-ref HEAD "%CD%" "%TARGET%" -d project_name="!PROJECT_NAME!" -d project_slug="!DIST_NAME!" -d include_system="%INCLUDE_SYSTEM%"
goto end
:end
set "EXIT_CODE=%ERRORLEVEL%"
popd >nul
exit /b %EXIT_CODE%

@ -1,116 +0,0 @@
#!/usr/bin/env sh
set -eu
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$ROOT_DIR"
PROJECT_VENV="$ROOT_DIR/.venv"
case "${VIRTUAL_ENV:-}" in
""|"$PROJECT_VENV"|"$PROJECT_VENV/")
;;
*)
unset VIRTUAL_ENV
;;
esac
show_help() {
cat <<'EOF'
iTi-Flask 开发脚本
用法:
./iti.sh <命令> [参数]
常用命令:
help 显示帮助
install 安装开发依赖uv sync --extra dev
test 运行测试uv run pytest -q
check 运行测试和 mypy
serve [端口] 启动框架示例应用,默认 8000
migrate 执行当前仓库 Alembic upgrade head
migration <说明> 生成 migration说明建议以作者名开头
heads 查看 Alembic heads
current 查看当前 Alembic 版本
make-app <目录> [发行名] 从当前框架仓库模板生成业务项目
make-system-app <目录> [发行名] 生成带 iti-system 的业务项目
release [版本] 发布框架:测试、改版本、提交、打 tag、推送
示例:
./iti.sh install
./iti.sh test
./iti.sh serve 8000
./iti.sh make-app ../hsyh-erp-phase2 hsyh-erp-phase2
./iti.sh make-system-app ../hsyh-mes-phase2 hsyh-mes-phase2
说明:
- 默认生成项目使用 copier-template 里的 Git 依赖配置。
- 临时本地验证可在生成时按 copier 交互改成 file://。
EOF
}
command=${1:-help}
shift || true
case "$command" in
help|-h|--help)
show_help
;;
install)
uv sync --extra dev
;;
test)
uv run pytest -q
;;
check)
uv run pytest -q
uv run mypy
;;
serve)
port=${1:-8000}
uv run uvicorn iti.app:create_app --factory --reload --port "$port"
;;
migrate)
uv run alembic upgrade head
;;
migration)
message=${1:-}
if [ -z "$message" ]; then
echo "缺少 migration 说明。示例:./iti.sh migration \"alice add order table\"" >&2
exit 2
fi
uv run alembic revision --autogenerate -m "$message"
;;
heads)
uv run alembic heads
;;
current)
uv run alembic current
;;
release)
sh scripts/release.sh "$@"
;;
make-app|make-system-app)
target=${1:-}
dist_name=${2:-}
if [ -z "$target" ]; then
echo "缺少目标目录。示例:./iti.sh make-app ../my-app my-app" >&2
exit 2
fi
if [ -z "$dist_name" ]; then
dist_name=$(basename "$target")
fi
include_system=false
if [ "$command" = "make-system-app" ]; then
include_system=true
fi
uvx copier copy --defaults --vcs-ref HEAD "$ROOT_DIR" "$target" \
-d project_name="$(basename "$target")" \
-d project_slug="$dist_name" \
-d include_system="$include_system"
;;
*)
echo "未知命令:$command" >&2
echo >&2
show_help >&2
exit 2
;;
esac

@ -1,226 +0,0 @@
#!/usr/bin/env sh
set -eu
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
cd "$ROOT_DIR"
ABOUT_FILE="$ROOT_DIR/iti/__about__.py"
COPIER_FILE="$ROOT_DIR/copier.yml"
COPIER_TEMPLATE_FILE="$ROOT_DIR/copier-template/pyproject.toml.jinja"
README_FILE="$ROOT_DIR/README.md"
die() {
printf '%s\n' "$*" >&2
exit 1
}
parse_version() {
raw=$1
version=${raw#v}
old_ifs=$IFS
IFS=.
set -- $version
IFS=$old_ifs
if [ "$#" -ne 3 ]; then
die "invalid version: $raw"
fi
for part in "$@"; do
case $part in
''|*[!0-9]*)
die "invalid version: $raw"
;;
esac
done
printf '%s %s %s\n' "$1" "$2" "$3"
}
normalize_version() {
set -- $(parse_version "$1")
printf '%s.%s.%s\n' "$1" "$2" "$3"
}
bump_patch() {
set -- $(parse_version "$1")
printf '%s.%s.%s\n' "$1" "$2" "$(( $3 + 1 ))"
}
version_is_newer() {
current_version=$1
target_version=$2
current_parts=$(parse_version "$current_version")
set -- $current_parts
current_major=$1
current_minor=$2
current_patch=$3
target_parts=$(parse_version "$target_version")
set -- $target_parts
target_major=$1
target_minor=$2
target_patch=$3
if [ "$target_major" -gt "$current_major" ]; then
return 0
fi
if [ "$target_major" -lt "$current_major" ]; then
return 1
fi
if [ "$target_minor" -gt "$current_minor" ]; then
return 0
fi
if [ "$target_minor" -lt "$current_minor" ]; then
return 1
fi
[ "$target_patch" -gt "$current_patch" ]
}
read_current_version() {
current_version=$(sed -n 's/^__version__[[:space:]]*=[[:space:]]*"\([^"]*\)".*$/\1/p' "$ABOUT_FILE" | sed -n '1p')
[ -n "$current_version" ] || die "version not found in $ABOUT_FILE"
printf '%s\n' "$current_version"
}
replace_first_line_with_prefix() {
file=$1
prefix=$2
new_line=$3
tmp_file=$(mktemp)
if awk -v prefix="$prefix" -v new="$new_line" '
BEGIN { done = 0 }
index($0, prefix) == 1 && !done {
print new
done = 1
next
}
{ print }
END { if (!done) exit 1 }
' "$file" >"$tmp_file"; then
mv "$tmp_file" "$file"
else
rm -f "$tmp_file"
die "line not updated in $file"
fi
}
replace_first_line_in_section_with_prefix() {
file=$1
section_header=$2
prefix=$3
new_line=$4
tmp_file=$(mktemp)
if awk -v section="$section_header" -v prefix="$prefix" -v new="$new_line" '
BEGIN { in_section = 0; done = 0 }
$0 == section { in_section = 1; print; next }
in_section && /^[^[:space:]]/ { in_section = 0 }
in_section && !done && index($0, prefix) == 1 {
print new
done = 1
next
}
{ print }
END { if (!done) exit 1 }
' "$file" >"$tmp_file"; then
mv "$tmp_file" "$file"
else
rm -f "$tmp_file"
die "line not updated in $file"
fi
}
write_about_version() {
target_version=$1
replace_first_line_with_prefix "$ABOUT_FILE" "__version__ = " "__version__ = \"$target_version\""
}
write_copier_framework_tag() {
target_version=$1
replace_first_line_in_section_with_prefix "$COPIER_FILE" "framework_tag:" " default: v" " default: v$target_version"
}
write_copier_system_tag() {
target_version=$1
replace_first_line_in_section_with_prefix "$COPIER_FILE" "system_tag:" " default: v" " default: v$target_version"
}
write_copier_template_version() {
target_version=$1
replace_first_line_with_prefix "$COPIER_TEMPLATE_FILE" "version = " "version = \"$target_version\""
}
write_readme_dependency_tag() {
target_version=$1
replace_first_line_with_prefix "$README_FILE" ' "iti-flask @ git+https://git.noahlan.cn/iti-framework/iTi-Flask.git@v' ' "iti-flask @ git+https://git.noahlan.cn/iti-framework/iTi-Flask.git@v'"$target_version"'",'
}
write_readme_release_examples() {
target_version=$1
replace_first_line_with_prefix "$README_FILE" './iti.sh release v' "./iti.sh release v$target_version"
replace_first_line_with_prefix "$README_FILE" 'iti.cmd release v' "iti.cmd release v$target_version"
}
ensure_clean_tree() {
if [ -n "$(git status --porcelain)" ]; then
die "working tree is not clean"
fi
}
ensure_branch() {
if branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null); then
[ -n "$branch" ] || die "release requires a branch checkout"
printf '%s\n' "$branch"
else
die "release requires a branch checkout"
fi
}
ensure_tag_absent() {
tag=$1
if git rev-parse --verify --quiet "refs/tags/$tag" >/dev/null; then
die "tag already exists: $tag"
fi
}
main() {
version_arg=${1:-}
current_version=$(read_current_version)
if [ -n "$version_arg" ]; then
target_version=$(normalize_version "$version_arg")
else
target_version=$(bump_patch "$current_version")
fi
target_tag="v$target_version"
if [ "$target_version" = "$current_version" ]; then
die "version already set to $target_version"
fi
if ! version_is_newer "$current_version" "$target_version"; then
die "target version must be newer than $current_version"
fi
ensure_clean_tree
branch=$(ensure_branch)
ensure_tag_absent "$target_tag"
uv run pytest -q
write_about_version "$target_version"
write_copier_framework_tag "$target_version"
write_copier_system_tag "$target_version"
write_copier_template_version "$target_version"
write_readme_dependency_tag "$target_version"
write_readme_release_examples "$target_version"
git add iti/__about__.py copier.yml copier-template/pyproject.toml.jinja README.md
git commit -m "chore: release $target_tag"
git tag -a "$target_tag" -m "release $target_tag"
git push origin "$branch" "$target_tag"
printf 'released %s\n' "$target_tag"
}
main "$@"
Loading…
Cancel
Save