[enh] CI - add shell script formatter

Implement rules and functions to format shell scripts:

    $ make format.shell

or alternatively to format all source code:

    $ make format

The formatter `shfmt` reads the rules from the editorconfig[1]

  If any EditorConfig files are found, they will be used to apply formatting
  options.  If any parser or printer flags are given to the tool, no
  EditorConfig files will be used.

[1] https://github.com/patrickvane/shfmt?tab=readme-ov-file#description

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser 2025-07-16 15:54:54 +02:00 committed by Markus Heiser
parent 7ee3dc9d74
commit 67e423edb2
6 changed files with 48 additions and 20 deletions

View File

@ -14,6 +14,14 @@ charset = utf-8
# code formatter accepts length of 120, but editor should prefer 80 # code formatter accepts length of 120, but editor should prefer 80
max_line_length = 80 max_line_length = 80
[{*.sh,manage}]
indent_style = space
indent_size = 4
# shfmt options
shell_variant = bash
switch_case_indent = true
[*.html] [*.html]
# in the jinja templates we use indent size of 2 and we do not use tabs # in the jinja templates we use indent size of 2 and we do not use tabs
indent_size = 2 indent_size = 2

View File

@ -47,8 +47,8 @@ search.checker.%: install
$(Q)./manage pyenv.cmd searxng-checker -v "$(subst _, ,$(patsubst search.checker.%,%,$@))" $(Q)./manage pyenv.cmd searxng-checker -v "$(subst _, ,$(patsubst search.checker.%,%,$@))"
PHONY += test ci.test test.shell PHONY += test ci.test test.shell
ci.test: test.yamllint test.black test.types.ci test.pylint test.unit test.robot test.rst test.shell test.pybabel ci.test: test.yamllint test.black test.types.ci test.pylint test.unit test.robot test.rst test.shell test.shfmt test.pybabel
test: test.yamllint test.black test.types.dev test.pylint test.unit test.robot test.rst test.shell test: test.yamllint test.black test.types.dev test.pylint test.unit test.robot test.rst test.shell test.shfmt
test.shell: test.shell:
$(Q)shellcheck -x -s dash \ $(Q)shellcheck -x -s dash \
container/entrypoint.sh container/entrypoint.sh
@ -64,6 +64,8 @@ test.shell:
utils/searxng.sh utils/searxng.sh
$(Q)$(MTOOLS) build_msg TEST "$@ OK" $(Q)$(MTOOLS) build_msg TEST "$@ OK"
PHONY += format
format: format.python format.shell
# wrap ./manage script # wrap ./manage script
@ -77,8 +79,8 @@ MANAGE += gecko.driver
MANAGE += node.env node.env.dev node.clean MANAGE += node.env node.env.dev node.clean
MANAGE += py.build py.clean MANAGE += py.build py.clean
MANAGE += pyenv pyenv.install pyenv.uninstall MANAGE += pyenv pyenv.install pyenv.uninstall
MANAGE += format.python MANAGE += format.python format.shell
MANAGE += test.yamllint test.pylint test.black test.pybabel test.unit test.coverage test.robot test.rst test.clean test.themes test.types.dev test.types.ci MANAGE += test.yamllint test.pylint test.black test.pybabel test.unit test.coverage test.robot test.rst test.clean test.themes test.types.dev test.types.ci test.shfmt
MANAGE += themes.all themes.simple themes.fix themes.lint themes.test MANAGE += themes.all themes.simple themes.fix themes.lint themes.test
MANAGE += static.build.commit static.build.drop static.build.restore MANAGE += static.build.commit static.build.drop static.build.restore
MANAGE += nvm.install nvm.clean nvm.status nvm.nodejs MANAGE += nvm.install nvm.clean nvm.status nvm.nodejs

View File

