diff options
author | Scott Wittenburg <scott.wittenburg@kitware.com> | 2022-11-03 13:33:52 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-03 13:33:52 -0600 |
commit | b55509ffa89f847df3c24ff2a90ce8a11d154a96 (patch) | |
tree | b8e1dcaff2a966eb98077998d6978e899eacc649 /lib | |
parent | 08bee718a26c96ceffd228e4917358570239ede1 (diff) | |
download | spack-b55509ffa89f847df3c24ff2a90ce8a11d154a96.tar.gz spack-b55509ffa89f847df3c24ff2a90ce8a11d154a96.tar.bz2 spack-b55509ffa89f847df3c24ff2a90ce8a11d154a96.tar.xz spack-b55509ffa89f847df3c24ff2a90ce8a11d154a96.zip |
gitlab: Prune untouched specs less aggressively (#33669)
Untouched spec pruning was added to reduce the number of specs
developers see getting rebuilt in their PR pipelines that they
don't understand. Because the state of the develop mirror lags
quite far behind the tip of the develop branch, PRs often find
they need to rebuild things untouched by their PR.
Untouched spec pruning was previously implemented by finding all
specs in the environment with names of packages touched by the PR,
traversing in both directions the DAGS of those specs, and adding
all dependencies as well as dependents to a list of concrete specs
that should not be considered for pruning.
We found that this heuristic results in too many pruned specs, and
that dependents of touched specs must have all their dependencies
added to the list of specs that should not be considered for pruning.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/ci.py | 42 | ||||
-rw-r--r-- | lib/spack/spack/test/ci.py | 11 | ||||
-rw-r--r-- | lib/spack/spack/test/cmd/ci.py | 4 |
3 files changed, 31 insertions, 26 deletions
diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py index bec7a2f38b..56b3b249ac 100644 --- a/lib/spack/spack/ci.py +++ b/lib/spack/spack/ci.py @@ -515,38 +515,36 @@ def compute_affected_packages(rev1="HEAD^", rev2="HEAD"): return spack.repo.get_all_package_diffs("ARC", rev1=rev1, rev2=rev2) -def get_spec_filter_list(env, affected_pkgs, dependencies=True, dependents=True): - """Given a list of package names, and assuming an active and - concretized environment, return a set of concrete specs from - the environment corresponding to any of the affected pkgs (or - optionally to any of their dependencies/dependents). +def get_spec_filter_list(env, affected_pkgs): + """Given a list of package names and an active/concretized + environment, return the set of all concrete specs from the + environment that could have been affected by changing the + list of packages. Arguments: env (spack.environment.Environment): Active concrete environment affected_pkgs (List[str]): Affected package names - dependencies (bool): Include dependencies of affected packages - dependents (bool): Include dependents of affected pacakges Returns: - A list of concrete specs from the active environment including - those associated with affected packages, and possible their - dependencies and dependents as well. + A set of concrete specs from the active environment including + those associated with affected packages, their dependencies and + dependents, as well as their dependents dependencies. """ affected_specs = set() all_concrete_specs = env.all_specs() tty.debug("All concrete environment specs:") for s in all_concrete_specs: tty.debug(" {0}/{1}".format(s.name, s.dag_hash()[:7])) - for pkg in affected_pkgs: - env_matches = [s for s in all_concrete_specs if s.name == pkg] - for match in env_matches: - affected_specs.add(match) - if dependencies: - affected_specs.update(match.traverse(direction="children", root=False)) - if dependents: - affected_specs.update(match.traverse(direction="parents", root=False)) + env_matches = [s for s in all_concrete_specs if s.name in frozenset(affected_pkgs)] + visited = set() + dag_hash = lambda s: s.dag_hash() + for match in env_matches: + for parent in match.traverse(direction="parents", key=dag_hash): + affected_specs.update( + parent.traverse(direction="children", visited=visited, key=dag_hash) + ) return affected_specs @@ -625,7 +623,7 @@ def generate_gitlab_ci_yaml( affected_specs = get_spec_filter_list(env, affected_pkgs) tty.debug("all affected specs:") for s in affected_specs: - tty.debug(" {0}".format(s.name)) + tty.debug(" {0}/{1}".format(s.name, s.dag_hash()[:7])) # Allow overriding --prune-dag cli opt with environment variable prune_dag_override = os.environ.get("SPACK_PRUNE_UP_TO_DATE", None) @@ -848,7 +846,11 @@ def generate_gitlab_ci_yaml( if prune_untouched_packages: if release_spec not in affected_specs: - tty.debug("Pruning {0}, untouched by change.".format(release_spec.name)) + tty.debug( + "Pruning {0}/{1}, untouched by change.".format( + release_spec.name, release_spec.dag_hash()[:7] + ) + ) spec_record["needs_rebuild"] = False continue diff --git a/lib/spack/spack/test/ci.py b/lib/spack/spack/test/ci.py index 06f212d92a..2a4786d51b 100644 --- a/lib/spack/spack/test/ci.py +++ b/lib/spack/spack/test/ci.py @@ -442,13 +442,16 @@ def test_get_spec_filter_list(mutable_mock_env_path, config, mutable_mock_repo): touched = ["libdwarf"] # traversing both directions from libdwarf in the graphs depicted - # above results in the following possibly affected env specs: - # mpileaks, callpath, dyninst, libdwarf, and libelf. Unaffected - # specs are mpich, plus hypre and it's dependencies. + # above (and additionally including dependencies of dependents of + # libdwarf) results in the following possibly affected env specs: + # mpileaks, callpath, dyninst, libdwarf, libelf, and mpich. + # Unaffected specs are hypre and it's dependencies. affected_specs = ci.get_spec_filter_list(e1, touched) affected_pkg_names = set([s.name for s in affected_specs]) - expected_affected_pkg_names = set(["mpileaks", "callpath", "dyninst", "libdwarf", "libelf"]) + expected_affected_pkg_names = set( + ["mpileaks", "mpich", "callpath", "dyninst", "libdwarf", "libelf"] + ) assert affected_pkg_names == expected_affected_pkg_names diff --git a/lib/spack/spack/test/cmd/ci.py b/lib/spack/spack/test/cmd/ci.py index 5529defee5..b2e84e0c02 100644 --- a/lib/spack/spack/test/cmd/ci.py +++ b/lib/spack/spack/test/cmd/ci.py @@ -1837,8 +1837,8 @@ spack: yaml_contents = syaml.load(contents) for ci_key in yaml_contents.keys(): - if "archive-files" in ci_key or "mpich" in ci_key: - print("Error: archive-files and mpich should have been pruned") + if "archive-files" in ci_key: + print("Error: archive-files should have been pruned") assert False |