From dde63253d7b990e63a1f4d8540d2e27f7a81a70d Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Wed, 4 Dec 2024 23:38:53 -0600 Subject: [PATCH] Split CI matrix run over several runners --- .github/workflows/test.yml | 11 ++++++++--- ci/util.py | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5b08aaf..a7a4449 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -138,6 +138,11 @@ jobs: unittest-linux: runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + compiler: [g++-10, clang++-18] + dwarf_version: [4, 5] steps: - uses: actions/checkout@v4 - name: dependencies @@ -147,7 +152,7 @@ jobs: cpptrace/ci/setup-prerequisites-unittest.sh - name: build and test run: | - python3 ci/unittest.py + python3 ci/unittest.py --slice=compiler:${{matrix.compiler}} --slice=dwarf_version:${{matrix.dwarf_version}} unittest-linux-bazel: runs-on: ubuntu-22.04 steps: @@ -157,10 +162,10 @@ jobs: sudo apt install -y libtool libncurses5 - name: test dbg run: | - bazel test //... -c dbg + bazel test //... -c dbg - name: test opt run: | - bazel test //... -c opt + bazel test //... -c opt unittest-macos: runs-on: macos-14 steps: diff --git a/ci/util.py b/ci/util.py index 20e06ff..7596292 100644 --- a/ci/util.py +++ b/ci/util.py @@ -1,7 +1,7 @@ import subprocess import sys import itertools -from typing import List +from typing import List, Dict from colorama import Fore, Back, Style import re import time @@ -23,6 +23,7 @@ class MatrixRunner: def __init__(self, matrix, exclude): self.matrix = matrix self.exclude = exclude + self.include = self.parse_includes() self.keys = [*matrix.keys()] self.values = [*matrix.values()] self.results = {} # insertion-ordered @@ -32,6 +33,17 @@ def __init__(self, matrix, exclude): self.last_matrix_config = None self.current_matrix_config = None + def parse_includes(self) -> Dict[str, List[str]]: + includes: Dict[str, List[str]] = dict() + for arg in sys.argv: + if arg.startswith("--slice="): + rest = arg[len("--slice="):] + key, value = rest.split(":") + if key not in includes: + includes[key] = [] + includes[key].append(value) + return includes + def run_command(self, *args: List[str], always_output=False, output_matcher=None) -> bool: self.log(f"{Fore.CYAN}{Style.BRIGHT}Running Command \"{' '.join(args)}\"{Style.RESET_ALL}") start_time = time.time() @@ -78,6 +90,11 @@ def log(self, *args, **kwargs): def do_exclude(self, matrix_config, exclude): return all(map(lambda k: matrix_config[k] == exclude[k], exclude.keys())) + def do_include(self, matrix_config, include): + if len(include) == 0: + return True + return all(map(lambda k: matrix_config[k] in include[k], include.keys())) + def assignment_to_matrix_config(self, assignment): matrix_config = {} for k, v in zip(self.matrix.keys(), assignment): @@ -87,7 +104,10 @@ def assignment_to_matrix_config(self, assignment): def get_work(self): work = [] for assignment in itertools.product(*self.matrix.values()): - if any(map(lambda ex: self.do_exclude(self.assignment_to_matrix_config(assignment), ex), self.exclude)): + config = self.assignment_to_matrix_config(assignment) + if any(map(lambda ex: self.do_exclude(config, ex), self.exclude)): + continue + if not self.do_include(config, self.include): continue work.append(assignment) return work