【Bug已解决】CI fails for code quality check: No such file or directory: ‘ruff‘ 解决方案

📅 2026/7/21 22:01:44
【Bug已解决】CI fails for code quality check: No such file or directory: ‘ruff‘ 解决方案
【Bug已解决】CI fails for code quality check: No such file or directory: ruff 解决方案一、现象长什么样仓库的 CI 里有一条代码质量检查lint调用ruff做静态检查。某次改动后这条 CI 直接挂/bin/sh: 1: ruff: not found No such file or directory: ruff或者更隐蔽地用subprocess.run([ruff, ...])时FileNotFoundError: [Errno 2] No such file or directory: ruff现象特征只在 CI 失败本地ruff跑得好好的——因为本地你用pipx/pip install ruff装过PATH 里有CI 的干净环境里没装有时是偶发CI 用了缓存或某个 base image 里刚好有 ruff 的旧版本换了 runner 后又没了报错发生在执行 ruff这一步说明调用命令本身没问题是运行环境里找不到这个可执行文件。这是典型的把 CLI 工具当成环境自带的 CI 配置缺漏脚本假定ruff一定在 PATH 上但没保证它真的被安装。二、背景ruff是 Python 的 lint/格式化工具有两种常见调用方式直接当可执行ruff check ./ruff format --check .——要求ruff在 PATH 上作为 Python 模块python -m ruff check .——要求ruff作为包被安装到当前 Python 环境。CI 里常见两种失败原因依赖没装CI 的requirements/pyproject的 dev 依赖里没列ruffrunner 干净环境就没有它用了可执行但装成了模块只pip install ruff装成模块python -m ruff可用脚本却写ruff依赖 PATH 上的可执行而pip install不一定把可执行链接进 PATH取决于环境/隔离于是ruff找不到版本漂移本地 ruff 新版CI 旧版或反之规则不一致甚至某些规则名变了导致找不到规则式报错——但本题是更直接的文件不存在。核心问题CI 把ruff的存在当成前提却没在 CI 流程里显式保证它存在。三、根因根因一句话CI 的代码质量检查脚本直接调用ruff可执行文件但 CI 环境没有安装/暴露ruff既没列进依赖也没用python -m ruff这种依赖已安装包的方式调用导致执行时FileNotFoundError: ruff。具体依赖缺口ruff不在 CI 安装的依赖清单里或只在本地 dev 环境没进 CI 用的 lockfile调用方式脆弱脚本写死ruff ...依赖 PATH 可执行而不是python -m ruff ...后者只要包装了就可用不依赖 PATH 链接环境不可复现本地有、CI 没有因为本地和 CI 的依赖来源不同步报错早、阻塞大lint 是门禁ruff 找不到直接整条质量检查红连带可能阻断合并。本质是工具可用性没在 CI 里被显式保证。四、最小可运行复现下面用纯 Python 模拟可执行不存在的两种调用方式的差异import subprocess import sys def run_as_executable(): 旧方式直接调 ruff 可执行依赖 PATH。 try: return subprocess.run([ruff, --version], checkTrue, capture_outputTrue) except FileNotFoundError as e: return f失败: {e} def run_as_module(): 更稳方式python -m ruff依赖包已安装。 try: return subprocess.run([sys.executable, -m, ruff, --version], checkTrue, capture_outputTrue) except FileNotFoundError as e: return f失败: {e}说明包也没装 def demo(): print(直接可执行:, run_as_executable()) print(python -m:, run_as_module()) if __name__ __main__: demo()如果环境里ruff没装第一行抛FileNotFoundError: ruff和线上一致第二行如果包装了也会成功没装才失败。复现了直接调可执行在干净环境里找不到的核心问题也提示了修复方向——用python -m ruff或确保安装。五、解决方案第一层保证 CI 安装 ruff进依赖清单第一层最稳妥把ruff显式加进 CI 用的依赖保证它一定存在# pyproject.toml 的 dev 依赖或 requirements-dev.txt [project.optional-dependencies] dev [ ruff0.5.0, # 显式固定下限避免版本漂移 ]CI 步骤里先装# .github/workflows/quality.yml - name: Install dev deps run: pip install -e .[dev] # 或 pip install ruff - name: Lint run: ruff check .或者最小改动单独装- name: Install ruff run: pip install ruff0.5.0 - name: Lint run: ruff check .关键是ruff 不再依赖本地恰好装过而是 CI 自己安装环境可复现。六、解决方案第二层改用python -m ruff去掉 PATH 依赖第一层保证了包被安装第二层再让调用方式不依赖 PATH 链接更稳# 用 python -m ruff只要包装了就能调不要求可执行在 PATH - name: Lint run: python -m ruff check . - name: Format check run: python -m ruff format --check .同时在项目脚本里也统一import subprocess, sys def run_ruff(path.): # 统一用 python -m ruff避免 PATH 上找不到可执行 return subprocess.run([sys.executable, -m, ruff, check, path], checkTrue) if __name__ __main__: run_ruff()python -m ruff的好处它解析的是当前sys.executable对应的环境里装的 ruff 包只要pip install ruff进了这个环境就 100% 可用不受 PATH 链接、venv 激活状态影响。配合第一层的显式安装双重保险。七、解决方案第三层CI 预检 锁版本 缓存第三层加健壮性避免偶发找不到和版本漂移# 1) 锁版本避免本地新/CI 旧导致规则不一致 - name: Install pinned ruff run: pip install ruff0.6.9 # 2) 预检真正执行前先确认可用给出友好报错 - name: Preflight ruff run: python -m ruff --version # 3) 缓存 pip加速且避免偶发网络失败导致没装上 - uses: actions/setup-pythonv5 with: python-version: 3.11 cache: pip本地也加个Makefile/tox统一入口保证本地跑的和 CI 跑的是同一套.PHONY: lint lint: python -m ruff check . python -m ruff format --check .这样开发者本地make lint与 CI 调用完全一致本地能过 CI 必过在同样版本下消除本地绿 CI 红的落差。八、落地建议如果你在 CI 遇到 No such file or directory: ruff建议加依赖把ruff显式写进 dev 依赖 / requirements固定版本下限。改调用脚本和 CI 都用python -m ruff去掉 PATH 依赖。锁版本固定ruffx.y.z避免规则漂移。加缓存pip 缓存加速避免偶发安装失败。统一入口Makefile/tox让本地与 CI 一致。预检CI 先python -m ruff --version确认可用。九、排查清单如果 CI 报 No such file or directory: ruff按顺序查确认 ruff 是否在 CI 安装的依赖里没有就加进 dev 依赖/requirements。看调用方式脚本是ruff还是python -m ruff前者依赖 PATH改后者更稳。确认 CI 装了依赖pip install 步骤有没有包含 ruff或单独pip install ruff。锁版本本地与 CI ruff 版本是否一致规则差异会导致误报。加预检CI 先python -m ruff --version early fail。本地复现用干净 venvpython -m ruff check .确认本地和 CI 一致。看缓存/网络偶发失败可能是安装阶段网络问题加 pip 缓存。十、小结CI 报No such file or directory: ruff根因是代码质量检查脚本直接调用ruff可执行文件但 CI 的干净环境里既没有把ruff装进依赖清单也没有用python -m ruff这种依赖已安装包的方式调用于是执行时找不到这个可执行文件。它只在 CI 暴露本地你装过所以有属于工具可用性没在 CI 里被显式保证的配置缺漏。修复分三层第一层把ruff显式加进 CI 依赖并固定版本下限保证一定被安装第二层把调用统一改成python -m ruff去掉对 PATH 上可执行链接的依赖只要包装了就可用第三层加版本锁定、pip 缓存和make lint统一入口消除本地绿 CI 红的版本/环境落差并加预检 early fail。核心心法是CI 里调用的任何 CLI 工具都不能假设它环境自带——必须显式安装进依赖、并用不依赖 PATH 的方式调用python -m才能保证环境可复现、构建稳定。