news 2026/9/28 7:21:47

Dolibarr 开发者的 pre-commit 钩子实战指南:从安装配置到 CI 集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dolibarr 开发者的 pre-commit 钩子实战指南:从安装配置到 CI 集成
  • 企业应用
  • 后端

【免费下载链接】dolibarr

Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.

项目地址:https://gitcode.com/gh_mirrors/do/dolibarr
点击查看免费下载
# Dolibarr 开发者的 pre-commit 钩子实战指南:从安装配置到 CI 集成

Dolibarr 是一个基于 PHP 的开源 ERP/CRM 系统,代码库庞大且横跨 PHP、YAML、SQL、Shell、JavaScript 多种语言,因此保证每一次git commit的代码质量至关重要。本文以仓库中 pre-commit 说明文档 为主线,完整讲解 Dolibarr 如何使用 pre-commit 中每一项钩子的作用、配置要点与底层实现,帮助你在一台新机器上快速启用这套质量门禁,并理解它如何与 CI 流水线协同。

读完后,你将掌握:pre-commit 工具在 Linux/macOS 上的安装、钩子的两种安装方式(pre-commit install与手动复制脚本)、钩子触发与跳过的常见技巧、Dolibarr 自定义代码规范的落地方式,以及.github/workflows/pre-commit.yml中 CI 侧的执行策略。

pre-commit 是什么?为什么 Dolibarr 需要它

pre-commit是一个用于管理和维护多语言 pre-commit 钩子的框架,官方网站为 https://pre-commit.org(完整文档见 https://pre-commit.com)。所谓 pre-commit 钩子,是指与git集成、在执行git commit时自动运行的检查程序:只要任一检查失败,提交就会被中止,直到你修复问题或显式跳过检查。

在引入该框架之前,Dolibarr 仓库内已经存在一个名为precommit的传统钩子脚本(见 dev/setup/git/hooks/pre-commit.legacy)。这个旧脚本在每次提交时依次运行三件事:

  1. phplint:用php -l对每个暂存的 PHP 文件做语法检查;
  2. phpcs:以 Dolibarr 自定义代码规范扫描代码风格问题;
  3. phpcbf:当检查失败且AUTOFIX=1(脚本默认值)时,自动修复代码风格错误并中止本次提交。

pre-commit框架与旧的precommit脚本相比,最大的优势是不局限于单一语言、也不局限于 PHP:它由 Python 生态驱动,通过仓库根目录的pre-commit-config.yaml声明式描述钩子列表,可组合使用 PHP、Shell、YAML、SQL、Markdown 等几乎任何语言的检查工具。因此虽然它多用于 Python 项目,但适用于绝大多数代码与文档开发场景,Dolibarr 也正是借助它把代码规范、翻译完整性、静态分析、秘密扫描等几十项检查统一纳入了提交流程。

注意:pre-commit与旧版precommit是两个不同的东西。Dolibarr 仓库中保留了旧脚本作为历史参考,但 dev/setup/git/README.md 明确建议使用新的 pre-commit 钩子文件配合pre-commit install安装,效果更好。

在本地 git 项目中安装与启用

1. 安装 pre-commit 工具本体

pre-commit是 Python 包,前提是系统中有 Python 与 pip:

# 若未安装 Python(以 Debian/Ubuntu 系为例) sudo apt install python3 # 若未安装 pip sudo apt install pip # 安装 pre-commit 工具 python3 -m pip install pre-commit

在较新的发行版(如 Debian 12 / Ubuntu 23.04+)上,pip 默认拒绝向系统环境写入包,需要追加--break-system-packages:

python3 -m pip install pre-commit --break-system-packages

Dolibarr 的 PHP 代码检查依赖 PHP_CodeSniffer,即phpcs与phpcbf两个命令,同样需要安装:

sudo apt install php-codesniffer

macOS(Homebrew)安装路径:

# 安装 pipx(管理 Python CLI 工具,隔离环境) brew install pipx pipx ensurepath # 安装 pre-commit 工具 pipx install pre-commit # 安装 phpcbf 与 phpcs brew install php-codesniffer

2. 把钩子挂到你的本地 git 克隆

在你的 Dolibarr 本地克隆目录中执行(只需一次):

pre-commit install

pre-commit install会在.git/hooks/pre-commit写入一个由框架生成、指向.pre-commit-config.yaml的启动脚本。Dolibarr 文档特别指出,推荐直接复制仓库自带的钩子文件,因为该文件可能与pre-commit install生成的版本存在差异:

cp dev/setup/git/hooks/pre-commit .git/hooks/pre-commit

