diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ed3de8e..83b6a803 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: - repo: https://github.com/ambv/black - rev: 22.6.0 + rev: 25.9.0 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/common.mk b/common.mk index 77e029c6..b4d7d632 100644 --- a/common.mk +++ b/common.mk @@ -158,3 +158,6 @@ generate: $(generator) -v $$version -m manifest.yml -s specs/multispec.yml ; \ fi \ done + +version-table: + $(common_dir)/generate_version_table.py "$(BASE_IMAGE_NAME)" diff --git a/generate_version_table.py b/generate_version_table.py new file mode 100755 index 00000000..5f075bae --- /dev/null +++ b/generate_version_table.py @@ -0,0 +1,138 @@ +#!/usr/bin/python3 +import os +import re +import sys +from natsort import natsorted + +distro_names = { + "c9s": ["CentOS Stream 9", "quay.io/sclorg/%s-c9s"], + "c10s": ["CentOS Stream 10", "quay.io/sclorg/%s-c10s"], + "fedora": ["Fedora", "quay.io/fedora/%s"], + "rhel8": ["RHEL 8", "registry.redhat.io/rhel8/%s"], + "rhel9": ["RHEL 9", "registry.redhat.io/rhel9/%s"], + "rhel10": ["RHEL 10", "registry.redhat.io/rhel10/%s"], +} +version_regex = re.compile(r"^VERSIONS\s*=\s*(.*)$") +docker_file_regex = re.compile(r"(?<=Dockerfile\.).+") +exclude_file_regex = re.compile(r"(?<=\.exclude-).+") + +table_regex = re.compile( + r"(\n).*?(\n)", re.DOTALL +) + + +def main(name: str) -> None: + docker_distros = {} + all_distros = set() + + versions = _get_versions() + if len(versions) == 0: + print( + "No VERSIONS variable found in Makefile, please make sure the syntax is correct", + file=sys.stderr, + ) + exit(2) + + # goes through all the versions and gets their dockerfile + # and 'exclude-' distros + for version in versions: + files = "\n".join(os.listdir(version)) + available_distros: set[str] = set(re.findall(docker_file_regex, files)) + exclude_distros = set(re.findall(exclude_file_regex, files)) + unsupported = available_distros - distro_names.keys() + if len(unsupported) > 0: + print( + f"WARNING: Distros {list(unsupported)} in version " + + f"{version} are unsupported and Dockerfiles for them should be deleted", + file=sys.stderr, + ) + all_distros |= available_distros + docker_distros[version] = ( + available_distros - exclude_distros + ) & distro_names.keys() + all_distros &= distro_names.keys() + + table = _create_table(natsorted(all_distros), versions, docker_distros, name) + _replace_in_readme(table) + + +# gets the versions of the container from the Makefile +def _get_versions() -> list[str]: + try: + with open("Makefile", "r") as f: + for line in f: + match = re.search(version_regex, line) + if match: + return match.group(1).split(" ") + except Exception as e: + print( + f"An exception occurred when trying to read the Makefile: {e}", + file=sys.stderr, + ) + exit(1) + return [] + + +# generates the table string +def _create_table( + distros: list[str], + versions: list[str], + docker_distros: dict[str, set[str]], + name: str, +) -> str: + # table header + table = f"||{'|'.join([distro_names[distro][0] for distro in distros])}|\n" + # prints the table column separator + # align the versions to left and ticks to center + table += f"|:--|{':--:|' * len(distros)}\n" + for version in versions: + # prints the version line header + table += f"|{version}" + # goes over the distros and prints a tick and repo address + # if the image is available + for distro in distros: + table += "|" + if distro in docker_distros[version]: + table += ( + "
" + + f"`{distro_names[distro][1] % (name + "-" + version.replace('.', ''))}`
" + ) + # end the table line + table += "|\n" + return table + + +# reads the README.md, finds the Table start and Table end comments +# replaces any string between them with the table string +# and writes it back to the README.md file +def _replace_in_readme(table: str) -> None: + try: + with open("README.md", "r+") as readme: + original_readme = readme.read() + new_readme, subs = re.subn(table_regex, f"\\1{table}\\2", original_readme) + if subs == 0: + print( + "The Table start and Table end tag not found, not modifying README.md", + file=sys.stderr, + ) + exit(0) + if subs > 1: + print( + "More than one Table start and Table end tag found, not modifying README.md", + file=sys.stderr, + ) + exit(0) + readme.seek(0) + readme.write(new_readme) + readme.truncate() + except Exception as e: + print(f"An error occurred while trying to open README.md: {e}", file=sys.stderr) + exit(1) + + +if __name__ == "__main__": + args = sys.argv[1:] + if len(args) != 1: + print("Usage: ./generate_table.py NAME\nThe NAME of the image is required") + exit(2) + main(args[0]) diff --git a/tests/check_generate_version_table.sh b/tests/check_generate_version_table.sh new file mode 100755 index 00000000..be2af7ef --- /dev/null +++ b/tests/check_generate_version_table.sh @@ -0,0 +1,118 @@ +#!/usr/bin/bash + +if [ "$(dirname "$0")" != "." ]; then + echo "You need to run this script from the directory it's located in (./tests)" + exit 1 +fi + +# setup +mkdir test-container || exit 1 +pushd test-container || exit 1 +echo " +BASE_IMAGE_NAME = test +VERSIONS = 1.2 2.3 +include ../../common.mk +" > Makefile +export common_dir="../.." + +# create base files for the script to work +mkdir 1.2 +mkdir 2.3 +touch 1.2/Dockerfile.c8s +touch 1.2/Dockerfile.c9s +touch 1.2/Dockerfile.fedora +touch 1.2/Dockerfile.rhel8 +touch 1.2/Dockerfile.rhel9 +touch 1.2/.exclude-c9s +touch 1.2/.exclude-rhel9 +touch 2.3/Dockerfile.c9s +touch 2.3/Dockerfile.c10s +touch 2.3/Dockerfile.fedora +touch 2.3/Dockerfile.rhel9 +touch 2.3/Dockerfile.rhel10 +touch 2.3/.exclude-fedora + +# test README without table tags +touch README.md +make version-table &>/dev/null || exit 1 +if [ ! -s "README.md" ]; then + echo "[PASS] README without table tags not modified" +else + echo "[FAIL] README without table tags modified" +fi + +# test README with table tags +echo " + +this will be overwritten + +text outside +" > README.md + +echo " + +||CentOS Stream 9|CentOS Stream 10|Fedora|RHEL 8|RHEL 9|RHEL 10| +|:--|:--:|:--:|:--:|:--:|:--:|:--:| +|1.2|||
\`quay.io/fedora/test-12\`
|
\`registry.redhat.io/rhel8/test-12\`
||| +|2.3|
\`quay.io/sclorg/test-23-c9s\`
|
\`quay.io/sclorg/test-23-c10s\`
|||
\`registry.redhat.io/rhel9/test-23\`
|
\`registry.redhat.io/rhel10/test-23\`
| + +text outside +" > README.expected +make version-table &>/dev/null || exit 1 +if diff README.md README.expected ; then + echo "[PASS] README with table tags modified correctly" +else + echo "[FAIL] README with table tags modified incorrectly or not modified" +fi + +# test README with multiple pairs of table tags +echo " + + +text inbetween + + +" > README.md + +echo " + + +text inbetween + + +" > README.expected + +make version-table &>/dev/null || exit 1 +if diff README.md README.expected ; then + echo "[PASS] README with multiple pairs of table tags unmodified" +else + echo "[FAIL] README with multiple pairs of table tags modified" +fi + +# cleanup +popd || exit 1 +rm -rf test-container