@wneng/create-keel 0.3.6 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/index.js +206 -13
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/templates/ci-gitee/files/PULL_REQUEST_TEMPLATE.md +15 -2
  5. package/src/templates/ci-gitee/files/pipeline.yml +62 -0
  6. package/src/templates/ci-github/files/PULL_REQUEST_TEMPLATE.md +15 -2
  7. package/src/templates/ci-github/files/ci.yml +160 -0
  8. package/src/templates/db-go-elasticsearch/files/Makefile +18 -0
  9. package/src/templates/db-go-elasticsearch/files/apply_templates.go +80 -0
  10. package/src/templates/db-go-elasticsearch/files/db-README.md +57 -0
  11. package/src/templates/db-go-elasticsearch/files/go.mod +7 -0
  12. package/src/templates/db-go-elasticsearch/files/index-template-init.json +25 -0
  13. package/src/templates/db-go-elasticsearch/fragment.yaml +22 -0
  14. package/src/templates/db-go-migrate-mysql/files/000001_init.down.sql +3 -0
  15. package/src/templates/db-go-migrate-mysql/files/000001_init.up.sql +35 -0
  16. package/src/templates/db-go-migrate-mysql/files/Makefile +33 -0
  17. package/src/templates/db-go-migrate-mysql/files/db-README.md +77 -0
  18. package/src/templates/db-go-migrate-mysql/files/go.mod +8 -0
  19. package/src/templates/db-go-migrate-mysql/fragment.yaml +22 -0
  20. package/src/templates/db-go-migrate-postgres/files/000001_init.down.sql +3 -0
  21. package/src/templates/db-go-migrate-postgres/files/000001_init.up.sql +32 -0
  22. package/src/templates/db-go-migrate-postgres/files/Makefile +31 -0
  23. package/src/templates/db-go-migrate-postgres/files/db-README.md +71 -0
  24. package/src/templates/db-go-migrate-postgres/files/go.mod +8 -0
  25. package/src/templates/db-go-migrate-postgres/fragment.yaml +22 -0
  26. package/src/templates/db-java-elasticsearch/files/EsTemplateApplier.java +86 -0
  27. package/src/templates/db-java-elasticsearch/files/db-README.md +63 -0
  28. package/src/templates/db-java-elasticsearch/files/index-template-init.json +25 -0
  29. package/src/templates/db-java-elasticsearch/files/pom.xml +134 -0
  30. package/src/templates/db-java-elasticsearch/fragment.yaml +19 -0
  31. package/src/templates/db-java-flyway-mysql/files/V1__init.sql +44 -0
  32. package/src/templates/db-java-flyway-mysql/files/application.yaml +39 -0
  33. package/src/templates/db-java-flyway-mysql/files/db-README.md +102 -0
  34. package/src/templates/db-java-flyway-mysql/files/pom.xml +172 -0
  35. package/src/templates/db-java-flyway-mysql/fragment.yaml +19 -0
  36. package/src/templates/db-java-flyway-postgres/files/V1__init.sql +40 -0
  37. package/src/templates/db-java-flyway-postgres/files/application.yaml +37 -0
  38. package/src/templates/db-java-flyway-postgres/files/db-README.md +75 -0
  39. package/src/templates/db-java-flyway-postgres/files/pom.xml +166 -0
  40. package/src/templates/db-java-flyway-postgres/fragment.yaml +19 -0
  41. package/src/templates/db-node-elasticsearch/files/apply-templates.cjs +60 -0
  42. package/src/templates/db-node-elasticsearch/files/db-README.md +76 -0
  43. package/src/templates/db-node-elasticsearch/files/index-template-init.json +26 -0
  44. package/src/templates/db-node-elasticsearch/files/package.json +26 -0
  45. package/src/templates/db-node-elasticsearch/fragment.yaml +19 -0
  46. package/src/templates/db-node-knex-mysql/files/db-README.md +90 -0
  47. package/src/templates/db-node-knex-mysql/files/knexfile.cjs +72 -0
  48. package/src/templates/db-node-knex-mysql/files/migrations-init.cjs +42 -0
  49. package/src/templates/db-node-knex-mysql/files/package.json +31 -0
  50. package/src/templates/db-node-knex-mysql/files/seeds-dev-fixtures.cjs +38 -0
  51. package/src/templates/db-node-knex-mysql/files/seeds-prod-dictionaries.cjs +25 -0
  52. package/src/templates/db-node-knex-mysql/fragment.yaml +25 -0
  53. package/src/templates/db-node-knex-postgres/files/db-README.md +81 -0
  54. package/src/templates/db-node-knex-postgres/files/knexfile.cjs +67 -0
  55. package/src/templates/db-node-knex-postgres/files/migrations-init.cjs +42 -0
  56. package/src/templates/db-node-knex-postgres/files/package.json +31 -0
  57. package/src/templates/db-node-knex-postgres/files/seeds-dev-fixtures.cjs +36 -0
  58. package/src/templates/db-node-knex-postgres/files/seeds-prod-dictionaries.cjs +26 -0
  59. package/src/templates/db-node-knex-postgres/fragment.yaml +25 -0
  60. package/src/templates/db-python-alembic-mysql/files/0001_init.py +70 -0
  61. package/src/templates/db-python-alembic-mysql/files/alembic.ini +47 -0
  62. package/src/templates/db-python-alembic-mysql/files/db-README.md +87 -0
  63. package/src/templates/db-python-alembic-mysql/files/env.py +71 -0
  64. package/src/templates/db-python-alembic-mysql/files/pyproject.toml +52 -0
  65. package/src/templates/db-python-alembic-mysql/files/script.py.mako +26 -0
  66. package/src/templates/db-python-alembic-mysql/fragment.yaml +25 -0
  67. package/src/templates/db-python-alembic-postgres/files/0001_init.py +62 -0
  68. package/src/templates/db-python-alembic-postgres/files/alembic.ini +45 -0
  69. package/src/templates/db-python-alembic-postgres/files/db-README.md +70 -0
  70. package/src/templates/db-python-alembic-postgres/files/env.py +62 -0
  71. package/src/templates/db-python-alembic-postgres/files/pyproject.toml +52 -0
  72. package/src/templates/db-python-alembic-postgres/files/script.py.mako +25 -0
  73. package/src/templates/db-python-alembic-postgres/fragment.yaml +25 -0
  74. package/src/templates/db-python-elasticsearch/files/apply_templates.py +55 -0
  75. package/src/templates/db-python-elasticsearch/files/db-README.md +57 -0
  76. package/src/templates/db-python-elasticsearch/files/index-template-init.json +25 -0
  77. package/src/templates/db-python-elasticsearch/files/pyproject.toml +50 -0
  78. package/src/templates/db-python-elasticsearch/fragment.yaml +19 -0
  79. package/src/templates/docs-skeleton/files/governance-change-tiers.md +135 -76
  80. package/src/templates/docs-skeleton/files/governance-database.md +150 -0
  81. package/src/templates/docs-skeleton/fragment.yaml +3 -0
  82. package/src/templates/root-files/files/AGENTS.md +35 -17
  83. package/src/templates/server-python/files/README.md +75 -2
  84. package/src/templates/server-python/files/app-init.py +11 -1
  85. package/src/templates/server-python/files/config.py +40 -0
  86. package/src/templates/server-python/files/main.py +62 -0
  87. package/src/templates/server-python/files/pyproject.toml +14 -1
  88. package/src/templates/server-python/files/test_healthz.py +36 -0
  89. package/src/templates/server-python/fragment.yaml +10 -1
