diff --git a/dvc/dvcfile.py b/dvc/dvcfile.py index df8a61b7c..023d69517 100644 --- a/dvc/dvcfile.py +++ b/dvc/dvcfile.py @@ -208,6 +208,8 @@ class PipelineFile(FileMixin): if existing_entry: orig_stage_data = data["stages"][stage.name] + if "meta" in orig_stage_data: + stage_data[stage.name]["meta"] = orig_stage_data["meta"] apply_diff(stage_data[stage.name], orig_stage_data) else: data["stages"].update(stage_data) diff --git a/tests/func/test_dvcfile.py b/tests/func/test_dvcfile.py index 6ba4ed72a..6206f12e3 100644 --- a/tests/func/test_dvcfile.py +++ b/tests/func/test_dvcfile.py @@ -290,3 +290,37 @@ def test_remove_stage_preserves_comment(tmp_dir, dvc, run_copy): "# This copies 'foo' text to 'foo' file." in (tmp_dir / PIPELINE_FILE).read_text() ) + + +def test_dvcfile_dump_preserves_meta(tmp_dir, dvc, run_copy): + tmp_dir.gen("foo", "foo") + stage = run_copy("foo", "bar", name="run_copy") + dvcfile = stage.dvcfile + + data = dvcfile._load()[0] + metadata = {"name": "copy-file"} + data["stages"]["run_copy"]["meta"] = metadata + dump_yaml(dvcfile.path, data) + + dvcfile.dump(stage, update_pipeline=True) + assert dvcfile._load()[0] == data + assert dvcfile._load()[0]["stages"]["run_copy"]["meta"] == metadata + + +def test_dvcfile_dump_preserves_comments(tmp_dir, dvc): + text = textwrap.dedent( + """\ + stages: + generate-foo: + cmd: echo foo > foo + # This copies 'foo' text to 'foo' file. + outs: + - foo""" + ) + tmp_dir.gen("dvc.yaml", text) + stage = dvc.get_stage(name="generate-foo") + stage.outs[0].use_cache = False + dvcfile = stage.dvcfile + + dvcfile.dump(stage, update_pipeline=True) + assert dvcfile._load()[1] == (text + ":\n\tcache: false\n".expandtabs())