test: backport tests Python lint to 2.6 (#49618)

pr: #49130

Backport tests Python lint support to the 2.6 branch so PRs that touch
tests/**/*.py can run the Python Lint (tests/) workflow.

What changed:
- Add .github/workflows/python-lint.yaml.
- Add tests/Makefile for local CI parity.
- Add tests/ruff.toml for the workflow and local Ruff runs.

Verification:
- git diff --check
- uvx ruff@0.15.11 check --exit-zero tests/scripts

Signed-off-by: zhuwenxing <wenxing.zhu@zilliz.com>
This commit is contained in:
zhuwenxing
2026-05-09 11:04:07 +08:00
committed by GitHub
parent 7c1cf59d5a
commit b314d378bb
3 changed files with 187 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
name: Python Lint (tests/)
on:
push:
branches:
- master
paths:
- 'tests/**/*.py'
- 'tests/ruff.toml'
- '.github/workflows/python-lint.yaml'
pull_request:
paths:
- 'tests/**/*.py'
- 'tests/ruff.toml'
- '.github/workflows/python-lint.yaml'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
ruff:
name: Ruff (changed files only)
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed Python files under tests/
id: changed
uses: tj-actions/changed-files@v46
with:
files: tests/**/*.py
- name: ruff check
if: steps.changed.outputs.any_changed == 'true'
uses: astral-sh/ruff-action@v4.0.0
with:
version: "0.15.11"
src: ${{ steps.changed.outputs.all_changed_files }}
- name: ruff format --check
if: steps.changed.outputs.any_changed == 'true'
uses: astral-sh/ruff-action@v4.0.0
with:
version: "0.15.11"
src: ${{ steps.changed.outputs.all_changed_files }}
args: "format --check --diff"
- name: Validate ruff configuration (smoke test)
# Always runs so config-only PRs still catch a broken ruff.toml.
# --exit-zero ignores existing baseline violations; only fails when
# ruff cannot load the config at all.
uses: astral-sh/ruff-action@v4.0.0
with:
version: "0.15.11"
src: "tests/scripts"
args: "check --exit-zero"
+95
View File
@@ -0,0 +1,95 @@
# tests/Makefile — lint helpers for Python files under tests/.
#
# All targets operate on the *PR-changed* set: files under tests/**/*.py that
# differ between $(BASE_REF) and HEAD (three-dot diff = since merge-base),
# matching the GitHub Actions "Python Lint (tests/)" workflow.
#
# Usage (run from this tests/ directory):
# make lint # ruff check (CI equivalent)
# make format-check # ruff format --check (CI equivalent)
# make ci # lint + format-check
# make lint-fix # ruff check --fix
# make format # ruff format
#
# Variables:
# BASE_REF diff base ref. Auto-detected from the current branch's open PR
# via `gh pr view`. If no PR exists, you MUST set it explicitly,
# e.g.: make ci BASE_REF=origin/master
# RUFF_VERSION ruff version (default: 0.15.11, pinned to .github/workflows/python-lint.yaml)
#
# Requires `uvx` (ships with `uv`). Ruff is fetched & cached on first run.
# Auto-detection requires `gh` authenticated (`gh auth status`).
RUFF_VERSION ?= 0.15.11
RUFF := uvx ruff@$(RUFF_VERSION)
REPO_ROOT := $(shell git rev-parse --show-toplevel)
# Auto-detect the base ref from the current branch's open PR.
# Steps:
# 1. Read the PR URL (always lives under the base repo) and base branch via gh.
# Extract base repo as "<owner>/<name>" from the URL path.
# 2. Find which local remote points to that base repo (must NOT assume "origin"
# — for forks, "upstream" is typically the base; for direct clones, "origin").
# 3. Emit "<remote>/<baseRefName>".
# Empty when no PR exists, no remote matches, or gh is unauthenticated —
# user must then set BASE_REF explicitly.
BASE_REF ?= $(shell \
pr_url=$$(gh pr view --json url -q .url 2>/dev/null); \
base_branch=$$(gh pr view --json baseRefName -q .baseRefName 2>/dev/null); \
if [ -z "$$pr_url" ] || [ -z "$$base_branch" ]; then exit 0; fi; \
base_repo=$$(echo "$$pr_url" | sed -E 's|^https?://[^/]+/([^/]+/[^/]+)/.*|\1|'); \
if [ -z "$$base_repo" ]; then exit 0; fi; \
remote=$$(git -C $(REPO_ROOT) remote -v | awk -v p="$$base_repo" 'index($$2, p) > 0 && $$3=="(fetch)" {print $$1; exit}'); \
if [ -z "$$remote" ]; then exit 0; fi; \
echo "$$remote/$$base_branch")
CHANGED_FILES_CMD = git -C $(REPO_ROOT) diff --name-only --diff-filter=ACMR $(BASE_REF)...HEAD -- 'tests/**/*.py'
.PHONY: help lint format-check ci lint-fix format _require-base-ref
help:
@echo "tests/ Makefile — lint PR-changed *.py using ruff $(RUFF_VERSION)"
@echo
@echo "Targets:"
@echo " make lint ruff check (CI equivalent)"
@echo " make format-check ruff format --check (CI equivalent)"
@echo " make ci lint + format-check"
@echo " make lint-fix ruff check --fix"
@echo " make format ruff format"
@echo
@echo "BASE_REF: auto-detected from the current branch's open PR via 'gh pr view'."
@echo " When no PR exists, you must set it explicitly:"
@echo " make ci BASE_REF=origin/master"
@if [ -n "$(BASE_REF)" ]; then echo; echo "Currently detected: BASE_REF=$(BASE_REF)"; \
else echo; echo "Currently: BASE_REF is unset (no open PR detected)."; fi
_require-base-ref:
@if [ -z "$(BASE_REF)" ]; then \
echo "Error: BASE_REF is not set."; \
echo " No open PR detected for the current branch via 'gh pr view'."; \
echo " Set it explicitly, e.g.:"; \
echo " make $(or $(MAKECMDGOALS),ci) BASE_REF=origin/master"; \
exit 1; \
fi
lint: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) check $$files; fi
format-check: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) format --check --diff $$files; fi
ci: lint format-check
lint-fix: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) check --fix $$files; fi
format: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) format $$files; fi
+32
View File
@@ -0,0 +1,32 @@
line-length = 120
target-version = "py310"
extend-exclude = [
".venv",
"__pycache__",
"assets",
"*.ipynb_checkpoints",
]
[lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"W", # pycodestyle warnings
"I", # isort
"UP", # pyupgrade
]
ignore = [
"E501", # line-too-long handled by formatter
"E741", # ambiguous variable names (l, I, O) common in test code
]
[lint.per-file-ignores]
"__init__.py" = ["F401", "F403"]
"conftest.py" = ["F401", "F811"]
"**/testcases/**/*.py" = ["E402"]
"**/chaos/**/*.py" = ["E402"]
[format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"