@@ -0,0 +1,40 @@
1
+ """Application configuration via pydantic-settings.
2
+
3
+ 环境变量映射规则:
4
+ - 全部大写、`_` 分隔
5
+ - 嵌套字段用 `__` 分隔(pydantic-settings 默认)
6
+ - 例:APP_NAME / APP_VERSION / CORS_ALLOW_ORIGINS=http://localhost:5173,http://localhost:3000
7
+
8
+ `.env` 文件由 pydantic-settings 自动加载(项目根目录)。
9
+ """
10
+
11
+ from pydantic import Field
12
+ from pydantic_settings import BaseSettings, SettingsConfigDict
13
+
14
+
15
+ class Settings(BaseSettings):
16
+ """Runtime settings.
17
+
18
+ 新增字段必须:
19
+ - 给默认值(不要让生产环境因缺一个变量启动崩溃)
20
+ - 同步更新根 `.env.example`(如启用 contracts-base fragment)
21
+ - 敏感字段(密钥、token)只能从环境变量读,绝不写默认值
22
+ """
23
+
24
+ model_config = SettingsConfigDict(
25
+ env_file=".env",
26
+ env_file_encoding="utf-8",
27
+ case_sensitive=False,
28
+ extra="ignore",
29
+ )
30
+
31
+ app_name: str = Field(default="<%= it.options.projectName %>-server")
32
+ app_version: str = Field(default="0.1.0")
33
+
34
+ # CORS:逗号分隔字符串解析为列表
35
+ cors_allow_origins: list[str] = Field(
36
+ default_factory=lambda: ["http://localhost:5173", "http://localhost:3000"]
37
+ )
38
+
39
+
40
+ settings = Settings()
@@ -0,0 +1,62 @@
1
+ """<%= it.options.projectName %>-server entry point.
2
+
3
+ Contract First:路由 / 请求体 / 响应体应当与 contracts/openapi/api.yaml 对齐。
4
+ 新增端点的工作流见根 AGENTS.md §6(变更分级)+ docs/governance/change-tiers.md:
5
+ 端点新增 / 字段新增是 Tier 3,必须先冻结 contracts/openapi/api.yaml 再写实现。
6
+ """
7
+
8
+ from collections.abc import AsyncIterator
9
+ from contextlib import asynccontextmanager
10
+
11
+ from fastapi import FastAPI
12
+ from fastapi.middleware.cors import CORSMiddleware
13
+
14
+ from .config import settings
15
+
16
+
17
+ @asynccontextmanager
18
+ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
19
+ """启动 / 关闭钩子。
20
+
21
+ 在这里做:
22
+ - 数据库连接池初始化(如启用 db)
23
+ - Elasticsearch 客户端初始化(如启用 db=elasticsearch)
24
+ - 后台任务启动
25
+ 关闭时反向清理。
26
+ """
27
+ yield
28
+
29
+
30
+ app = FastAPI(
31
+ title=settings.app_name,
32
+ version=settings.app_version,
33
+ description="Generated by @wneng/create-keel; implement per contracts/openapi/api.yaml.",
34
+ lifespan=lifespan,
35
+ )
36
+
37
+ # CORS — 默认放开本地前端开发常用端口;生产请通过环境变量收紧 allow_origins
38
+ app.add_middleware(
39
+ CORSMiddleware,
40
+ allow_origins=settings.cors_allow_origins,
41
+ allow_credentials=True,
42
+ allow_methods=["*"],
43
+ allow_headers=["*"],
44
+ )
45
+
46
+
47
+ @app.get("/healthz", tags=["meta"])
48
+ async def healthz() -> dict[str, str]:
49
+ """Liveness 探针。
50
+
51
+ 部署时由 Kubernetes / Docker Compose 周期性调用;返回非 200 即视为不健康。
52
+ """
53
+ return {"status": "ok"}
54
+
55
+
56
+ @app.get("/", tags=["meta"])
57
+ async def root() -> dict[str, str]:
58
+ return {
59
+ "name": settings.app_name,
60
+ "version": settings.app_version,
61
+ "docs": "/docs",
62
+ }
@@ -2,13 +2,20 @@
2
2
  name = "<%= it.options.projectName %>-server"
