改技能配置从 .env里读取

This commit is contained in:
jerron
2026-09-27 23:52:24 +08:00
parent a8d67f3c64
commit 50f3f0ffc2
5 changed files with 83 additions and 22 deletions
+4
View File
@@ -0,0 +1,4 @@
# YIERP API 连接配置(复制为项目根目录 .env 并填入真实值;.env 禁止入库)
YIERP_URL=https://yierp.example.com
YIERP_APIKEY=你的_api_key
YIERP_APISECRET=你的_api_secret
+2 -2
View File
@@ -39,8 +39,8 @@
```bash
python tools/yierp_cli.py whoami --config .yierp/config.json
python tools/yierp_cli.py list --doctype ToDo --config .yierp/config.json --limit 10
python tools/yierp_cli.py create --doctype ToDo --config .yierp/config.json --data '{"description":"测试任务","status":"Open"}'
python tools/yierp_cli.py list --config .yierp/config.json --doctype ToDo --limit 10
python tools/yierp_cli.py create --config .yierp/config.json --doctype ToDo --data '{"description":"测试任务","status":"Open"}'
```
## 常用命令
+32 -12
View File
@@ -7,6 +7,8 @@ description: 适用于 YIERP(源自 ERPNext v16)的数据访问与管理技
这个技能用于访问 YIERP 系统中的业务数据与文档资源。YIERP 继承 ERPNext v16 的 Frappe / REST API 设计,因此可以使用标准的 HTTP API 方式进行 DocType 数据访问、文档操作和后端方法调用。
> **同步方向**:本技能的工作副本位于项目 `D:\git\giterp\yierp-script\.qoder\skills\yierp-cli\`(自包含技能包,脚本在其 `scripts/`)。变更先更新工作副本,再同步到本仓库(本仓库脚本位于 `tools/`)。
## 适用目标
- 通过配置 `url`、`apikey`、`ApiSecret` 建立认证
@@ -14,9 +16,26 @@ description: 适用于 YIERP(源自 ERPNext v16)的数据访问与管理技
- 适合脚本自动化、批量同步、业务查询、报表提取和业务集成
- 所有说明、注释、提示和输出都使用简体中文
> **参数顺序**:`--config` / `--url` / `--apikey` / `--apisecret` / `--timeout` / `--no-verify-ssl` 为全局参数,必须写在子命令**之前**,否则会报 `unrecognized arguments`。
## 配置方式
### 1. 配置文件方式
配置解析优先级:命令行参数 > 环境变量(含 `.env`)> 配置文件。
### 1. .env 文件方式(推荐)
脚本从当前工作目录自动向上查找 `.env`(至含 `.git` 的项目根为止),加载 `YIERP_URL / YIERP_APIKEY / YIERP_APISECRET`,不覆盖已存在的系统环境变量:
```bash
YIERP_URL=https://yierp.example.com
YIERP_APIKEY=你的_api_key
YIERP_APISECRET=你的_api_secret
```
模板见技能包内 `.env.example`。凭证文件 `.env` 必须 gitignore、不入库、不随技能发布。
### 2. 配置文件方式
建议在项目中创建 `.yierp/config.json`:
@@ -30,7 +49,7 @@ description: 适用于 YIERP(源自 ERPNext v16)的数据访问与管理技
}
```
### 2. 环境变量方式
### 3. 环境变量方式
```bash
set YIERP_URL=https://yierp.example.com
@@ -38,10 +57,10 @@ set YIERP_APIKEY=你的_api_key
set YIERP_APISECRET=你的_api_secret
```
### 3. 命令行参数方式
### 4. 命令行参数方式
```bash
python tools/yierp_cli.py list --doctype ToDo --url https://yierp.example.com --apikey xxx --apisecret yyy
python tools/yierp_cli.py --url https://yierp.example.com --apikey xxx --apisecret yyy list --doctype ToDo
```
## 关键命令
@@ -49,49 +68,49 @@ python tools/yierp_cli.py list --doctype ToDo --url https://yierp.example.com --
### 1. 检查当前登录用户
```bash
python tools/yierp_cli.py whoami --config .yierp/config.json
python tools/yierp_cli.py whoami
```
### 2. 查询列表
```bash
python tools/yierp_cli.py list --doctype ToDo --config .yierp/config.json --filters '{"status":"Open"}' --limit 20
python tools/yierp_cli.py list --doctype ToDo --filters '{"status":"Open"}' --limit 20
```
### 3. 获取单条记录
```bash
python tools/yierp_cli.py get --doctype ToDo --name "TODO-00001" --config .yierp/config.json
python tools/yierp_cli.py get --doctype ToDo --name "TODO-00001"
```
### 4. 创建记录
```bash
python tools/yierp_cli.py create --doctype ToDo --config .yierp/config.json --data '{"description":"测试任务","status":"Open"}'
python tools/yierp_cli.py create --doctype ToDo --data '{"description":"测试任务","status":"Open"}'
```
### 5. 更新记录
```bash
python tools/yierp_cli.py update --doctype ToDo --name "TODO-00001" --config .yierp/config.json --data '{"status":"Closed"}'
python tools/yierp_cli.py update --doctype ToDo --name "TODO-00001" --data '{"status":"Closed"}'
```
### 6. 删除记录
```bash
python tools/yierp_cli.py delete --doctype ToDo --name "TODO-00001" --config .yierp/config.json --yes
python tools/yierp_cli.py delete --doctype ToDo --name "TODO-00001" --yes
```
### 7. 调用自定义后端方法
```bash
python tools/yierp_cli.py method --method your_app.api.test --config .yierp/config.json --args '{"message":"hello"}'
python tools/yierp_cli.py method --method your_app.api.test --args '{"message":"hello"}'
```
### 8. 查看当前配置摘要
```bash
python tools/yierp_cli.py config --config .yierp/config.json
python tools/yierp_cli.py config
```
## 认证方式
@@ -144,6 +163,7 @@ Authorization: token {apikey}:{ApiSecret}
- 请求体 JSON 是否符合规范
- API 路径是否正确,是否为 `api/resource` 或 `api/method`
- SSL 证书错误是否需要使用 `--no-verify-ssl`
- Windows GBK 控制台中文输出乱码:设置环境变量 `PYTHONIOENCODING=utf-8` 后重跑,数据本身不受影响
## 适用场景
-7
View File
@@ -1,7 +0,0 @@
{
"url": "https://yierp.example.com",
"apikey": "你的_api_key",
"ApiSecret": "你的_api_secret",
"timeout": 30,
"verify_ssl": true
}
+45 -1
View File
@@ -55,6 +55,49 @@ def _mask_value(value: Optional[str]) -> str:
return f"{value[:2]}******{value[-2:]}"
def _parse_env_value(value: str) -> str:
"""去除 .env 值两侧空白与包裹的引号。"""
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in ("'", '"'):
value = value[1:-1]
return value
def _iter_dotenv_candidates() -> list:
"""从当前工作目录向上逐级查找 .env,遇到 .git 目录即停止上溯。"""
candidates = []
cwd = Path.cwd().resolve()
candidates.append(cwd / ".env")
for parent in cwd.parents:
candidates.append(parent / ".env")
if (parent / ".git").exists():
break
return candidates
def load_dotenv() -> None:
"""加载 .env 到环境变量(不覆盖已存在的环境变量)。"""
for env_path in _iter_dotenv_candidates():
if not env_path.is_file():
continue
try:
text = env_path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
continue
for line in text.splitlines():
stripped = line.strip()
if not stripped or stripped.startswith("#") or "=" not in stripped:
continue
if stripped.startswith("export "):
stripped = stripped[len("export "):].strip()
key, _, raw_value = stripped.partition("=")
key = key.strip()
if not key or key in os.environ:
continue
os.environ[key] = _parse_env_value(raw_value)
break
def _load_json_file(file_path: str) -> Dict[str, Any]:
"""读取 JSON 配置文件。"""
path = Path(file_path)
@@ -71,7 +114,8 @@ def _load_json_file(file_path: str) -> Dict[str, Any]:
def resolve_config(args: argparse.Namespace) -> Dict[str, Any]:
"""按优先级解析配置:命令行参数 > 环境变量 > 配置文件。"""
"""按优先级解析配置:命令行参数 > 环境变量(含 .env 文件)> 配置文件。"""
load_dotenv()
config_path = args.config or os.getenv("YIERP_CONFIG_PATH", ".yierp/config.json")
config_data: Dict[str, Any] = _load_json_file(config_path)