8.4 KiB
8.4 KiB
Contributing to MacTools
[中文] [English]
感谢你关注 MacTools。请让每次贡献保持小而清晰:说明问题、给出可验证改动,并避免混入无关重构。
贡献方式
- Bug 报告请包含复现步骤、期望结果、实际结果、macOS 版本和相关日志或截图。
- 功能建议请说明使用场景、目标用户和预期交互;大型插件或交互变更请先开 issue 对齐范围。
- 涉及磁盘删除、系统权限、全局快捷键、显示器控制、签名或更新流程的改动,需要说明风险、保护措施和回滚方式。
开发环境
- 需要 Xcode 和
xcodegen,项目最低支持 macOS 14.0。 - 首次初始化:运行
make setup,再编辑LocalConfig.xcconfig填写DEVELOPMENT_TEAM和BUNDLE_IDENTIFIER_PREFIX。 - 常用命令:
make generate生成 Xcode 项目,make build编译校验,make run本地运行。 - 插件开发:
make run会增量编译 App 和插件,并把最新 Debug 插件包同步到本地开发市场;make sync-debug-plugins可只同步已编译插件。make build-plugin保留给单独验证动态包或发布链路使用,指定插件可运行make build-plugin PLUGIN=calendar。 - 不要提交本地或生成文件:
MacTools.xcodeproj、MacTools.xcworkspace、LocalConfig.xcconfig、build/、scripts/release.local.env。
项目结构
Sources/App/:应用入口、菜单栏状态项、设置页和窗口路由。Sources/Core/:插件宿主、动态插件加载、快捷键、权限、日志、更新等共享基础能力。Sources/MacToolsPluginKit/:插件 API、描述式 UI 模型和运行时上下文。Plugins/<PluginName>/:插件 manifest、源码、bundle 入口、资源和相邻测试。Tests/:App/Core 共享逻辑的 XCTest;插件测试优先放在对应插件目录下。project.yml:XcodeGen 根项目源文件,只维护 App、PluginKit 和公共聚合入口;插件 target 由生成器自动生成。Plugins/<PluginName>/project.yml:可选的插件构建差异配置,仅在插件需要额外 framework、include path、bundle 资源、helper/tool target 或 target 覆盖时添加。docs/plugins/:插件包、catalog、本地调试和发布流程说明。docs/superpowers/:较大的产品、交互或实施设计文档。
开发约定
- 新增插件放在
Plugins/<PluginName>/,至少包含plugin.json、Sources/和Bundle/。 - 普通插件只需要在目录内定义
plugin.json、源码和 bundle 入口;make generate会扫描Plugins/*/plugin.json并生成本地Configs/GeneratedPlugins.yml,不要手改生成文件。 - 需要 macOS app extension 的能力(如 Finder Sync)必须在根
project.yml添加扩展 target 并嵌入主应用;动态插件只负责 MacTools 面板和设置入口。 - 新增和更新插件的命令流程见
docs/plugins/local-native-plugins.md的 Development Steps。 - 文档保持简短、聚焦任务。用户可见行为变化应同步更新
README.md或docs/下的相关文档;插件包、catalog 或发布流程变化应更新docs/plugins/。 - 插件实现
MacToolsPlugin;菜单栏主面板实现PluginPrimaryPanel,组件面板实现PluginComponentPanel。 plugin.json.id必须稳定、可读,并与运行时PluginMetadata.id完全一致;每个插件包只返回一个插件实例。- 插件展示状态通过
PluginPanelState、PluginPanelDetail、PluginPanelControl等模型表达,不绕过现有面板框架。 - 插件设置优先使用
settingsSections、permissionRequirements、shortcutDefinitions等描述式模型;只有复杂管理器或专用交互才使用PluginConfiguration自定义视图。 - 普通插件资源文件如果依赖变更较少,推荐直接打包到可执行二进制中;需要额外 bundle 资源时,在插件自己的
project.yml中声明最小差异。 - 自定义插件设置视图必须复用
MacToolsPluginKit.PluginSettingsTheme和.pluginSettingsCardBackground(...),不要复制插件私有 settings style,也不要让插件依赖Sources/App/SettingsStyle.swift。 - 插件状态变化后调用
onStateChange?();耗时扫描、文件系统和系统调用不要长时间阻塞主线程。 - 用户可见文案以中文为主,保持简洁、清楚、接近 macOS 原生表达。
- 用户可见文案使用
.xcstrings本地化。App/Core 文案放在Sources/Resources/Localization,PluginKit 文案放在Sources/MacToolsPluginKit/Resources,插件文案放在Plugins/<PluginName>/Resources。插件plugin.json保留displayName/summary作为 fallback,并为插件市场和未加载插件展示提供localizedMetadata。 - 新插件应尽量提供多语言,至少覆盖面板文案、设置文案、权限说明和插件元数据。
- 优先复用 Apple 原生框架;新增系统 framework、私有 include path、bundle 内辅助可执行文件时,在插件自己的
project.yml中声明最小差异。需要单独签名的 bundle 资源可执行文件应写入plugin.json.package.signPaths。
测试
- 行为改动应补充或更新相邻 XCTest,测试文件命名使用
<TypeName>Tests.swift。 - 完整测试:
xcodebuild -project MacTools.xcodeproj -scheme MacTools -configuration Debug -derivedDataPath build/DerivedData test -quiet。 - 单个测试类:在完整测试命令后追加
-only-testing:MacToolsTests/<TestClassName>。 - 文件系统测试使用临时目录或 fake store;磁盘清理相关测试不得删除真实用户目录。
Pull Request Checklist
- PR 范围聚焦,并说明变更目的、验证方式和用户影响。
- commit message、Pull Request 标题/描述和 issue 优先使用英文。
- 构建或测试已通过;如无法运行,请在 PR 中说明原因。
- 用户可见行为变化已同步更新
README.md或相关设计文档。 - 高风险功能已覆盖安全校验、错误状态和权限不足场景。
- 不包含无关格式化、生成物、本地配置、证书或发布凭证。
Release
- 发布由维护者执行;不要在普通贡献中创建 tag、发布 GitHub Release 或提交发布产物。
- GitHub 页面发包优先使用
Actions→Prepare Release。输入type、目标version和是否release;勾选release时会在 bump、提交和创建 tag 后继续触发实际发包 workflow。 - 快速发包优先使用
make release。命令会交互选择app或plugin,先分析下一版本的patch/minor/major并预览 bump;确认后才git pull --rebase、执行轻量检查、更新并提交版本 bump、创建并推送对应 tag。 - App 发布会更新
project.yml的MARKETING_VERSION和CURRENT_PROJECT_VERSION,推送v*.*.*tag 后由Releaseworkflow 构建、签名、公证并上传 DMG。 - 插件发布会推送
plugins-*批次 tag。默认auto模式会按生产 catalog 找出新插件、已 bump 插件和包相关变更插件;需要时自动更新对应plugin.json.version,然后由Plugin Releaseworkflow 构建并合并签名 catalog。 - 新版 App 首次启动时会先检查已安装插件,并从签名后的生产 catalog 自动更新到最新版;不会自动安装用户未安装的新插件。
- 非交互用法示例:
make release ARGS="--type app --version 1.0.7 --yes",或make release ARGS="--type plugin --version 1.0.10 --plugin-mode selected --plugin calendar --yes"。 - 预览将执行的步骤可追加
--dry-run;正式发布前工作区必须干净。 - 本地发布前复制
scripts/release.local.env.sample为scripts/release.local.env,至少填写DEVELOPER_ID_APPLICATION。 - 如需 Apple 公证,首次使用
xcrun notarytool store-credentials保存凭证。 - 版本号默认读取
project.yml中的MARKETING_VERSION和CURRENT_PROJECT_VERSION。 - 生成本地正式包仍可使用底层脚本:
./scripts/release-local.sh;发布到 GitHub Release 前需先完成gh auth login,再执行./scripts/release-local.sh --publish。 - 插件库发布使用
plugins-*批次 tag 触发Plugin Releaseworkflow。默认只构建和上传版本递增的插件,并将新条目合并进生产 catalog;catalog 私钥、Developer ID 证书和 GitHub token 必须来自 CI secrets 或本地环境变量。 - GitHub Actions 自动构建与发布配置见
docs/github-actions.md;插件 catalog、包结构和批次发布流程见docs/plugins/plugin-catalog.md。