3
3
  version = "0.1.0"
4
4
  requires-python = ">=3.11"
5
- dependencies = []
5
+ dependencies = [
6
+ "fastapi==0.115.5",
7
+ "uvicorn[standard]==0.32.0",
8
+ "pydantic==2.9.2",
9
+ "pydantic-settings==2.6.1",
10
+ ]
6
11
 
7
12
  [project.optional-dependencies]
8
13
  dev = [
9
14
  "ruff>=0.6.8",
10
15
  "mypy>=1.11.0",
11
16
  "pytest>=8.3.0",
17
+ "pytest-asyncio>=0.24.0",
18
+ "httpx>=0.27.0",
12
19
  "pip-audit>=2.7.0",
13
20
  ]
14
21
 
@@ -47,3 +54,9 @@ exclude = ["generated", ".venv"]
47
54
 
48
55
  [tool.pytest.ini_options]
49
56
  testpaths = ["tests"]
57
+ asyncio_mode = "auto"
58
+
59
+ # 显式声明应用包,避免 setuptools 把 generated/ 误认为顶层包导致 build error
60
+ [tool.setuptools.packages.find]
61
+ include = ["app*"]
62
+ exclude = ["tests*", "generated*"]
@@ -0,0 +1,36 @@
1
+ """Smoke test for the healthz endpoint.
2
+
3
+ CI 跑 `pytest -q` 时会运行;端到端验证:
4
+ - FastAPI app 能 import(语法、依赖、配置都对)
5
+ - lifespan 钩子能起、能落
6
+ - /healthz 返回 200 + {"status": "ok"}
7
+
8
+ 新加端点应在 tests/ 下补对应测试;契约级断言(响应 schema 一致性)由
9
+ contracts/tests/contracts/ 下的契约测试覆盖,不在这里重复。
10
+ """
11
+
12
+ import pytest
13
+ from httpx import ASGITransport, AsyncClient
14
+
15
+ from app.main import app
16
+
17
+
18
+ @pytest.mark.asyncio
19
+ async def test_healthz_returns_ok() -> None:
20
+ transport = ASGITransport(app=app)
21
+ async with AsyncClient(transport=transport, base_url="http://test") as client:
22
+ response = await client.get("/healthz")
23
+ assert response.status_code == 200
24
+ assert response.json() == {"status": "ok"}
25
+
26
+
27
+ @pytest.mark.asyncio
28
+ async def test_root_returns_metadata() -> None:
29
+ transport = ASGITransport(app=app)
30
+ async with AsyncClient(transport=transport, base_url="http://test") as client:
31
+ response = await client.get("/")
32
+ assert response.status_code == 200
33
+ body = response.json()
34
+ assert body["name"].endswith("-server")
35
+ assert body["version"] == "0.1.0"
36
+ assert body["docs"] == "/docs"
@@ -1,5 +1,5 @@
1
1
  name: server-python
2
- version: 1.0.0
2
+ version: 1.1.0
3
3
  appliesWhen:
4
4
  backend: python
5
5
  priority: 30
@@ -12,6 +12,15 @@ files:
12
12
  render: true
13
13
  - from: files/app-init.py
14
14
  to: server/app/__init__.py
15
+ render: true
16
+ - from: files/main.py
17
+ to: server/app/main.py
18
+ render: true
19
+ - from: files/config.py
20
+ to: server/app/config.py
21
+ render: true
22
+ - from: files/test_healthz.py
23
+ to: server/tests/test_healthz.py
15
24
  render: false
16
25
  - from: files/generated-gitkeep
17
26
  to: server/generated/.gitkeep