summaryrefslogtreecommitdiff
path: root/lib/spack/spack/ci.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/ci.py')
-rw-r--r--lib/spack/spack/ci.py83
1 files changed, 81 insertions, 2 deletions
diff --git a/lib/spack/spack/ci.py b/lib/spack/spack/ci.py
index e7606135c3..b48f6d44d2 100644
--- a/lib/spack/spack/ci.py
+++ b/lib/spack/spack/ci.py
@@ -24,7 +24,6 @@ import llnl.util.tty as tty
import spack
import spack.binary_distribution as bindist
-import spack.cmd
import spack.compilers as compilers
import spack.config as cfg
import spack.environment as ev
@@ -514,6 +513,60 @@ def format_job_needs(phase_name, strip_compilers, dep_jobs,
return needs_list
+def get_change_revisions():
+ """If this is a git repo get the revisions to use when checking
+ for changed packages and spack core modules."""
+ git_dir = os.path.join(spack.paths.prefix, '.git')
+ if os.path.exists(git_dir) and os.path.isdir(git_dir):
+ # TODO: This will only find changed packages from the last
+ # TODO: commit. While this may work for single merge commits
+ # TODO: when merging the topic branch into the base, it will
+ # TODO: require more thought outside of that narrow case.
+ return 'HEAD^', 'HEAD'
+ return None, None
+
+
+def compute_affected_packages(rev1='HEAD^', rev2='HEAD'):
+ """Determine which packages were added, removed or changed
+ between rev1 and rev2, and return the names as a set"""
+ 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).
+
+ 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.
+ """
+ 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))
+ return affected_specs
+
+
def generate_gitlab_ci_yaml(env, print_summary, output_file,
prune_dag=False, check_index_only=False,
run_optimizer=False, use_dependencies=False,
@@ -546,6 +599,24 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file,
tty.verbose("Using CDash auth token from environment")
cdash_auth_token = os.environ.get('SPACK_CDASH_AUTH_TOKEN')
+ prune_untouched_packages = os.environ.get('SPACK_PRUNE_UNTOUCHED', None)
+ if prune_untouched_packages:
+ # Requested to prune untouched packages, but assume we won't do that
+ # unless we're actually in a git repo.
+ prune_untouched_packages = False
+ rev1, rev2 = get_change_revisions()
+ tty.debug('Got following revisions: rev1={0}, rev2={1}'.format(rev1, rev2))
+ if rev1 and rev2:
+ prune_untouched_packages = True
+ affected_pkgs = compute_affected_packages(rev1, rev2)
+ tty.debug('affected pkgs:')
+ for p in affected_pkgs:
+ tty.debug(' {0}'.format(p))
+ 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))
+
generate_job_name = os.environ.get('CI_JOB_NAME', None)
parent_pipeline_id = os.environ.get('CI_PIPELINE_ID', None)
@@ -742,6 +813,13 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file,
release_spec_dag_hash = release_spec.dag_hash()
release_spec_build_hash = release_spec.build_hash()
+ if prune_untouched_packages:
+ if release_spec not in affected_specs:
+ tty.debug('Pruning {0}, untouched by change.'.format(
+ release_spec.name))
+ spec_record['needs_rebuild'] = False
+ continue
+
runner_attribs = find_matching_config(
release_spec, gitlab_ci)
@@ -903,7 +981,8 @@ def generate_gitlab_ci_yaml(env, print_summary, output_file,
tty.debug(debug_msg)
if prune_dag and not rebuild_spec:
- tty.debug('Pruning spec that does not need to be rebuilt.')
+ tty.debug('Pruning {0}, does not need rebuild.'.format(
+ release_spec.name))
continue
if (broken_spec_urls is not None and