对比 dev/setup/git/hooks/pre-commit 与框架默认生成的文件可以发现,Dolibarr 维护的这个版本只做了一处关键改造:在exec调用中追加了1>&2,把 pre-commit 的全部输出重定向到标准错误通道。这样当你在 IDE(如 VSCode、PhpStorm)里执行提交时,IDE 能正确捕获错误信息并展示给开发者,而不是被标准输出吞掉。脚本同时保留了回退逻辑:优先调用系统 Python 的-mpre_commit,否则回退到pre-commit命令,两者都不可用时输出提示并退出。

理解 Dolibarr 的 pre-commit 配置

Dolibarr 的所有钩子声明都集中在仓库根目录的 .pre-commit-config.yaml,它采用 pre-commit 标准的repos结构:每个repo指向一个 GitHub 仓库(或local本地钩子),rev固定到某个发布版本,hooks列出具体钩子及其参数、文件过滤规则。

顶层的全局 exclude 规则

配置第一行定义了一个全局排除正则:

exclude: (?x)^( htdocs/includes/ckeditor/.*|htdocs/public/includes/ckeditor/.*|htdocs/public/includes/jquery/.*|(\.(?!github/workflows)[^/]*/.*))$

它表示:第三方引入目录(htdocs/includes/、htdocs/public/includes/下的编辑器与 jQuery 等)以及仓库根目录下所有隐藏文件/目录(除.github/workflows外)默认不参与检查。这一设计是为了避免对上游库代码做无意义检查、也避免把隐藏配置文件卷入规范化流程。

通用代码卫生检查(pre-commit/pre-commit-hooks)

来自pre-commit/pre-commit-hooks(rev v6.0.0)的通用钩子负责最基础的仓库卫生:

钩子 id作用关键配置
no-commit-to-branch禁止直接在保护分支上提交--branch develop且匹配\d+.0$(即官方版本号分支,如20.0);可通过 SKIP 跳过
check-xml校验 XML 文件格式排除htdocs/includes/.*
check-yaml校验 YAML 文件格式--unsafe(允许解析包含特定标签的文件)
check-json校验 JSON 文件格式无
mixed-line-ending统一行尾为 LF,替代dev/tools/fixdosfiles.sh排除 TCPDF 字体文件与 swiftmailer 的 CRLF 文件
trailing-whitespace删除行尾空白排除 markdown 类型
end-of-file-fixer确保文件以单个换行结尾排除 tinymce 目录
check-merge-conflict检测未解决的冲突标记阶段含pre-rebase、pre-commit、pre-merge-commit
check-executables-have-shebangs有 shebang 的可执行文件必须带 shebang无
check-shebang-scripts-are-executable带 shebang 的脚本必须在 git 中标记为可执行排除 postgres2mysql、测试文本文件、debian 打包脚本、modulebuilder 模板等
fix-byte-order-marker移除 UTF-8 BOM无
check-case-conflict检查是否存在仅大小写不同的同名文件(Windows 冲突)无

这些钩子中相当一部分会直接修改文件(如mixed-line-ending、trailing-whitespace、end-of-file-fixer、fix-byte-order-marker),与文档"钩子可能修改你的代码"的描述一致——一旦文件被改动,本次提交会被取消,需要重新提交一次以纳入修复后的内容。

秘密扫描:gitleaks

来自gitleaks/gitleaks(rev v8.30.0)的gitleaks钩子用于检测并阻止硬编码秘密,如密码、API Key、Token 等被提交进 git 仓库,属于典型的 SAST(静态应用安全测试)工具。它默认在每次提交时扫描暂存内容,是保护 Dolibarr 这类开源项目供应链安全的重要一环。

GitHub Actions 工作流检查:actionlint

来自rhysd/actionlint(rev v1.7.12)的actionlint钩子用于校验.github/workflows/下的 GitHub Actions 定义是否正确(语法、表达式、引用等)。它被标记为stages: [manual],不会在默认提交阶段运行,需要手动触发:

pre-commit run -a --hook-stage=manual actionlint

PHP 代码检查与格式化:pre-commit-php

PHP 相关的检查来自mdeweerd/pre-commit-php(rev v1.6.8),这是 Dolibarr 质量门禁的核心:

  • php-cbf:对*.php文件运行 PHP Code Beautifier and Fixer(phpcbf),使用 Dolibarr 自定义规范自动修复代码风格,参数为--standard=dev/setup/codesniffer/ruleset.xml;
  • php-cs:对非htdocs/includes/的 PHP 文件运行 phpcs 代码风格检查,参数--standard=dev/setup/codesniffer/ruleset.xml、--report=emacs(IDE 友好的输出格式)、--severity=5(只报严重级别 ≥5 的问题)、--no-colors;
  • php-cs-with-cache:php-cs的别名变体,标记为stages: [manual],配合--cache=.cache/pre-commit/dolibarr-php-cs.cache缓存并扫描全仓库,供 CI 使用;
  • php-lint:对所有 PHP 文件做语法检查(php -l),排除 symfony var-dumper 测试目录;
  • php-stan:PHPStan 检查(stages: [manual]),同样只针对 PHP 文件。