@ -188,24 +188,22 @@ sources of the theme need to be rebuild. You can do that by running::
$ LIVE_THEME=simple make run $ LIVE_THEME=simple make run
.. _make format.python: .. _make format:
``make format.python`` ``make format``
====================== ======================
Format Python source code using `Black code style`_. See ``$BLACK_OPTIONS``
and ``$BLACK_TARGETS`` in :origin:`Makefile`.
.. attention::
We stuck at Black 22.12.0, please read comment in PR `Bump black from 22.12.0
to 23.1.0`_
.. _Bump black from 22.12.0 to 23.1.0:
https://github.com/searxng/searxng/pull/2159#pullrequestreview-1284094735
.. _Black code style: .. _Black code style:
https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html
.. _shfmt: https://github.com/mvdan/sh?tab=readme-ov-file#shfmt
.. _EditorConfig: https://github.com/patrickvane/shfmt?tab=readme-ov-file#description
- Format Python source code using `Black code style`_. See ``$BLACK_OPTIONS``
and ``$BLACK_TARGETS`` in :origin:`Makefile`.
- Format Shell scripts using shfmt_. The formatter ``shfmt`` reads the rules
from the EditorConfig_ files.
.. _make clean: .. _make clean:

View File

@ -27,7 +27,7 @@ Here is how a minimal workflow looks like:
1. *start* hacking 1. *start* hacking
2. *run* your code: :ref:`make run` 2. *run* your code: :ref:`make run`
3. *format & test* your code: :ref:`make format.python` and :ref:`make test` 3. *format & test* your code: :ref:`make format` and :ref:`make test`
If you think at some point something fails, go back to *start*. Otherwise, If you think at some point something fails, go back to *start*. Otherwise,
choose a meaningful commit message and we are happy to receive your pull choose a meaningful commit message and we are happy to receive your pull

15
manage
View File

@ -64,6 +64,12 @@ RST_FILES=(
'README.rst' 'README.rst'
) )
SHFMT_SCRIPTS=(
"./manage"
"./container"
"./utils"
)
help() { help() {
nvm.help nvm.help
cat <<EOF cat <<EOF
@ -90,6 +96,7 @@ pyenv.:
OK : test if virtualenv is OK OK : test if virtualenv is OK
format.: format.:
python : format Python code source using black python : format Python code source using black
shell : format Shell scripts using shfmt
EOF EOF
go.help go.help
node.help node.help
@ -248,11 +255,17 @@ pyenv.uninstall() {
} }
format.python() { format.python() {
build_msg TEST "[format.python] black \$BLACK_TARGETS" build_msg TEST "[format.python] black ${BLACK_TARGETS[*]}"
pyenv.cmd black "${BLACK_OPTIONS[@]}" "${BLACK_TARGETS[@]}" pyenv.cmd black "${BLACK_OPTIONS[@]}" "${BLACK_TARGETS[@]}"
dump_return $? dump_return $?
} }
format.shell() {
build_msg TEST "[shfmt] shfmt ${SHFMT_SCRIPTS[*]}"
go.tool shfmt --list --write "${SHFMT_SCRIPTS[@]}"
dump_return $?
}
docs.prebuild() { docs.prebuild() {
build_msg DOCS "build ${DOCS_BUILD}/includes" build_msg DOCS "build ${DOCS_BUILD}/includes"
( (

View File

@ -6,8 +6,9 @@ test.help(){
test.: test.:
yamllint : lint YAML files (YAMLLINT_FILES) yamllint : lint YAML files (YAMLLINT_FILES)
pylint : lint ./searx, ./searxng_extra and ./tests pylint : lint ./searx, ./searxng_extra and ./tests
pyright : static type check of python sources (.dev or .ci)
black : check black code format black : check black code format
shfmt : check shfmt code format
shfmt : check Shell script code format
unit : run unit tests unit : run unit tests
coverage : run unit tests with coverage coverage : run unit tests with coverage
robot : run robot test robot : run robot test
@ -105,6 +106,12 @@ test.black() {
dump_return $? dump_return $?
} }
test.shfmt() {
build_msg TEST "[shfmt] ${SHFMT_SCRIPTS[*]}"
go.tool shfmt --list --diff "${SHFMT_SCRIPTS[@]}"
dump_return $?
}
test.unit() { test.unit() {
build_msg TEST 'tests/unit' build_msg TEST 'tests/unit'
# shellcheck disable=SC2086 # shellcheck disable=SC2086