工程化红皮书
工程规范不是约束,是给你兜底的安全网。
本文档是所有 I++ OSS Hub 孵化项目的工程化强制规范。无论项目语言、规模大小,以下规则一律适用,没有例外。
一、从 Template 仓库启动(推荐路径)
I++ 俱乐部为不同类型的项目提供了官方 Template 仓库。对于从零开始的新项目,强烈推荐基于对应模板创建,这是最低摩擦的起点。
| 项目类型 | 官方模板仓库 |
|---|---|
| TypeScript CLI 工具 | ippclub/template-ts-cli |
| Node.js 全栈应用 | ippclub/template-node-fullstack |
| Python 脚本 / 数据项目 | ippclub/template-python |
| VitePress 文档站点 | ippclub/template-vitepress |
| 通用开源项目 | ippclub/template-oss-generic |
为什么推荐使用 Template?
- 模板已内置 CI/CD 流水线、Lint 配置、
.gitignore、LICENSE、CONTRIBUTING.md等基础文件,避免每个项目重复劳动。 - 模板由俱乐部维护者统一维护,经过安全审查,不会引入已知漏洞的初始依赖。
- 统一的目录结构降低跨项目贡献的认知成本。
从 Template 创建的流程:
# 1. 在 GitHub 上进入对应模板仓库
# 2. 点击绿色 "Use this template" 按钮
# 3. 仓库归属选择 ippclub 组织(而非个人账号)
# 4. 命名规范:全小写,用连字符分隔,如 blog2md、code-review-bot二、灵活入孵与模板反哺机制
I++ 不是门槛,而是助推器。
我们深知:最有价值的项目,往往不是在模板框架里诞生的,而是来自个人在真实场景中打磨的代码库。因此,I++ 提供灵活的入孵路径:
2.1 携原仓库直接入孵
社员无需放弃已有的项目、重新用模板建仓。 如果你已经有一个在开发中的优质项目,可以通过以下流程直接加入孵化大厅:
- 提交 RFC:按照《如何提交入孵申请》的流程,在 GitHub Issue 提交入孵申请,并附上现有仓库链接。
- PMC 代码规范审查:I++ 核心成员(PMC,Project Management Committee)将对原仓库进行一次代码规范审查,重点检查:
- 是否包含有效的
README.md和LICENSE - 是否有基础的
.gitignore配置 - CI/CD 流水线是否可以快速补全(可由俱乐部协助配置)
- 代码风格是否具备基本一致性(有 Lint 配置即可,无需完全对齐俱乐部模板)
- 是否包含有效的
- 转移与共同维护:审查通过后,仓库可转移至
ippclub组织,或以 Fork + 上游同步方式加入,双方协商决定。正式入孵后,适用本文档第三章起的所有规范。
2.2 模板反哺机制
我们鼓励——并高度重视——这种贡献:
如果你携带了一个新的技术栈或工程结构入孵,请考虑将你的工程目录提取为一个新的「官方模板(Template Repository)」,贡献给社团生态。
具体流程:
- 将你项目的工程基础部分(CI 配置、Lint、目录结构等)提取为一个独立的 Template 仓库
- 提交 PR,将新模板添加到本文档第一节的模板列表中
- Template 仓库将由俱乐部作为官方资产维护,你的名字将作为模板作者永久留存
这不只是贡献,这是在为下一个像你一样的同学铺路。
三、主干分支保护(Branch Protection)
main 分支是神圣的。所有在孵项目的 main 分支必须开启以下 Branch Protection 规则:
| 规则 | 配置值 |
|---|---|
| Require a pull request before merging | ✅ 启用 |
| Required approvals | 1(至少 1 名 Reviewer 批准) |
| Dismiss stale pull request approvals when new commits are pushed | ✅ 启用 |
| Require status checks to pass before merging | ✅ 启用 |
| Require branches to be up to date before merging | ✅ 启用 |
| Do not allow bypassing the above settings | ✅ 启用(对仓库管理员同样生效) |
| Allow force pushes | ❌ 禁止 |
| Allow deletions | ❌ 禁止 |
配置路径:仓库 → Settings → Branches → Add branch protection rule → Branch name pattern: main
⚠️ 注意:「Do not allow bypassing the above settings」必须勾选。这意味着即使是仓库 Owner,也必须走 PR 流程。这不是对你的不信任,这是对整个协作系统的信任。
四、强制 Pull Request 工作流
禁止一切形式的直接推送(git push)到 main 分支。 所有代码变更必须通过 Pull Request 进行。
标准分支命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 新功能 | feat/<描述> | feat/add-json-output |
| Bug 修复 | fix/<描述> | fix/encoding-issue-on-windows |
| 文档 | docs/<描述> | docs/update-readme |
| 重构 | refactor/<描述> | refactor/parser-module |
| 工程化配置 | chore/<描述> | chore/upgrade-dependencies |
PR 描述规范
每个 PR 的描述必须包含:
- What:这个 PR 做了什么(1-3 句话)
- Why:为什么要做(关联 Issue 编号,如
Closes #12) - How to test:Reviewer 如何验证这个变更(如适用)
Commit 消息规范(Conventional Commits)
遵循 Conventional Commits 规范:
<type>(<scope>): <subject>
[optional body]
[optional footer]常用 type:feat / fix / docs / refactor / test / chore
示例:
feat(parser): support dynamic rendering via Playwright
Previously the parser relied on static HTML, which failed on React SSR
pages. This commit adds Playwright headless browser support.
Closes #8五、CI/CD 全绿才能合并
所有 Status Check 必须全部通过(绿色),方可合并 PR。禁止任何形式的「跳过 CI」合并。
每个 Template 仓库预置的 CI 流水线包含以下检查项:
┌─────────────────────────────────────────────┐
│ CI Pipeline │
│ │
│ ① Lint — ESLint / Ruff / clippy │
│ ② Type — tsc --noEmit / mypy │
│ ③ Test — Jest / pytest / cargo test │
│ ④ Build — 确保构建产物可正常生成 │
│ │
│ 全部 ✅ → 允许合并 │
│ 任一 ❌ → 禁止合并,必须修复后重新触发 │
└─────────────────────────────────────────────┘为什么不能跳过 CI?
因为「本地没问题」从来都不是标准。CI 在一个干净的隔离环境中运行,能发现你本地因缓存、版本差异而掩盖的问题。每一次跳过 CI 的合并,都是在给未来的 Debug 埋雷。
六、发布(Release)规范
- 版本号遵循 Semantic Versioning:
MAJOR.MINOR.PATCH - 发布前必须更新
CHANGELOG.md(可使用conventional-changelog-cli自动生成) - 通过打 Git Tag 触发自动发布流水线:
git tag -a v1.0.0 -m "chore: release v1.0.0"
git push origin v1.0.0附:为什么这么「严格」?
有同学会问:一个学生社团的项目,为什么要搞这么多规矩?
答案很简单:因为你迟早要进入一家正式的软件公司,那里的规矩只会比这更严格。
I++ 不是在用规范约束你,而是在用真实环境提前给你打预防针。当你在 I++ 里已经习惯了 PR、CI、Code Review 的工作方式,进入公司的第一天你会发现:这里没有任何陌生的东西。
工程化规范由 I++ 维护者委员会制定,每学期审查一次。如有异议,在 GitHub 提交 RFC。