diff --git a/.codex/skills/iti-flask-framework/SKILL.md b/.codex/skills/iti-flask-framework/SKILL.md index cf34494..eeacb1c 100644 --- a/.codex/skills/iti-flask-framework/SKILL.md +++ b/.codex/skills/iti-flask-framework/SKILL.md @@ -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`。 ## 文档 diff --git a/README.md b/README.md index 3458c89..7479afb 100644 --- a/README.md +++ b/README.md @@ -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 ``` ## 文档 diff --git a/copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-project/SKILL.md.jinja b/copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-project/SKILL.md.jinja index bb644a1..154b5fe 100644 --- a/copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-project/SKILL.md.jinja +++ b/copier-template/.codex/skills/{{ project_slug | lower | replace('_', '-') }}-project/SKILL.md.jinja @@ -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 "" -}} \ No newline at end of file diff --git a/copier-template/README.md.jinja b/copier-template/README.md.jinja index 6727bf3..07de981 100644 --- a/copier-template/README.md.jinja +++ b/copier-template/README.md.jinja @@ -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 ``` 规则: diff --git a/copier-template/app.cmd.jinja b/copier-template/app.cmd.jinja deleted file mode 100644 index 05bf3de..0000000 --- a/copier-template/app.cmd.jinja +++ /dev/null @@ -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% diff --git a/copier-template/app.sh.jinja b/copier-template/app.sh.jinja deleted file mode 100644 index 033c38c..0000000 --- a/copier-template/app.sh.jinja +++ /dev/null @@ -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 diff --git a/docs/COPIER_TEMPLATE.md b/docs/COPIER_TEMPLATE.md index d992127..7b91bee 100644 --- a/docs/COPIER_TEMPLATE.md +++ b/docs/COPIER_TEMPLATE.md @@ -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 diff --git a/docs/README.md b/docs/README.md index 42bdd5e..9d3cdf5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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 ``` diff --git a/docs/TESTING_DEPLOYMENT.md b/docs/TESTING_DEPLOYMENT.md index 9105c6b..e07967d 100644 --- a/docs/TESTING_DEPLOYMENT.md +++ b/docs/TESTING_DEPLOYMENT.md @@ -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 ``` 服务容器使用: diff --git a/iti.cmd b/iti.cmd deleted file mode 100644 index 6d40736..0000000 --- a/iti.cmd +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -setlocal - -set "SCRIPT_DIR=%~dp0" -call "%SCRIPT_DIR%scripts\iti.cmd" %* -exit /b %ERRORLEVEL% diff --git a/iti.sh b/iti.sh deleted file mode 100644 index ab14b12..0000000 --- a/iti.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env sh -set -eu - -SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) -exec sh "$SCRIPT_DIR/scripts/iti.sh" "$@" diff --git a/scripts/iti.cmd b/scripts/iti.cmd deleted file mode 100644 index e109cde..0000000 --- a/scripts/iti.cmd +++ /dev/null @@ -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% diff --git a/scripts/iti.sh b/scripts/iti.sh deleted file mode 100644 index fbf9a29..0000000 --- a/scripts/iti.sh +++ /dev/null @@ -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 diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100644 index fcc9be8..0000000 --- a/scripts/release.sh +++ /dev/null @@ -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 "$@"