/ .pre-commit-config.yaml
.pre-commit-config.yaml
  1  minimum_pre_commit_version: 4.0.1
  2  repos:
  3    - repo: https://github.com/pre-commit/pre-commit-hooks
  4      rev: c4a0b883114b00d8d76b479c820ce7950211c99b # v4.5.0
  5      hooks:
  6        - id: trailing-whitespace
  7          files: \.(mdx|ya?ml|txt)$
  8        - id: end-of-file-fixer
  9          files: \.(txt|sh|rst)$
 10          exclude: ^examples/|^mlflow/protos/opentelemetry/
 11        - id: check-vcs-permalinks
 12          files: \.py$
 13          require_serial: true
 14    - repo: https://github.com/pre-commit/mirrors-prettier
 15      rev: "50c5478ed9e10bf360335449280cf2a67f4edb7a" # v2.7.1
 16      hooks:
 17        - id: prettier
 18          files: '^(?!docs/|mlflow/server/js/|libs/typescript/).+\.(js|ts|md|json|ya?ml)$'
 19          require_serial: true
 20  
 21    - repo: local
 22      hooks:
 23        - id: uv-lock
 24          name: uv-lock
 25          entry: uv lock
 26          language: system
 27          files: '^pyproject\.toml$'
 28          stages: [pre-commit]
 29          require_serial: true
 30          pass_filenames: false
 31  
 32        - id: normalize-chars
 33          name: normalize-chars
 34          entry: uv run --frozen --only-group lint dev/normalize_chars.py
 35          language: system
 36          stages: [pre-commit]
 37          types: [text]
 38          exclude: '^mlflow/server/js/|^docs/api_reference/source/R-api\.rst$'
 39          require_serial: true
 40  
 41        - id: ruff
 42          name: ruff
 43          entry: uv run --frozen --only-group lint dev/ruff.py
 44          language: system
 45          files: '\.(py|ipynb)$'
 46          stages: [pre-commit]
 47          require_serial: true
 48  
 49        - id: format
 50          name: format
 51          entry: uv run --frozen --only-group lint dev/format.py
 52          language: system
 53          files: '\.(py|ipynb|md|mdx)$'
 54          stages: [pre-commit]
 55          require_serial: true
 56  
 57        - id: mypy
 58          name: mypy
 59          language: system
 60          files: |
 61            (?x)^(
 62              dev/.*\.py|
 63              \.claude/skills/.*\.py
 64            )$
 65          exclude: |
 66            (?x)^(
 67              dev/gen_rest_api\.py|
 68              dev/proto_plugin\.py|
 69              dev/set_matrix\.py|
 70              dev/update_ml_package_versions\.py|
 71              dev/proto_to_graphql/.*\.py|
 72              dev/tests/.*\.py|
 73              dev/benchmarks/gateway/fake_server\.py|
 74              dev/benchmarks/gateway/benchmark\.py|
 75              dev/benchmarks/gateway/run\.py
 76            )$
 77          entry: uv run --frozen --only-group lint mypy
 78          require_serial: true
 79  
 80        - id: unresolved-import
 81          name: unresolved-import
 82          # Run `ty` to detect broken internal `mlflow.*` imports. Third-party
 83          # unresolved imports (optional deps) are filtered out via grep.
 84          entry: |
 85            bash -c '
 86              out=$(uv run --frozen --only-group lint ty check \
 87                --ignore all \
 88                --error unresolved-import \
 89                --output-format concise \
 90                mlflow/ 2>&1)
 91              bad=$(echo "$out" | grep "Module \`mlflow" || true)
 92              if [ -n "$bad" ]; then
 93                echo "$bad"
 94                exit 1
 95              fi
 96            '
 97          language: system
 98          pass_filenames: false
 99          files: ^mlflow/.*\.py$