其中php-cs与php-cbf使用的ruleset.xml位于 dev/setup/codesniffer/ruleset.xml,它定义了名为Dolibarr的完整代码规范,要点包括:

  • 统一使用4 空格 + Tab 缩进(tab-width=4);
  • 行尾必须是 Unix\n(LF),禁止 BOM(Generic.Files.ByteOrderMark),行长度限制宽松(lineLimit=800);
  • 禁止短开标签、禁止null/true/false使用大写、禁止过时的 PHP 函数、禁止@错误抑制符告警(该告警被降级为 0 不显示);
  • 要求类注释与函数注释(PEAR.Commenting.ClassComment、PEAR.Commenting.FunctionComment),但将许多误报率高的子规则降级为 0;
  • 复杂度阈值放宽到环复杂度 250、绝对 500、嵌套 12/50,以适应 Dolibarr 大量历史业务代码;
  • 通过<rule ref="codesniffer.Dolibarr.LanguageOfComments"/>与codesniffer.Dolibarr.CheckIsModEnabledArgument引用位于 dev/setup/codesniffer 目录下的自定义 PHPCS 嗅探器,强制注释语言、isModEnabled()参数使用等 Dolibarr 特有约定;
  • 排除第三方与生成代码目录:/htdocs/(custom|includes)/、/htdocs/install/doctemplates/websites、/dev/build/、/documents/、.cache、.git等。

静态分析:PHPStan 与 Phan(默认关闭,需手动开启)

.pre-commit-config.yaml 中声明了两个本地钩子,用于在提交前运行 PHP 静态分析:

  • php-stan:入口为 dev/tools/phpstan/allow_phpstan_in_precommit.sh;
  • phan:入口为 dev/tools/phan/allow_phan_in_precommit.sh。

这两个脚本的设计思想完全一致:默认跳过、按需开启。脚本首先检查~/.run-phpstan/~/.run-phan标记文件是否存在,不存在就直接输出 "Skipping" 并以 0 退出;随后检查~/vendor/bin/phpstan/~/vendor/bin/phan是否安装。也就是说,如果你想启用这两项重量级检查,需要:

# 启用 PHPStan(level 9,最高严格级别,配合 dev/build/phpstan/bootstrap.php 引导) touch ~/.run-phpstan # 启用 Phan touch ~/.run-phan # 不再需要时删除对应标记文件即可

PHPStan 脚本还做了作用域过滤:只分析htdocs/与scripts/下的文件(因为phpstan.neon.dist只覆盖这两个目录),并针对"批量文件中全部被excludePaths排除导致报 No files found to analyse"的情况做了特殊放行处理,避免误阻断提交。

翻译完整性检查(Dolibarr 特色钩子)

Dolibarr 是国际化项目,语言文件多达数千个(仓库htdocs/langs/下约 6070 个.lang文件),因此配置中专门为翻译文件设计了多个钩子:

  • check-translations(默认阶段执行):调用 dev/translation/sanity_check_trans_missing_unused.sh,检查htdocs/langs/en_US/下英文语言文件中是否存在缺失、未使用或重复的翻译键;
  • duplicate-lang-lines/duplicate-lang-keys(manual):分别调用 dev/tools/fixduplicatelanglines.sh 与 dev/tools/fixduplicatelangkey.sh,找出重复的翻译行/键;
  • fix-alt-languages(manual):调用 dev/tools/fixaltlanguages_pre-commit.sh,按语言前缀正则匹配所有非英文语言文件并同步修复。

本地扩展脚本:local.sh

配置末尾的local-precommit-script钩子是一个巧妙的扩展点:

- id: local-precommit-script name: Run local script before commit if it exists language: system entry: bash -c '[ ! -x local.sh ] || ./local.sh' pass_filenames: false

它检查仓库根目录是否存在可执行的local.sh,存在则执行。你可以在自己的分支上创建local.sh添加私有检查逻辑,例如配置注释中给出的示例:遍历git diff HEAD --name-only的改动文件,对其运行dev/tools/updatelicense.php更新版权头,且不把改动写入版本库。这是不修改仓库公共配置即可定制个人工作流的推荐做法。

