预提交检查如何在本地失败但在 CI 服务器上通过?

问题描述 投票:0回答:1

我的开发机器上有一个干净的分支工作树。如果我运行

pre-commit run --all-files
我的格式化程序挂钩失败,会重新格式化一些文件。我的 CI 服务器(Atlassian Bamboo)也在同一个分支上运行
pre-commit run --all-files
,但钩子通过了,这是意外的。我可以检查什么来找出原因?

作为示例,我将以下行添加到 Python 文件中:

unused = 1+1

我有一个用于格式化的黑色钩子和一个用于掉毛的皱褶钩子。本地输出为:

black....................................................................Failed
- hook id: black
- files were modified by this hook

reformatted tasks/tool.py

All done! ✨ 🍰 ✨
1 file reformatted, 1878 files left unchanged.

ruff.....................................................................Failed
- hook id: ruff
- exit code: 1

tasks/tool.py:76:5: F841 [*] Local variable `unused` is assigned to but never used
Found 1 error.
[*] 1 potentially fixable with the --fix option.

这正如预期的那样——黑色会将行重新格式化为

unused = 1 + 1
(加号运算符周围的空格),并且 ruff 正确地识别出
unused
未使用。

但是,在 CI 服务器上,输出是:

black....................................................................Passed
ruff.....................................................................Failed
- hook id: ruff
- exit code: 1

tasks/tool.py:76:5: F841 [*] Local variable `unused` is assigned to but never used
Found 1 error.
[*] 1 potentially fixable with the --fix option.

意想不到的传球并不是黑色独有的。我还有 mdformat 和 clang-format 的钩子,它们也在本地失败并在 CI 服务器上意外通过。

我尝试过的事情:

  • 在两个地方添加了对
    pre-commit --version
    的调用,以确保它们相同 (3.3.3)
  • 在两个地方添加了对
    pre-commit clean
    的调用,以确保钩子不会出现一些奇怪的缓存问题
  • 添加了身份挂钩以确保文件不会以某种方式被过滤掉

我还可以采取哪些其他措施来追踪此情况?

这是我的(经过精简但希望仍然有效/具有代表性)预提交-config.yaml:

default_language_version:
    python: python3.10

exclude: >
    (?x)^(
        acceptance/.*|
        build/.*|
        deploy/.*
    )$

repos:

-   repo: https://github.com/PyCQA/docformatter
    rev: v1.1
    hooks:
        -   id: docformatter
            alias: reformat-docs
            types: [python]
            args:
                - --in-place

-   repo: https://github.com/psf/black
    rev: "23.3.0"
    hooks:
        -   id: black
            alias: reformat
            types: [python]

-   repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.0.292
    hooks:
        - id: ruff
          alias: lint
          types: [python]

-   repo: https://github.com/executablebooks/mdformat
    rev: "0.7.16"
    hooks:
    -   id: mdformat
        description: Auto-format Markdown files.
        args: [--wrap=88, --number]
        additional_dependencies:
        - mdformat-gfm==0.3.5
        - mdformat-tables==0.4.1
        - mdformat-black==0.1.1
        - linkify-it-py==2.0.2

-   repo: https://github.com/adrienverge/yamllint.git
    rev: v1.29.0
    hooks:
        -   id: yamllint
            description: This hook runs yamllint.
            entry: yamllint
            language: python
            types: [file, yaml]
            args:
                - -c
                - yamllint-config.yml
                - --no-warnings

-   repo: https://github.com/pre-commit/mirrors-clang-format
    rev: v16.0.6
    hooks:
        -   id: clang-format
            types_or: [c++, c]

-   repo: meta
    hooks:
    -   id: identity
        types: [python]
pre-commit.com
1个回答
0
投票

根据文档,预提交挂钩“必须在失败或修改文件时退出非零”。如果一个钩子意外通过,它应该与这两件事之一有关。

以 black 为例,除非通过 --check 标志,否则即使重新格式化文件,它也会以 0 退出。因此,预提交必须依赖于检测文件已更改以使挂钩失败。

预提交如何知道文件是否更改?它在前后使用 git diff

 并比较两次运行的标准输出。如果它们不同,则必须进行更改。

将相同的

git diff

 命令添加到我的构建脚本中,我发现它在 CI 服务器上失败并打印错误消息。据推测,预提交也出现了错误,但前后消息相同,导致未检测到更改而“通过”。看起来预提交并没有检查 
git diff
 的退出代码。

在我的例子中,由于 Bamboo 的链接存储库功能和 Docker 容器未挂载 Bamboo 的缓存目录的组合,

git diff

 失败了。错误看起来像:

error: object directory /opt/bamboo-home/alpha/xml-data/build-dir/_git-repositories-cache/fdae2edae02caea8ea6d761ec2587a93d46f063d/.git/objects does not exist; check .git/objects/info/alternates. error: unable to find e6ce93b6af518f7e3efd767aa7124aed5d036734 fatal: unable to read e6ce93b6af518f7e3efd767aa7124aed5d036734
    
© www.soinside.com 2019 - 2024. All rights reserved.