Blender 插件开发需要更多 DevOps
Source: Dev.to
概览
编写测试代码并实现自动化。
在多个 Blender 版本上运行测试,以安心发布。
- 想要(或已经)开发 Blender 插件的个人开发者。
- 想确保质量但不知道如何引入 CI/CD 的人。
- 对手动修复和检查感到厌倦的人。
- 对使用 GitHub Actions 实现 CI/CD 感兴趣的人(本文将通用的 CI/CD 流水线应用到 Blender 插件开发中)。
关于 DevOps 的文献非常丰富,这里就不深入探讨了。简而言之,它被视为通用软件开发的最佳实践。在这种方法论中,开发流程被表示为以下阶段的无限循环:
| 阶段 | Blender 插件开发中的过程 |
|---|---|
| Plan | 规划功能实现、Bug 修复等 |
| Code ★ | 编写 Python 代码 |
| Build ★ | 创建干净的 ZIP 文件 |
| Test ★ | 手动或自动化测试 |
| Release ★ | 发布已测试的 ZIP(GitHub/Extensions) |
| Deploy | 用户下载 ZIP 并在 Blender 中安装 |
| Operate | 用户在生产环境中实际使用插件 |
| Monitor | 接收用户的 issue 与反馈 |
本文重点关注标有 ★ 的阶段:Code、Build、Test 与 Release。
问题
Blender 5 上个月正式发布。我安装了 5 的 beta 版以及约 30 个插件(付费和免费都有),其中很多都报错。即使在正式版发布后,仍有若干插件没有可用的发行版。当插件描述写着 “支持 4.2 及以上” 但在 Blender 5 中失效时,用户只能纠结是等待更新还是自行修复。
一个简单的 CI 设置,即使只跑一次,也能检测出基本的兼容性错误。维护者随后可以临时声明不再支持 Blender 5,或明确结束支持。如果维护者已经失联,那也只能无计可施。
在不同规模的仓库中观察到,Blender 插件生态的测试文化相较于其他软件开发领域更为薄弱。官方类项目往往拥有自动化测试和交付流水线,但许多个人开发者的仓库——即使是热门仓库——也缺乏任何测试自动化。手动测试流程常常缺失,导致提交 PR 时缺乏信心,因为潜在的副作用未知。大型插件随着功能请求的增加往往变得臃肿,进一步加大维护难度。
根本原因在于通用软件开发的常用实践尚未渗透到 Blender 插件社区。本文提出一种可以直接采用的方法。
一个已准备好进行 DevOps 的插件示例:SavePoints
我最近在 Blender Extensions 上发布了我的第一个插件 SavePoints。它可以为 .blend 文件保存缩略图和备注,并执行定期自动保存。该插件从一开始就以 DevOps 为目标构建,作为模板供大家参考。
- 扩展页面:
可维护性目标
- 可测试性 – 将逻辑隔离以便进行单元测试。
- CI 兼容性 – 确保插件能够在无头环境(
-b参数)下运行。 - 明确分层 – 将 Blender‑specific 代码保持在最小范围。
无头环境
无头环境指在没有 GUI 的情况下运行 Blender:
blender -b -P my_script.py
参考文献:
实现细节
轻量的 Operator 层
operators.py 只包含 UI 粘合层。核心处理逻辑位于 core.py,且 不 依赖 bpy。
# operators.py
class SAVEPOINTS_OT_delete(bpy.types.Operator):
# ...
def execute(self, context):
# 实际处理调用 core.py 中的函数
delete_version_by_id(item.version_id)
return {'FINISHED'}
# core.py
def delete_version_by_id(version_id: str) -> None:
# 标准 Python 逻辑(shutil、json 等)– 不使用 bpy
...
这种分离使得单元测试可以在不启动 Blender 的情况下运行。
优先使用 bpy.data 而非 bpy.ops
经验法则:尽可能使用 bpy.data;只有在绝对必要时才回退到 bpy.ops。bpy.ops 会模拟用户操作,需要合适的 UI 上下文,在 CI 中常常因 poll 错误而失败。
为无头模式添加守卫子句
在使用 OpenGL 捕获缩略图时,无头模式没有窗口。代码捕获异常并跳过缩略图生成:
def capture_thumbnail(context: bpy.types.Context, thumb_path: str) -> None:
try:
if context.window_manager.windows:
bpy.ops.render.opengl(write_still=True)
# ... 保存缩略图 ...
else:
pass # 在无头模式下跳过
except Exception as e:
print(f"Thumbnail generation failed: {e}")
虽然引入了与环境相关的分支,但可以防止 CI 崩溃。
测试策略
我将测试分为两层,以实现成本效益。
逻辑测试
- 工具:
pytest+fake-bpy-module - 范围:验证纯 Python 逻辑(路径处理、数据计算等),不启动 Blender。
- 频率:每次提交本地和 CI 都运行。
端到端(E2E)测试
- 工具:在无头模式下启动真实的 Blender 并运行插件。
- 范围:验证插件与 Blender API 的交互是否正确。
- 频率:在开发期间偶尔运行,以及在关键 CI 事件(如合并到
main)时运行。
因为大多数兼容性问题来源于 API 变动,E2E 测试对于捕获 Blender 更新导致的破坏至关重要。
使用 GitHub Actions 设置 CI
一个最小化的工作流,运行两层测试:
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
blender-version: [ "3.6", "4.0", "5.0" ]
steps:
- uses: actions/checkout@v3
- name: Install Blender
run: |
sudo add-apt-repository ppa:thomas-schiex/blender
sudo apt-get update
sudo apt-get install blender=${{ matrix.blender-version }}
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install pytest fake-bpy-module
- name: Run Logic Tests
run: pytest tests/logic
- name: Run E2E Tests
run: |
blender -b -P tests/e2e/run_tests.py
请根据你的平台自行调整 Blender 安装步骤。 该工作流会构建一个干净的 ZIP(Build 阶段),并可以将其作为发布制品(Release 阶段)上传。
结论
把 Blender 插件开发当作普通软件项目来对待——拆分代码、编写单元与 E2E 测试、并使用 CI 自动化流水线,你可以:
- 及早发现兼容性问题(尤其是跨 Blender 版本的差异)。
- 减少手动测试工作量。
- 为维护者和贡献者在提交 PR 时提供信心。
采用这些实践能够让 Blender 插件生态更接近现代 DevOps 标准,从而产出更稳定、可维护的插件。