其他可选工具

配置中还以stages: [manual]或注释形式声明了更多可选钩子,可按需手动执行:

  • prettier(pre-commit/mirrors-prettierv3.1.0):格式化非 PHP 的常见文件(排除 php、shell、js、markdown、yaml、css 等大量类型后剩余的文件);
  • yamllint(adrienverge/yamllintv1.38.0):校验 YAML 风格,行宽上限 120;
  • codespell(codespell-project/codespellv2.4.2):拼写纠错,使用 dev/tools/codespell 下的三个词表文件(codespell-dict.txt自定义词典、codespell-ignore.txt忽略词、codespell-lines-ignore.txt忽略行),并针对htdocs/langs/en_US/提供了带专门豁免词的codespell-lang-en_US别名;
  • shellcheck(shellcheck-py/shellcheck-pyv0.11.0.1):检查 Shell 脚本,-W 100设置告警级别;
  • sqlfluff-lint(sqlfluff/sqlfluff4.2.0):检查 SQL 文件语法风格(manual),排除初始化数据 dump、旧迁移脚本、第三方目录等;
  • 被注释掉的beautysh(Shell 美化)、perltidy、perlcritic(Perl 相关,因 virtualmin 场景暂缓)可作为参考但当前未启用。

日常使用:触发、跳过与调试

提交时的工作流

安装钩子后,每次git commit都会自动运行全部默认阶段钩子,首次运行时 pre-commit 会把所需工具下载安装到~/.cache/pre-commit(文档中亦提到运行产物会落到.cache/pre-commit/repo.../pre_commit_hooks/php-....sh等路径)。推荐流程如下:

cd PROJECT_DIR pre-commit install # 只需要执行一次 # 重复直到成功 git commit -a -m "My message" # pre-commit 会运行并给出报告 # 查看结果、修复问题后重新提交(即重复上一行命令)

关键行为(与文档一致):

  • 一旦检查发现问题,git commit 会被中止,让你修复或人工复核;
  • 部分钩子会修改你的代码(phpcbf 格式化 PHP、行尾修复、文件末尾修复等),如果代码被改动,本次提交会被取消,再执行一次git commit即可把修复纳入提交;
  • 钩子还会告警潜在问题:语法错误、拼写错误、代码质量、git 仓库中可执行位设置不当等。

三种跳过方式

场景方法
某次提交完全跳过检查git commit -a -m "My message" --no-verify
仅跳过某个钩子在.git/hooks/pre-commit中导出环境变量:export SKIP=no-commit-to-branch(也可写成SKIP=no-commit-to-branch git commit -a -m "My message"单次生效;SKIP 支持逗号分隔多个钩子 id)
永久跳过某个钩子在~/.bashrc或当前会话中export SKIP=no-commit-to-branch

注意文档给出的 SKIP 示例针对的是no-commit-to-branch钩子——如果你正在自定义分支名(而非develop或x.0版本分支)上开发,该钩子本就不会触发;若确实需要在保护分支上临时提交,才用上述方式跳过。

输出与颜色控制

在.git/hooks/pre-commit文件中设置:

export PRE_COMMIT_COLOR=never

可以关闭彩色输出、切换为纯文本,便于在 CI 日志或纯文本终端中阅读。

手动运行与调试

除了依赖 git 提交触发,pre-commit 支持手动执行全部或单个钩子,这在排查问题时非常有用:

# 手动运行所有默认钩子(-a 表示对全部文件而不是仅暂存文件) pre-commit run -a # 手动运行单个钩子 pre-commit run php-cs -a # 运行 manual 阶段的钩子(如 SQL 检查、静态分析、缓存版 PHPCS) pre-commit run --hook-stage manual -a sqlfluff-lint pre-commit run --hook-stage manual -a php-cs-with-cache pre-commit run --hook-stage manual actionlint

CI 如何复用同一套钩子

pre-commit 的价值不仅在于本地拦截,也在于与 CI 共享同一份配置,保证本地与流水线检查结果一致。Dolibarr 在 .github/workflows/pre-commit.yml 中实现了这一点,核心思路:

  • CI 先以--show-diff-on-failure --color=always --all-files运行一遍pre-commit run,任何失败都会展示修复后的 diff,便于定位;
  • 随后对改动文件运行pre-commit run php-cs(针对 PHP 代码规范);
  • 最后以--hook-stage manual运行php-cs-with-cache(带缓存的全量 PHPCS 检查)与sqlfluff-lint(SQL 检查),把重量级/手动阶段的检查也纳入流水线。

