diff --git a/dvc/repo/reproduce.py b/dvc/repo/reproduce.py index df5df0389..231662a04 100644 --- a/dvc/repo/reproduce.py +++ b/dvc/repo/reproduce.py @@ -3,6 +3,8 @@ from functools import partial from typing import TYPE_CHECKING, Iterator, List from dvc.exceptions import DvcException, ReproductionError +from dvc.repo.metrics.show import _collect_top_level_metrics +from dvc.repo.params.show import _collect_top_level_params from dvc.repo.scm_context import scm_context from dvc.stage.exceptions import CheckpointKilledError @@ -74,6 +76,17 @@ def _track_stage(stage: "Stage") -> None: return context.track_changed_files() +def _track_top_level(repo: "Repo") -> None: + context = repo.scm_context + for metric_file in _collect_top_level_metrics(repo): + context.track_file(metric_file) + for param_file in _collect_top_level_params(repo): + context.track_file(param_file) + for plot_file in repo.index._plot_sources: # pylint: disable=protected-access + context.track_file(plot_file) + context.track_changed_files() + + @locked @scm_context def reproduce( # noqa: C901 @@ -125,7 +138,9 @@ def reproduce( # noqa: C901 ) ) - return _reproduce_stages(self.index.graph, list(stages), **kwargs) + result = _reproduce_stages(self.index.graph, list(stages), **kwargs) + _track_top_level(self) + return result def _reproduce_stages( # noqa: C901 diff --git a/tests/func/experiments/test_experiments.py b/tests/func/experiments/test_experiments.py index f6e9d5b5e..794adf7bc 100644 --- a/tests/func/experiments/test_experiments.py +++ b/tests/func/experiments/test_experiments.py @@ -683,3 +683,24 @@ def test_local_config_is_propagated_to_tmp(tmp_dir, scm, dvc): with fs.open("file") as fobj: conf_obj = ConfigObj(fobj) assert conf_obj["cache"]["type"] == "hardlink" + + +@pytest.mark.parametrize("tmp", [True, False]) +def test_untracked_top_level_files_are_included_in_exp(tmp_dir, scm, dvc, tmp): + (tmp_dir / "dvc.yaml").dump( + { + "metrics": ["metrics.json"], + "params": ["params.yaml"], + "plots": ["plots.csv"], + } + ) + stage = dvc.stage.add( + cmd="touch metrics.json && touch params.yaml && touch plots.csv", + name="top-level", + ) + scm.add_commit(["dvc.yaml"], message="add dvc.yaml") + results = dvc.experiments.run(stage.addressing, tmp_dir=tmp) + exp = first(results) + fs = scm.get_fs(exp) + for file in ["metrics.json", "params.yaml", "plots.csv"]: + assert fs.exists(file)