You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-10-23 21:28:56 +03:00
test.pl becomes test.py and ci.pl becomes ci.py, so an invocation only changes from .pl to .py. Running the tests needs no command since that is what a developer does, and the unit and coverage commands that a run drives are commands of test.py because a test runs inside a container where only the repository copy is available. The Perl library in test/lib is gone. The modules the documentation depends on move to doc/lib, with ExecuteTest becoming Execute, and are trimmed to what the documentation calls, which removes the storage manifest, info, and owner along with everything else the tests were the only user of. release.pl no longer needs the vm definitions since all it did with them was compare two vm names. Nothing in a test container or on a CI runner runs on Perl now so none of it is installed in either place, which was a substantial part of a base image. The packaging tools go with it since they are written in Perl and nothing builds a package, and ca-certificates is installed explicitly because it was arriving as a dependency of a package that is no longer there. Every base image is rebuilt as a result. The generated Dockerfile is otherwise unchanged. The one difference is that the PostgreSQL repository for RHEL is installed for the architecture being built rather than for the architecture of the host, which only differs when cross building. The list of tests to run is unchanged. It was compared against the Perl across the vm, module, test, run, and PostgreSQL version options before the Perl was removed. The vm definitions, the user lookup, the test list, the container build, the job, the test run itself, and the code format are covered by tests, which the Perl equivalents never were. The container build is checked by comparing the generated script in full, since the hash of that script is the cache key. Make the code format a command rather than two options of a test run, and fold in the black check that CI has been running as a step of its own. It gets the files to format from git rather than from the repository copy, so it no longer depends on a test run having made that copy and is told nothing about where either path is. Wire up --log-level-test, which the driver has been collecting and discarding. Remove --psql-bin, --gen-check, --no-coverage-report, --build-max, --log-level-test-file, --no-optimize, --no-debug, and --debug-test-trace, none of which have done anything for some time. Allow --vm=all only for --vm-build. Building every container at once works but running the tests on every vm never has, since a test needs the binary and the build for the vm it runs on and there is one of each.
107 lines
4.3 KiB
Python
107 lines
4.3 KiB
Python
"""Code Format Command.
|
|
|
|
Formats the source to the project standards, or checks that it is already formatted, which is what CI runs. C is formatted with
|
|
uncrustify and python with black, and the execute permissions are checked afterward since a stray execute bit is easy to introduce
|
|
and hard to notice.
|
|
|
|
Only version controlled files are formatted, which is what git reports here, so scratch work in the working tree is left alone."""
|
|
|
|
####################################################################################################################################
|
|
import os
|
|
|
|
from common.error import TestError
|
|
from common.exec import exec_one
|
|
from common.log import *
|
|
|
|
# Line length black formats python to, which is the line length the rest of the project uses
|
|
_LINE_LENGTH = 132
|
|
|
|
# Files that are allowed to be executable. Everything else that is version controlled must not be, since a stray execute bit is
|
|
# usually the result of an editor or a file system that does not preserve modes.
|
|
_FILE_EXECUTABLE_LIST = (
|
|
"doc/doc.pl",
|
|
"doc/release.pl",
|
|
"src/build/dist.sh",
|
|
"test/ci.py",
|
|
"test/smoke.py",
|
|
"test/test.py",
|
|
)
|
|
|
|
|
|
####################################################################################################################################
|
|
def _file_list(path_repo):
|
|
"""The version controlled files, which are the ones that get formatted.
|
|
|
|
Only regular files are returned. A file that is in the index but no longer in the working tree has nothing to format, and git
|
|
reports a symlink to a directory as a single entry rather than descending into it."""
|
|
|
|
file_list = exec_one("git -C %s ls-files -c --others --exclude-standard" % path_repo).splitlines()
|
|
|
|
return [file for file in file_list if os.path.isfile(os.path.join(path_repo, file))]
|
|
|
|
|
|
####################################################################################################################################
|
|
def _format_c(path_repo, file_list, check):
|
|
"""Format the C with uncrustify."""
|
|
|
|
command = "uncrustify -c %s/test/uncrustify.cfg%s" % (path_repo, " --check" if check else " --replace --no-backup")
|
|
|
|
for file in file_list:
|
|
# Skip anything that is not C
|
|
if not file.endswith((".c", ".h", ".c.inc")):
|
|
continue
|
|
|
|
# Skip the test template, which does not format correctly, and vendorized and generated files
|
|
if file == "test/src/test.c" or file.endswith((".vendor.h", ".vendor.c.inc", ".auto.c.inc")):
|
|
continue
|
|
|
|
command += " %s/%s" % (path_repo, file)
|
|
|
|
exec_one(command)
|
|
|
|
|
|
####################################################################################################################################
|
|
def _format_python(path_repo, file_list, check):
|
|
"""Format the python with black."""
|
|
|
|
command = "black --line-length=%u%s" % (_LINE_LENGTH, " --check --diff" if check else "")
|
|
|
|
for file in file_list:
|
|
if file.endswith(".py"):
|
|
command += " %s/%s" % (path_repo, file)
|
|
|
|
exec_one(command)
|
|
|
|
|
|
####################################################################################################################################
|
|
def _permission_check(path_repo, file_list):
|
|
"""Check that nothing is executable that is not meant to be, which formatting can munge."""
|
|
|
|
for file in file_list:
|
|
mode = os.stat(os.path.join(path_repo, file)).st_mode & 0o777
|
|
|
|
if mode & 0o111 and file not in _FILE_EXECUTABLE_LIST:
|
|
raise TestError("expected mode '%04o' for '%s' but found '%04o'" % (mode & 0o666, file, mode))
|
|
|
|
|
|
####################################################################################################################################
|
|
def cmd_code_format(config):
|
|
"""Format the source, or check that it is already formatted."""
|
|
|
|
path_repo = config.repo_path
|
|
file_list = _file_list(path_repo)
|
|
|
|
log(INFO, "code format" + (" check" if config.check else ""))
|
|
|
|
try:
|
|
_format_c(path_repo, file_list, config.check)
|
|
_format_python(path_repo, file_list, config.check)
|
|
except TestError as error:
|
|
if not config.check:
|
|
raise
|
|
|
|
# The check is what CI runs, so it says how to fix what it found rather than only what it found
|
|
raise TestError("%s\nHINT: run 'test.py code-format' to format the code" % error)
|
|
|
|
_permission_check(path_repo, file_list)
|