100          stages: [pre-commit]
101          require_serial: true
102  
103        - id: clint
104          name: clint
105          entry: uv run --frozen --only-group lint clint
106          language: system
107          files: '\.(py|ipynb|rst|mdx?)$'
108          stages: [pre-commit]
109          require_serial: true
110  
111        - id: install-bin
112          name: install-bin
113          entry: uv run --frozen --only-group lint bin/install.py
114          language: system
115          stages: [pre-commit]
116          require_serial: true
117          pass_filenames: false
118  
119        - id: taplo
120          name: taplo
121          entry: bin/taplo format
122          language: system
123          files: '\.toml$'
124          stages: [pre-commit]
125          require_serial: true
126  
127        - id: must-have-signoff
128          name: must-have-signoff
129          entry: 'grep "Signed-off-by:"'
130          language: system
131          stages: [prepare-commit-msg]
132          require_serial: true
133  
134        - id: mlflow-typo
135          name: mlflow-typo
136          entry: dev/mlflow-typo.sh
137          language: system
138          stages: [pre-commit]
139          require_serial: true
140  
141        - id: check-mlflow-ui
142          name: check-mlflow-ui
143          entry: |
144            bash -c '
145              if bin/rg "mlflow ui" --line-number --with-filename "$@"; then
146                echo
147                echo "Error - Use \"mlflow server\" instead of \"mlflow ui\""
148                exit 1
149              fi
150            ' --
151          language: system
152          stages: [pre-commit]
153          require_serial: true
154          types: [text]
155          exclude: |
156            (?x)^(
157              \.pre-commit-config\.yaml|
158              CHANGELOG\.md|
159              changelogs/.*|
160              docs/api_reference/source/R-api\.rst|
161              examples/llms/RAG/.*\.(json|csv)|
162              mlflow/cli/__init__\.py|
163              mlflow/R/mlflow/.*|
164              tests/test_cli\.py
165            )$
166  
167        - id: pyproject
168          name: pyproject
169          entry: uv run --frozen --only-group lint dev/pyproject.py
170          language: system
171          stages: [pre-commit]
172          require_serial: true
173          pass_filenames: false
174  
175        - id: mlver
176          name: ml-package-versions-consistency
177          entry: "uv run --frozen --only-group lint dev/update_ml_package_versions.py --skip-yml"
178          files: '^(mlflow/ml-package-versions\.yml|mlflow/ml_package_versions\.py)$'
179          language: system
180          stages: [pre-commit]
181          require_serial: true
182          pass_filenames: false
183  
184        - id: lint-proto
185          name: lint-proto
186          entry: |
187            bash -c '
188              if grep -n "com.databricks.mlflow.api.MlflowTrackingMessage" "$@"; then
189                echo "Remove com.databricks.mlflow.api.MlflowTrackingMessage"
190                exit 1
191              fi
192            ' --
193          files: '\.proto$'
194          language: system
195          stages: [pre-commit]
196          require_serial: true
197  
198        - id: buf
199          name: buf
200          entry: bin/buf format -d -w --exit-code --exclude-path mlflow/protos/opentelemetry mlflow/protos
201          files: '\.proto$'
202          language: system
203          stages: [pre-commit]
204          require_serial: true
205          pass_filenames: false
206  
207        - id: typos
208          name: typos
209          entry: bin/typos --format brief --color never
210          files: '\.(py$|mdx?$)'
211          language: system
212          stages: [pre-commit]
213          require_serial: true
214          pass_filenames: false
215  
216        - id: conftest
217          name: conftest
218          entry: bin/conftest test --namespace mlflow --policy .github/policy.rego
219          files: '^\.github/(workflows|actions)/.*\.ya?ml$'
220          language: system
221          stages: [pre-commit]
222          require_serial: true
223  
224        - id: action-pins
225          name: action-pins
226          entry: uv run --frozen --only-group lint dev/check_action_pins.py
227          language: system
228          files: '^\.github/(workflows|actions)/.*\.ya?ml$'
229          pass_filenames: false
230          stages: [pre-commit]
231          require_serial: true
232  
233        - id: regal
234          name: regal
235          entry: bin/regal lint
236          files: '\.rego$'
237          language: system
238          stages: [pre-commit]
239          require_serial: true
240  
241        - id: check-init-py
242          name: check-init-py
243          entry: uv run --frozen --only-group lint dev/check_init_py.py
244          language: system
245          files: '^(mlflow|tests)/.*\.py$'
246          stages: [pre-commit]
247          require_serial: true
248          pass_filenames: false
249  
250        - id: forbid-gif
251          name: forbid-gif
252          language: fail
253          entry: "Please use MP4 instead of GIF for docs animations"
254          files: ^docs/.*\.gif$
255          stages: [pre-commit]
256  
257        - id: no-yaml
258          name: no-yaml
259          language: fail
260          entry: "Use .yml instead of .yaml"
261          files: ^\.github/(workflows|actions)/.*\.yaml$
262          stages: [pre-commit]
263  
264        - id: check-component-ids
265          name: check-component-ids
266          entry: |
267            bash -c '
268              if ! node .github/actions/check-component-ids/index.js; then
269                echo
270                echo "Auto-regenerating componentId registry..."
271                node .github/actions/check-component-ids/regenerate.js
272                git add .github/actions/check-component-ids/componentId-registry.js
273                exit 1
274              fi
275            '
276          language: system
277          files: ^(mlflow/server/js/src/|\.github/actions/check-component-ids/)
278          stages: [pre-commit]
279          require_serial: true
280          pass_filenames: false
281  
282        - id: js-fmt
283          name: js-fmt
284          entry: dev/js.sh fmt
285          language: system
286          files: ^mlflow/server/js/
287          stages: [pre-commit]
288          require_serial: true
289  
290        - id: no-spaces
291          name: no-spaces
292          language: fail
293          entry: "Filenames must not contain spaces"
294          files: " "