From 7e3789a5124e37ad7f77e2b10983f6d57e300feb Mon Sep 17 00:00:00 2001 From: Marc Foley Date: Wed, 25 Jan 2023 14:58:03 +0000 Subject: [PATCH] .ci/run.sh: rewrite in python --- .ci/run.py | 145 ++++++++++++++++++++++++++++++++++++ .ci/run.sh | 43 ----------- .github/workflows/test.yaml | 9 +-- 3 files changed, 149 insertions(+), 48 deletions(-) create mode 100644 .ci/run.py delete mode 100644 .ci/run.sh diff --git a/.ci/run.py b/.ci/run.py new file mode 100644 index 0000000000..fedc54d847 --- /dev/null +++ b/.ci/run.py @@ -0,0 +1,145 @@ +#!/usr/bin/python3 +import subprocess +import re +import os +import argparse +from collections import defaultdict +from enum import Enum +from glob import glob + + +class CheckType(Enum): + NEW_FAMILY = 1 + MODIFIED_FAMILY = 2 + MODIFIED_FAMILY_METADATA = 3 + DESIGNER = 4 + + +class CheckToken(Enum): + NEW_FONT = 1 + DESIGNER = 2 + FONT_FAMILY = 3 + MODIFIED_FONTS = 4 + MODIFIED_METADATA = 5 + + +def _parse_git_diff(diff_info: str) -> list[tuple[str, str]]: + """ + ''' + A ofl/mavenpro/MavenPro[wght].ttf + M ofl/mavenpro/METADATA.pb + ''' -> [ + ("A", "ofl/mavenpro/MavenPro[wght].ttf"), + ("M", "ofl/mavenpro/METADATA.pb") + ] + + """ + parsed = re.findall(r"([A|M|D])(\t)(.*)", diff_info) + return [(s, p) for s, _, p in parsed] + + +def directory_check_types(branch="origin/main"): + git_diff_text = subprocess.run( + ["git", "diff", branch, "--name-status"], capture_output=True + ).stdout.decode("utf-8") + git_diff = _parse_git_diff(git_diff_text) + + # Tokenize each directory git diff has reported + directories_to_check = defaultdict(set) + for state, path in git_diff: + dirpath = ( + os.path.dirname(path) + if path not in ("to_sandbox.txt", "to_production.txt") + else path + ) + + dir_tokens = directories_to_check[dirpath] + if path.startswith("catalog"): + dir_tokens.add(CheckToken.DESIGNER) + + if path.startswith(("ofl", "ufl", "apache")): + dir_tokens.add(CheckToken.FONT_FAMILY) + + if path.endswith((".ttf", ".otf")) and state == "A": + dir_tokens.add(CheckToken.NEW_FONT) + + if path.endswith((".ttf", ".otf")) and state == "M": + dir_tokens.add(CheckToken.MODIFIED_FONTS) + + if path.endswith((".txt", ".pb", ".html")) and state == "M": + dir_tokens.add(CheckToken.MODIFIED_METADATA) + + # Set each directory's check type + results = [] + for path, tokens in directories_to_check.items(): + if CheckToken.FONT_FAMILY in tokens: + if CheckToken.MODIFIED_FONTS in tokens: + results.append((path, CheckType.MODIFIED_FAMILY)) + elif CheckToken.MODIFIED_METADATA in tokens: + results.append((path, CheckType.MODIFIED_FAMILY_METADATA)) + else: + results.append((path, CheckType.NEW_FAMILY)) + if CheckToken.DESIGNER in tokens: + results.append((path, CheckType.DESIGNER)) + return results + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--branch", default="origin/main", help="branch to compare current head against" + ) + parser.add_argument( + "--render", action="store_true", help="Check rendering of families only" + ) + parser.add_argument("--pr-number", help="PR to output fontbakery report to") + parser.add_argument("--pr-url-body", default="https://www.github.com/google/fonts/pull/%s") + args = parser.parse_args() + + profile_test_file = os.path.join(os.path.dirname(__file__), "test_profiles.py") + + for directory, check_type in directory_check_types(args.branch): + out = os.path.join("out", os.path.basename(directory)) + fonts = glob(os.path.join(directory, "*.ttf")) + + qa_cmd_prefix = ["gftools", "qa", "-f"] + fonts + ["-o", out] + if args.pr_number: + if not args.pr_url_body.endswith("/"): + args.pr_url_body += "/" + url = "%s%s" % (args.pr_url_body, args.pr_number) + qa_cmd_prefix += ["--out-url", url] + + if args.render and check_type == CheckType.NEW_FAMILY: + print(f"Rendering new family: {directory}") + subprocess.run(qa_cmd_prefix + ["--render", "--imgs"]) + + elif args.render and check_type == CheckType.MODIFIED_FAMILY: + print(f"Rendering modified family: {directory}") + subprocess.run(qa_cmd_prefix + ["-gfb", "--render", "--imgs"]) + + # we only want args.render to do the above two conditions + elif args.render: + continue + + elif check_type == CheckType.NEW_FAMILY: + print(f"Checking new family: {directory}") + subprocess.run(qa_cmd_prefix + ["--fontbakery"]) + + elif check_type == CheckType.MODIFIED_FAMILY: + print(f"Checking modified family: {directory}") + subprocess.run(qa_cmd_prefix + ["-gfb", "--fontbakery", "--diffenator"]) + + elif check_type == CheckType.MODIFIED_FAMILY_METADATA: + print(f"Checking modified family metadata: {directory}") + subprocess.run(qa_cmd_prefix + ["--fontbakery", "-o", out]) + + elif check_type == CheckType.DESIGNER: + print(f"Checking designer profile: {directory}") + subprocess.run(["pytest", profile_test_file, directory]) + + else: + print(f"Skipping directory {directory}") + + +if __name__ == "__main__": + main() diff --git a/.ci/run.sh b/.ci/run.sh deleted file mode 100644 index c30318b6bc..0000000000 --- a/.ci/run.sh +++ /dev/null @@ -1,43 +0,0 @@ -# Only run gftools qa on prs which have modified files in directories which -# contain font binaries. - -# Find directories which contain files that have been altered or added. Also -# Skip /static, axisregistry, cc-by-sa and lang directories. -CHANGED_DIRS=$(git diff origin/main --dirstat=files --diff-filter d | sed "s/[0-9. ].*%//g" | grep -v "static\|axisregistry\|cc-by-sa\|lang") -OUT=out - -PR_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/pull/$PR_NUMBER" -echo "PR url: $PR_URL" - -for dir in $CHANGED_DIRS -do - font_count=$(ls -1 $dir*.ttf 2>/dev/null | wc -l) - is_designer_dir=$(echo $dir | grep "designers") - if [ $font_count != 0 ] - then - echo "Checking $dir" - mkdir -p $OUT - # If pr contains modified fonts, check with Fontbakery, Diffenator and DiffBrowsers. - # If pr doesn't contain modified fonts, just check with Fontbakery. - modified_fonts=$(git diff --name-only origin/main HEAD $dir*.ttf) - if [ -n "$modified_fonts" ] - then - echo "Fonts have been modified. Checking fonts with all tools" - if [ "$SCREENSHOTS" = true ]; then - gftools qa -f $dir*.ttf -gfb --render --imgs -o $OUT/$(basename $dir)_qa - else - gftools qa -f $dir*.ttf -gfb --diffenator --fontbakery -o $OUT/$(basename $dir)_qa --out-url $PR_URL - fi - else - echo "Fonts have not been modified. Checking fonts with Fontbakery only" - gftools qa -f $dir*.ttf --fontbakery -o $OUT/$(basename $dir)_qa --out-url $PR_URL - fi - elif [ ! -z $is_designer_dir ] - then - echo "Checking designer profile" - pytest .ci/test_profiles.py $dir - else - echo "Skipping $dir. Directory does not contain fonts" - fi -done - diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8717808c10..180c2491f4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -29,7 +29,7 @@ jobs: python-version: '3.10' - name: Install packages run: | - pip install "gftools[qa]@git+https://github.com/googlefonts/gftools@main" pytest + pip install gftools[qa] pytest shell: bash - name: Setup Chrome uses: browser-actions/setup-chrome@latest @@ -48,11 +48,10 @@ jobs: mkdir out python -m youseedee 0x078A chromedriver --url-base=/wd/hub & - sh .ci/run.sh + python3 .ci/run.py --render env: PYTHONIOENCODING: 'utf-8' PYTHONUTF8: '1' - SCREENSHOTS: true shell: bash - name: Check file existence @@ -89,11 +88,11 @@ jobs: pip install gftools[qa] pytest shell: bash - - name: Run Diffenator + - name: Run Diffenator and Fontbakery run: | mkdir out python -m youseedee 0x078A - sh .ci/run.sh + python3 .ci/run.py --pr-number $PR_NUMBER --pr-url-body https://www.github.com/m4rc1e/fonts/pull/ env: PYTHONIOENCODING: 'utf-8' PYTHONUTF8: '1' -- 2.47.2