这正对应文档结尾的结论:本地提交时提前暴露问题后,"你的提交在 GitHub 的 Continuous Integration(CI)运行中更不容易失败——CI 同样运行 pre-commit 以维护代码质量"。

常见故障排查(Troubleshooting)

ModuleNotFoundError: No module named 'platformdirs'

pre-commit 的 Python 环境缺少依赖:

pip3 install platformdirs # 或(系统级强制安装) pip3 install platformdirs --break-system-packages

ModuleNotFoundError: No module named 'pkg_resources'

pkg_resources属于 setuptools,在部分 Python 3.12+ 环境中不再随解释器提供:

pip3 install pkg_resources # 或 pip3 install pkg_resources --break-system-packages

ERROR: PHP_CodeSniffer requires the tokenizer, xmlwriter and SimpleXML extensions to be enabled. Please enable xmlwriter and SimpleXML.

PHP_CodeSniffer 需要 PHP 的 tokenizer、xmlwriter 与 SimpleXML 扩展,缺少时安装 PHP 的 xml 相关包:

sudo apt install php-simplexml

(若你使用第三方 PPA 或发行版,php-simplexml包名可能略有差异,以发行版软件源为准。)

总结

Dolibarr 的 pre-commit 体系可以概括为三层防护:第一层是通用仓库卫生钩子(行尾、空白、BOM、冲突标记、大小写冲突),保证任何语言的提交都干净整洁;第二层是语言专项检查(phpcs/phpcbf + Dolibarr 自定义 ruleset、gitleaks 秘密扫描、翻译完整性),保证 PHP 代码与国际化资产符合项目规范;第三层是可选的高阶静态分析(PHPStan level 9、Phan、SQL、ShellCheck、Prettier、yamllint 等,多数以manual阶段或标记文件开关形式按需启用),在 CI 中再以全量模式兜底。配合local.sh扩展点与--no-verify/SKIP/PRE_COMMIT_COLOR等控制手段,你可以在不牺牲灵活性的前提下,把"提交前质量门禁"无缝嵌入 Dolibarr 的日常开发流程。

  • 企业应用
  • 后端

【免费下载链接】dolibarr

Dolibarr ERP CRM is a modern software package to manage your company or foundation's activity (contacts, suppliers, invoices, orders, stocks, agenda, accounting, ...). it's an open source Web application (written in PHP) designed for businesses of any sizes, foundations and freelancers.

项目地址:https://gitcode.com/gh_mirrors/do/dolibarr
点击查看免费下载
上一篇:如何在5分钟内快速搭建MQTT.js物联网通信系统:完整指南
下一篇:能源消耗预测模型:用Python机器学习构建智能能源管理系统

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 7:21:19

校园AI助手落地实践:RAG+Agent+MCP教育场景全栈方案

1. 项目概述&#xff1a;这不是一个“玩具级”Demo&#xff0c;而是一套可落地的校园服务闭环你有没有遇到过这样的场景&#xff1a;新生入学前反复翻看教务系统&#xff0c;却找不到某门课的先修要求&#xff1b;研究生想选导师&#xff0c;但官网简介千篇一律&#xff0c;看不…

作者头像 李华
网站建设 2026/9/28 7:19:28

Keil STM32外设窗口消失?5类问题排查与修复方法

用Keil做STM32仿真调试&#xff0c;最让人头大的一类问题不是编译报错&#xff0c;而是明明已经进入了调试界面&#xff0c;Peripherals外设窗口却怎么都找不到了。这个窗口对于新手来说几乎是“透视眼”&#xff0c;不打开它&#xff0c;你只能靠猜去看外设寄存器到底有没有变…

作者头像 李华
网站建设 2026/9/28 7:19:02

二分查找深度解析:边界条件与循环不变量一次讲透

1. 为什么一道二分查找值得单独写一篇做了九天算法打卡&#xff0c;前八天都在跟数组的基本遍历、插入、删除打交道&#xff0c;到了第四天正式开始接触第一种真正意义上的查找算法。704这道题&#xff0c;题面一句话就能看完&#xff1a;给定一个升序整数数组和一个目标值&…

作者头像 李华
网站建设 2026/9/28 7:18:40

用Dify搭建智能复盘分析工作台:让大模型帮你沉淀团队经验

1. 项目概述1.1 从“事后诸葛亮”到“事前明白人”&#xff1a;这个项目在做什么“hindsight”这个词&#xff0c;直译是“后见之明”&#xff0c;说白了就是“事后诸葛亮”。但有意思的是&#xff0c;我这次想做的项目&#xff0c;恰恰是要把这个“事后”的能力往前挪一挪——…

作者头像 李华