diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a07cc4b..c30d00e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,25 @@ jobs: done } | sort -u | xargs -d '\n' shellcheck --severity=error --exclude=SC2148 + ruff: + name: Ruff + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + # Pinned to an exact release: unlike actions/checkout, ruff-action + # publishes no moving major tag past v3, so @v4 does not resolve. + - uses: astral-sh/ruff-action@v4.1.0 + with: + # There is no pyproject.toml for the action to read a version from, + # so pin it here: an unpinned ruff would resolve to `latest` and a + # new release could turn a green branch red on its own. Bump this + # deliberately, together with the rule set in ruff.toml. + version: 0.15.21 + # Rule selection, file discovery (the many extensionless Python + # executables) and exclusions all live in ruff.toml, so the whole + # workspace can be handed over as-is. + args: check --output-format=github + python-compileall: name: Python compileall runs-on: ubuntu-latest diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..5c19ab7d --- /dev/null +++ b/ruff.toml @@ -0,0 +1,71 @@ +# Ruff configuration for confluent. +# +# py37 is the oldest version ruff can target. The oldest interpreter parts of +# this tree still run on is 3.6 (el8, sles15) +target-version = "py37" + +line-length = 120 + +# Ruff discovers *.py only: it does not read shebangs when walking a tree, so +# without the patterns below it silently skips every CLI tool in +# confluent_client/bin and confluent_server/bin, the osdeploy deploy scripts, +# and the loose misc/ utilities. +# Some of the osdeploy scripts carry no shebang at all. +extend-include = [ + "confluent_client/bin/*", + "confluent_server/bin/*", + # Generated into setup.py at build time by makesetup; #VERSION# only ever + # appears inside a string literal, so the template itself is valid Python. + "**/setup.py.tmpl", + "imgutil/imgutil", + "misc/filterpasswd", + "misc/getipsfromswitchport", + "misc/getusbnicaddr", + # confluent_osdeploy: per-profile deploy scripts, matched by name because + # each profile directory mixes Python and shell. + "**/bfb-autoinstall", + "**/nodedeploy-bfb", + "**/opt/confluent/bin/apiclient", + "**/scripts/add_local_repositories", + "**/scripts/autoconsole", + "**/scripts/configbmc", + "**/scripts/confignet", + "**/scripts/getinstalldisk", + "**/scripts/makeksnet", + "**/scripts/mergetime", + "**/scripts/syncfileclient", +] + +extend-exclude = [ + # Shell scripts that live in the directories included wholesale above. + "*.sh", +] + +# Honour exclusions even when CI passes an explicit file list. +force-exclude = true + +# `ruff format` is deliberately not adopted: the tree uses single quotes almost +# everywhere and reformatting it would bury real changes. Preserve quotes so an +# accidental run does less damage. +[format] +quote-style = "preserve" + +[lint] +select = [ + "E9", # unparseable file + "F63", # `is` against a literal, assert on a tuple, bad print/if-tuple + "F7", # statements in impossible positions: return/yield outside a + # function, break/continue outside a loop, except clause not last + "F81", # redefinition of an unused name (shadowed def/class) + "F82", # undefined name, undefined name in __all__, use before assignment + "F402", # import shadowed by a loop variable + "PLE", # pylint errors: bad string format, invalid returns, ... + "T100", # forgotten pdb/breakpoint call + "W6", # invalid escape sequence in a non-raw string, and any future + # deprecated-construct warning pycodestyle adds + "B020", # loop control variable overrides the iterable it iterates + "B035", # dict comprehension with a static key +] + +# No ignores and no per-file exemptions: every rule selected above is expected +# to stay at zero on its own.