@@ -3597,6 +3597,114 @@ def test_import_provenance_survives_non_dict_metadata(
35973597 assert entry ["metadata" ]["imported_from" ] == "github:testuser"
35983598
35993599
3600+ def test_import_provenance_survives_null_metadata (
3601+ tmp_path : pathlib .Path ,
3602+ monkeypatch : MonkeyPatch ,
3603+ caplog : pytest .LogCaptureFixture ,
3604+ ) -> None :
3605+ """Provenance stamping replaces null metadata with a proper dict (SKIP path)."""
3606+ caplog .set_level (logging .INFO )
3607+ monkeypatch .setenv ("HOME" , str (tmp_path ))
3608+ workspace = tmp_path / "repos"
3609+ workspace .mkdir ()
3610+ config_file = tmp_path / ".vcspull.yaml"
3611+
3612+ # Existing entry with metadata: null (YAML null → Python None)
3613+ save_config_yaml (
3614+ config_file ,
3615+ {"~/repos/" : {"repo1" : {"repo" : _SSH , "metadata" : None }}},
3616+ )
3617+
3618+ importer = MockImporter (repos = [_make_repo ("repo1" )])
3619+ _run_import (
3620+ importer ,
3621+ service_name = "github" ,
3622+ target = "testuser" ,
3623+ workspace = str (workspace ),
3624+ mode = "user" ,
3625+ language = None ,
3626+ topics = None ,
3627+ min_stars = 0 ,
3628+ include_archived = False ,
3629+ include_forks = False ,
3630+ limit = 100 ,
3631+ config_path_str = str (config_file ),
3632+ dry_run = False ,
3633+ yes = True ,
3634+ output_json = False ,
3635+ output_ndjson = False ,
3636+ color = "never" ,
3637+ sync = True ,
3638+ import_source = "github:testuser" ,
3639+ )
3640+
3641+ from vcspull ._internal .config_reader import ConfigReader
3642+
3643+ final_config = ConfigReader ._from_file (config_file )
3644+ assert final_config is not None
3645+ entry = final_config ["~/repos/" ]["repo1" ]
3646+ assert isinstance (entry ["metadata" ], dict )
3647+ assert entry ["metadata" ]["imported_from" ] == "github:testuser"
3648+
3649+
3650+ def test_import_update_url_survives_null_metadata (
3651+ tmp_path : pathlib .Path ,
3652+ monkeypatch : MonkeyPatch ,
3653+ caplog : pytest .LogCaptureFixture ,
3654+ ) -> None :
3655+ """Provenance stamping replaces null metadata with a proper dict (UPDATE path)."""
3656+ caplog .set_level (logging .INFO )
3657+ monkeypatch .setenv ("HOME" , str (tmp_path ))
3658+ workspace = tmp_path / "repos"
3659+ workspace .mkdir ()
3660+ config_file = tmp_path / ".vcspull.yaml"
3661+
3662+ # Existing entry with a different URL and metadata: null
3663+ save_config_yaml (
3664+ config_file ,
3665+ {
3666+ "~/repos/" : {
3667+ "repo1" : {
3668+ "repo" : "git+git@github.com:testuser/repo1-OLD.git" ,
3669+ "metadata" : None ,
3670+ },
3671+ },
3672+ },
3673+ )
3674+
3675+ importer = MockImporter (repos = [_make_repo ("repo1" )])
3676+ _run_import (
3677+ importer ,
3678+ service_name = "github" ,
3679+ target = "testuser" ,
3680+ workspace = str (workspace ),
3681+ mode = "user" ,
3682+ language = None ,
3683+ topics = None ,
3684+ min_stars = 0 ,
3685+ include_archived = False ,
3686+ include_forks = False ,
3687+ limit = 100 ,
3688+ config_path_str = str (config_file ),
3689+ dry_run = False ,
3690+ yes = True ,
3691+ output_json = False ,
3692+ output_ndjson = False ,
3693+ color = "never" ,
3694+ sync = True ,
3695+ import_source = "github:testuser" ,
3696+ )
3697+
3698+ from vcspull ._internal .config_reader import ConfigReader
3699+
3700+ final_config = ConfigReader ._from_file (config_file )
3701+ assert final_config is not None
3702+ entry = final_config ["~/repos/" ]["repo1" ]
3703+ assert isinstance (entry ["metadata" ], dict )
3704+ assert entry ["metadata" ]["imported_from" ] == "github:testuser"
3705+ assert entry ["repo" ] == _SSH
3706+
3707+
36003708# ---------------------------------------------------------------------------
36013709# --prune standalone flag tests
36023710# ---------------------------------------------------------------------------
0 commit comments