|
| 1 | +# 贡献指南 |
| 2 | + |
| 3 | +感谢愿意改进本项目。开始前,请先阅读 [行为准则](CODE_OF_CONDUCT.md)。 |
| 4 | + |
| 5 | +本文面向开发者。目标是让你能从源码跑起来、提交一份容易 review 的 Pull Request。 |
| 6 | + |
| 7 | +本项目是 [SurveyController](https://github.com/SurveyController/SurveyController)(Windows 桌面端)的 macOS 移植版:业务逻辑以官方 Python 源码为准 1:1 移植,UI 用 SwiftUI 原生重写。移植约定详见 [AGENTS.md](AGENTS.md)。 |
| 8 | + |
| 9 | +## 开发环境 |
| 10 | + |
| 11 | +需要准备: |
| 12 | + |
| 13 | +- macOS 14(Sonoma)及以上 |
| 14 | +- Xcode 16 及以上(含 Swift 6 工具链) |
| 15 | +- Git |
| 16 | + |
| 17 | +不需要额外安装依赖管理器——唯一的第三方依赖 SwiftSoup 由 Xcode 自动解析。 |
| 18 | + |
| 19 | +## 开发流程 |
| 20 | + |
| 21 | +下面按第一次参与贡献的流程来写。 |
| 22 | + |
| 23 | +### 1. Fork 仓库 |
| 24 | + |
| 25 | +先在本仓库主页点击 **Fork**。 |
| 26 | + |
| 27 | +Fork 后,你会得到一份自己的仓库,例如: |
| 28 | + |
| 29 | +```text |
| 30 | +https://github.com/你的用户名/SurveyController-Mac |
| 31 | +``` |
| 32 | + |
| 33 | +后续改动**先推送到你自己的仓库**,再向主仓库提交 Pull Request。 |
| 34 | + |
| 35 | +### 2. 克隆自己的 Fork |
| 36 | + |
| 37 | +不要直接克隆主仓库——如果你没有被赋予直接推送到主仓库的权限。 |
| 38 | + |
| 39 | +```bash |
| 40 | +git clone https://github.com/你的用户名/SurveyController-Mac.git |
| 41 | +cd SurveyController-Mac |
| 42 | +``` |
| 43 | + |
| 44 | +### 3. 打开工程并运行 |
| 45 | + |
| 46 | +```bash |
| 47 | +open SurveyController.xcodeproj # Xcode 中选择 SurveyController scheme,Cmd+R 运行 |
| 48 | +``` |
| 49 | + |
| 50 | +或命令行构建: |
| 51 | + |
| 52 | +```bash |
| 53 | +xcodebuild -project SurveyController.xcodeproj -scheme SurveyController build |
| 54 | +``` |
| 55 | + |
| 56 | +### 4. 添加主仓库地址并同步最新代码 |
| 57 | + |
| 58 | +把主仓库添加为 `upstream`: |
| 59 | + |
| 60 | +```bash |
| 61 | +git remote add upstream https://github.com/SurveyController/SurveyController-Mac.git |
| 62 | +git remote -v |
| 63 | +``` |
| 64 | + |
| 65 | +看到 `origin` 和 `upstream` 都存在就行: |
| 66 | + |
| 67 | +```text |
| 68 | +origin 你的 Fork 地址 |
| 69 | +upstream https://github.com/SurveyController/SurveyController-Mac.git |
| 70 | +``` |
| 71 | + |
| 72 | +**每次开始新功能前,先同步主仓库最新代码:** |
| 73 | + |
| 74 | +```bash |
| 75 | +git checkout main |
| 76 | +git fetch upstream |
| 77 | +git pull upstream main |
| 78 | +``` |
| 79 | + |
| 80 | +### 5. 创建开发分支 |
| 81 | + |
| 82 | +**不建议直接在 `main` 分支上做出改动。** |
| 83 | + |
| 84 | +每个修复或功能都开一个新分支: |
| 85 | + |
| 86 | +```bash |
| 87 | +git checkout -b fix/short-description |
| 88 | +``` |
| 89 | + |
| 90 | +分支名可以这样写: |
| 91 | + |
| 92 | +```bash |
| 93 | +fix/slider-ratio-mismatch |
| 94 | +fix/wjx-scene-id-parse |
| 95 | +feature/tencent-provider |
| 96 | +docs/contributing-flow |
| 97 | +``` |
| 98 | + |
| 99 | +含义: |
| 100 | + |
| 101 | +- `fix/xxx`:修 bug。 |
| 102 | +- `feature/xxx`:加功能。 |
| 103 | +- `docs/xxx`:改文档。 |
| 104 | +- `refactor/xxx`:重构。 |
| 105 | + |
| 106 | +> [!IMPORTANT] |
| 107 | +> 每个分支只对应单一的改动,**不要在一个分支里猛塞多个新功能!** |
| 108 | +
|
| 109 | +### 6. 暂存与提交文件 |
| 110 | + |
| 111 | +Git 提交分两步: |
| 112 | + |
| 113 | +1. 暂存:告诉 Git 这次准备提交哪些文件。 |
| 114 | +2. 提交:把暂存内容保存成一次历史记录。 |
| 115 | + |
| 116 | +在此之前,先看一眼实际会进提交的文件: |
| 117 | + |
| 118 | +```bash |
| 119 | +git status --short |
| 120 | +``` |
| 121 | + |
| 122 | +> [!IMPORTANT] |
| 123 | +> **不要把 IDE 工作区垃圾、个人本地配置、临时文件一起提交进来!** |
| 124 | +
|
| 125 | +比如 `.idea/`、`.vscode/`、`xcuserdata/`、`DerivedData/`、构建产物目录(`build*/`)、`.DS_Store`、临时导出文件。这些东西和项目代码无关,塞进仓库只会污染 review。 |
| 126 | + |
| 127 | +暂存改动并提交: |
| 128 | + |
| 129 | +```bash |
| 130 | +git add 改动的文件 |
| 131 | +git commit -m "类型: 简短说明" |
| 132 | +``` |
| 133 | + |
| 134 | +常见类型: |
| 135 | + |
| 136 | +```text |
| 137 | +feat: 新增功能(含官方移植) |
| 138 | +fix: 修复问题 |
| 139 | +docs: 修改文档 |
| 140 | +test: 添加或修改测试 |
| 141 | +refactor: 重构代码 |
| 142 | +build: 构建或依赖调整 |
| 143 | +chore: 杂项 |
| 144 | +``` |
| 145 | + |
| 146 | +例子: |
| 147 | + |
| 148 | +```bash |
| 149 | +git commit -m "fix: 联动滑杆锁定额度计算错误" |
| 150 | +git commit -m "feat: 腾讯问卷解析链路(对标 tencent/provider/parser.py)" |
| 151 | +git commit -m "test: 补充 submitdata 转义表 golden 用例" |
| 152 | +``` |
| 153 | + |
| 154 | +### 7. 推送分支 |
| 155 | + |
| 156 | +第一次推送当前分支: |
| 157 | + |
| 158 | +```bash |
| 159 | +git push -u origin 当前分支名 |
| 160 | +``` |
| 161 | + |
| 162 | +以后同一个分支继续提交后,只需要: |
| 163 | + |
| 164 | +```bash |
| 165 | +git push |
| 166 | +``` |
| 167 | + |
| 168 | +### 8. 提交 Pull Request |
| 169 | + |
| 170 | +推送后,GitHub 通常会提示 **Compare & pull request**。 |
| 171 | + |
| 172 | +确认方向是: |
| 173 | + |
| 174 | +```text |
| 175 | +你的 Fork 分支 -> SurveyController/SurveyController-Mac 的 main 分支 |
| 176 | +``` |
| 177 | + |
| 178 | +PR 描述里写清楚: |
| 179 | + |
| 180 | +- 改了什么。 |
| 181 | +- 为什么改。 |
| 182 | +- 跑过哪些检查。 |
| 183 | +- 有没有用户能看见的变化。 |
| 184 | + |
| 185 | +### 9. 根据 review 修改 |
| 186 | + |
| 187 | +如果维护者提出修改意见,继续在同一个分支上改: |
| 188 | + |
| 189 | +```bash |
| 190 | +git add 修改过的文件 |
| 191 | +git commit -m "fix: address review comments" |
| 192 | +git push |
| 193 | +``` |
| 194 | + |
| 195 | +同一个 PR 会自动更新,不需要重新开 PR。 |
| 196 | + |
| 197 | +提交前请确认: |
| 198 | + |
| 199 | +- 改动只包含本次 PR 需要的内容。 |
| 200 | +- 没有提交 `xcuserdata/`、`DerivedData/`、`build*/` 等构建产物。 |
| 201 | +- 没有提交日志、缓存、`.DS_Store`。 |
| 202 | +- 没有提交密钥、卡密、代理套餐等敏感信息。 |
| 203 | +- 用户数据仍写入用户目录(`~/Library/Application Support/SurveyController/`),不写回安装目录。 |
| 204 | + |
| 205 | +## 常见改动位置 |
| 206 | + |
| 207 | +| 目标 | 目录 | |
| 208 | +| --- | --- | |
| 209 | +| 问卷星解析、提交编解码 | `SurveyController/Provider/Wjx/` | |
| 210 | +| 平台识别、Provider 协议 | `SurveyController/Provider/` | |
| 211 | +| 核心模型(题目/配置/动作) | `SurveyController/Core/Model/` | |
| 212 | +| 执行引擎、调度 | `SurveyController/Core/Engine/` | |
| 213 | +| 答案生成、逻辑规划 | `SurveyController/Core/Questions/` | |
| 214 | +| 随机 IP 后端、代理池、地区 | `SurveyController/Core/Backend/`、`Core/Proxy/` | |
| 215 | +| HTTP 客户端 | `SurveyController/Core/Network/` | |
| 216 | +| 配置编解码、默认配置 | `SurveyController/Data/` | |
| 217 | +| SwiftUI 界面、向导、组件 | `SurveyController/UI/` | |
| 218 | +| 单元测试 | `SurveyControllerTests/` | |
| 219 | +| 实测链路(门控) | `SurveyControllerTests/LiveSurveyE2ETests.swift` | |
| 220 | +| CI / 发布 | `.github/workflows/` | |
| 221 | + |
| 222 | +不要把新功能塞进不相干文件。屎山通常就是这么长出来的。 |
| 223 | + |
| 224 | +如果新增或删除顶层目录,需同步更新本文档和 AGENTS.md 里的结构说明。 |
| 225 | + |
| 226 | +## 代码要求 |
| 227 | + |
| 228 | +- Swift 代码保持简单直白,优先复用现有模块。 |
| 229 | +- UI 一律使用 SwiftUI 原生组件;品牌图标用 `UI/BrandIcons.swift` 自绘,不引入图标库。 |
| 230 | +- 不引入带 native 库的第三方依赖(当前唯一依赖 SwiftSoup)。 |
| 231 | +- 业务逻辑与官方 Python 源码 1:1:变量名可转 camelCase,但**分支、边界值、魔法数字不动**;文件头注释标注对标的 Python 文件路径。 |
| 232 | +- 涉及 WJX 提交协议(submitdata 转义、jqsign、starttime 格式等)的改动必须有 golden-value 测试。 |
| 233 | +- 版本号三处同步改:`App/AppVersion.swift`、工程 `MARKETING_VERSION`、`CURRENT_PROJECT_VERSION`(`major*10000 + minor*100 + patch`)。 |
| 234 | +- 用户配置与日志写入 `~/Library/Application Support/SurveyController/`。 |
| 235 | + |
| 236 | +## 本地检查 |
| 237 | + |
| 238 | +只跑单测: |
| 239 | + |
| 240 | +```bash |
| 241 | +xcodebuild -project SurveyController.xcodeproj -scheme SurveyController test |
| 242 | +``` |
| 243 | + |
| 244 | +构建 Release 包验证: |
| 245 | + |
| 246 | +```bash |
| 247 | +xcodebuild -project SurveyController.xcodeproj -scheme SurveyController \ |
| 248 | + -configuration Release -derivedDataPath build \ |
| 249 | + -skipPackagePluginValidation CODE_SIGNING_ALLOWED=NO build |
| 250 | +``` |
| 251 | + |
| 252 | +## 测试建议 |
| 253 | + |
| 254 | +改哪一块,就补哪一块测试: |
| 255 | + |
| 256 | +- 解析器、提交编解码:补 `SurveyControllerTests/Wjx*Tests.swift` 的 golden 用例(官方 `CI/unit_tests/` 有对应 Python 用例可移植)。 |
| 257 | +- 配置编解码:补 `ConfigCodecTests.swift`。 |
| 258 | +- 执行引擎、代理池:补 `RunEngineTests.swift`。 |
| 259 | +- 纯 UI 交互逻辑(如联动滑杆算法)抽成纯函数并补测(参考 `RatioSliderMathTests.swift`)。 |
| 260 | +- 纯展示改动可不强制补单测,但要手动启动看一遍。 |
| 261 | + |
| 262 | +不要在测试里访问真实问卷、真实账号、真实付费代理。实测链路走 `LiveSurveyE2ETests` 的环境变量门控,默认跳过。 |
| 263 | + |
| 264 | +## Pull Request 要求 |
| 265 | + |
| 266 | +PR 描述请写清楚: |
| 267 | + |
| 268 | +- 改了什么。 |
| 269 | +- 为什么改。 |
| 270 | +- 影响哪些功能。 |
| 271 | +- 跑过哪些检查。 |
| 272 | +- 是否有用户可见变化。 |
| 273 | + |
| 274 | +建议格式: |
| 275 | + |
| 276 | +```markdown |
| 277 | +## 简述改动 |
| 278 | +- ... |
| 279 | + |
| 280 | +## 对标的官方实现 |
| 281 | +- `wjx/provider/http_runtime.py` 中的 ... |
| 282 | + |
| 283 | +## 影响 |
| 284 | +- ... |
| 285 | + |
| 286 | +## 已跑检查 |
| 287 | +- [ ] xcodebuild test |
| 288 | +- [ ] 手动运行验证 |
| 289 | +``` |
| 290 | + |
| 291 | +如果修复 Issue,请在 PR 描述里关联: |
| 292 | + |
| 293 | +```markdown |
| 294 | +Fixes #123 |
| 295 | +``` |
| 296 | + |
| 297 | +## 仓库结构 |
| 298 | + |
| 299 | +```markdown |
| 300 | +仓库根目录 |
| 301 | +├── .github/ # GitHub Actions(CI 与 Release) |
| 302 | +├── assets/ # README 图标、二维码等仓库资源 |
| 303 | +├── SurveyController/ # 应用主体 |
| 304 | +│ ├── App/ # 版本常量 |
| 305 | +│ ├── Core/ # 核心业务 |
| 306 | +│ │ ├── Model/ # 题目/配置/动作等领域模型 |
| 307 | +│ │ ├── Engine/ # 执行引擎、槽位调度 |
| 308 | +│ │ ├── Questions/ # 答案生成、逻辑规划、时长采样 |
| 309 | +│ │ ├── AI/ # AI 填空(规划中) |
| 310 | +│ │ ├── Network/ # HTTP 客户端 |
| 311 | +│ │ ├── Backend/ # 随机 IP 官方后端 |
| 312 | +│ │ └── Proxy/ # 代理池、地区服务 |
| 313 | +│ ├── Provider/ # 平台适配 |
| 314 | +│ │ └── Wjx/ # 问卷星解析/编解码/提交 |
| 315 | +│ ├── Data/ # 配置编解码、默认配置、常量 |
| 316 | +│ ├── Resources/ # 图标 icns、二维码、地区码 |
| 317 | +│ ├── Support/ # JSON 宽松转换、随机源等辅助 |
| 318 | +│ └── UI/ # SwiftUI 界面(向导、社区、关于等) |
| 319 | +├── SurveyControllerTests/ # 单元测试(对标官方 CI/unit_tests) |
| 320 | +├── SurveyController.xcodeproj |
| 321 | +├── AGENTS.md # 移植约定(对标文件映射表) |
| 322 | +├── CONTRIBUTING.md # 本文档 |
| 323 | +└── CODE_OF_CONDUCT.md # 行为准则 |
| 324 | +``` |
0 commit comments