summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorScott Wittenburg <scott.wittenburg@kitware.com>2022-11-03 13:33:52 -0600
committerGitHub <noreply@github.com>2022-11-03 13:33:52 -0600
commitb55509ffa89f847df3c24ff2a90ce8a11d154a96 (patch)
treeb8e1dcaff2a966eb98077998d6978e899eacc649 /lib
parent08bee718a26c96ceffd228e4917358570239ede1 (diff)
downloadspack-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.py42
-rw-r--r--lib/spack/spack/test/ci.py11
-rw-r--r--lib/spack/spack/test/cmd/ci.py4
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