From 3e3603903cf2660ae80b37801623d32a86824698 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:03:54 +0000 Subject: [PATCH 1/2] Initial plan From 34649b19cc3d5f9237fa77b579cf66906c3f9c67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:08:56 +0000 Subject: [PATCH 2/2] Add Tests badge to README; rename directories config key to paths Agent-Logs-Url: https://github.com/FertigLab/ontrack/sessions/f62efca8-f1d3-44a5-995d-e62225ac50db Co-authored-by: dimalvovs <1246862+dimalvovs@users.noreply.github.com> --- README.md | 6 ++++-- config.yaml | 2 +- ontrack.py | 12 ++++++------ tests/test_ontrack.py | 44 +++++++++++++++++++++---------------------- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index fbca482..8e02d68 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ontrack +[![Tests](https://github.com/FertigLab/ontrack/actions/workflows/tests.yml/badge.svg)](https://github.com/FertigLab/ontrack/actions/workflows/tests.yml) + A command-line tool that scans directory trees and reports file statistics (file count, total size) for locations defined in a YAML configuration file. Supports Unix group-based filtering. ## Requirements @@ -20,7 +22,7 @@ Create a YAML config file (see [`config.yaml`](config.yaml) for a template): ```yaml # Top-level directories to scan -directories: +paths: - /path/to/data # Unix group whose members' subdirectories should be reported (optional) @@ -34,7 +36,7 @@ ignore: | Key | Description | |---|---| -| `directories` | List of top-level paths to scan (required) | +| `paths` | List of top-level paths to scan (required) | | `group` | Unix group name; enables group mode (optional, overridden by `--group`) | | `ignore` | Glob patterns matched against base names to exclude from all scans | diff --git a/config.yaml b/config.yaml index 995ca7f..f41eb68 100644 --- a/config.yaml +++ b/config.yaml @@ -2,7 +2,7 @@ # Specify the top-level directories to scan. # For each directory, first-level subdirectories owned by members of `groups` # will be reported. -directories: +paths: - /path/to/your/data # Unix groups whose members' subdirectories should be reported. diff --git a/ontrack.py b/ontrack.py index 49f91ac..b07c212 100644 --- a/ontrack.py +++ b/ontrack.py @@ -393,14 +393,14 @@ def main( output: Write YAML report to this path instead of printing to stdout. """ config = load_config(config_path) - directories = config.get("directories", []) + paths: list[str] = config.get("paths", []) # Allow groups to be specified in the config file; CLI takes precedence. if groups is None: groups = config.get("groups") - if not directories: - print("No directories specified in configuration.", file=sys.stderr) + if not paths: + print("No paths specified in configuration.", file=sys.stderr) sys.exit(1) # Read ignore patterns from the config file. @@ -408,7 +408,7 @@ def main( if ignore_patterns: logger.info("Ignore patterns: %s", ignore_patterns) - logger.info("Directories supplied: %s", directories) + logger.info("Paths supplied: %s", paths) if groups is not None: members: set[str] = set() @@ -418,7 +418,7 @@ def main( members.update(group_members) subdirs: list[str] = [] - for parent_dir in directories: + for parent_dir in paths: if not pathlib.Path(parent_dir).is_dir(): print( f"WARNING: '{parent_dir}' is not a valid directory – skipping.", @@ -429,7 +429,7 @@ def main( paths_to_process: list[str] = subdirs else: - paths_to_process = directories + paths_to_process = paths iterator = ( tqdm(paths_to_process, desc="Processing directories", unit="dir", file=sys.stderr) diff --git a/tests/test_ontrack.py b/tests/test_ontrack.py index ed88086..29c0b78 100644 --- a/tests/test_ontrack.py +++ b/tests/test_ontrack.py @@ -132,7 +132,7 @@ def test_get_username_returns_string(): def test_load_config(): - config_data = {"directories": ["/tmp/test1", "/tmp/test2"]} + config_data = {"paths": ["/tmp/test1", "/tmp/test2"]} with tempfile.NamedTemporaryFile( mode="w", suffix=".yaml", delete=False ) as tmp: @@ -141,7 +141,7 @@ def test_load_config(): try: loaded = load_config(tmp_path) - assert loaded["directories"] == ["/tmp/test1", "/tmp/test2"] + assert loaded["paths"] == ["/tmp/test1", "/tmp/test2"] finally: os.unlink(tmp_path) @@ -178,7 +178,7 @@ def test_report_directory_invalid(capsys): def test_main_no_directories(tmp_path): config_file = tmp_path / "config.yaml" - config_file.write_text("directories: []\n") + config_file.write_text("paths: []\n") with pytest.raises(SystemExit): main(str(config_file)) @@ -190,7 +190,7 @@ def test_main_with_valid_directory(tmp_path, capsys): (data_dir / "file.txt").write_text("hello world") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") main(str(config_file)) captured = capsys.readouterr() @@ -321,7 +321,7 @@ def test_main_with_group(tmp_path, capsys): (user_subdir / "file.txt").write_text("hello world") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") main(str(config_file), groups=[group_name]) captured = capsys.readouterr() @@ -351,7 +351,7 @@ def test_main_with_multiple_groups(tmp_path, capsys): (user_subdir / "file.txt").write_text("hello world") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") main(str(config_file), groups=[group_name, second_group]) captured = capsys.readouterr() @@ -382,7 +382,7 @@ def test_main_multiple_groups_from_config(tmp_path, capsys): config_file = tmp_path / "config.yaml" config_file.write_text( - f"directories:\n - {data_dir}\ngroups:\n - {group_name}\n - {second_group}\n" + f"paths:\n - {data_dir}\ngroups:\n - {group_name}\n - {second_group}\n" ) main(str(config_file)) @@ -403,12 +403,12 @@ def test_main_logs_directories(tmp_path, caplog): (data_dir / "file.txt").write_text("hello") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") with caplog.at_level(logging.INFO, logger="ontrack"): main(str(config_file)) - assert "Directories supplied" in caplog.text + assert "Paths supplied" in caplog.text assert str(data_dir) in caplog.text @@ -424,7 +424,7 @@ def test_main_logs_group_members(tmp_path, caplog): (data_dir / "file.txt").write_text("hello") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") with caplog.at_level(logging.INFO, logger="ontrack"): main(str(config_file), groups=[group_name]) @@ -441,7 +441,7 @@ def test_main_no_group_logging_skipped(tmp_path, caplog): (data_dir / "file.txt").write_text("hello") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") with caplog.at_level(logging.INFO, logger="ontrack"): main(str(config_file)) @@ -775,7 +775,7 @@ def test_main_group_from_config(tmp_path, capsys): (user_subdir / "file.txt").write_text("content") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\ngroups:\n - {group_name}\n") + config_file.write_text(f"paths:\n - {data_dir}\ngroups:\n - {group_name}\n") main(str(config_file)) # no groups kwarg; should come from config captured = capsys.readouterr() @@ -796,7 +796,7 @@ def test_main_cli_group_overrides_config(tmp_path, capsys): config_file = tmp_path / "config.yaml" # Config contains a bogus group; the CLI groups should win. - config_file.write_text(f"directories:\n - {data_dir}\ngroups:\n - __bogus_group__\n") + config_file.write_text(f"paths:\n - {data_dir}\ngroups:\n - __bogus_group__\n") main(str(config_file), groups=[group_name]) captured = capsys.readouterr() @@ -810,7 +810,7 @@ def test_main_with_group_invalid_parent_dir(tmp_path, capsys): group_name = grp.getgrgid(current_gid).gr_name config_file = tmp_path / "config.yaml" - config_file.write_text("directories:\n - /nonexistent/path/xyz\n") + config_file.write_text("paths:\n - /nonexistent/path/xyz\n") main(str(config_file), groups=[group_name]) captured = capsys.readouterr() @@ -858,7 +858,7 @@ def test_main_light_mode_omits_stats(tmp_path, capsys): (data_dir / "file.txt").write_text("hello world") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") main(str(config_file), light=True) captured = capsys.readouterr() @@ -879,7 +879,7 @@ def test_main_output_writes_yaml(tmp_path): (data_dir / "file.txt").write_text("hello world") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") output_file = str(tmp_path / "report.yaml") main(str(config_file), output=output_file) @@ -904,7 +904,7 @@ def test_main_output_does_not_print(tmp_path, capsys): (data_dir / "file.txt").write_text("content") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") output_file = str(tmp_path / "report.yaml") main(str(config_file), output=output_file) @@ -919,7 +919,7 @@ def test_main_output_light_mode(tmp_path): (data_dir / "file.txt").write_text("hello") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") output_file = str(tmp_path / "report.yaml") main(str(config_file), light=True, output=output_file) @@ -1154,7 +1154,7 @@ def test_main_config_ignore_excludes_hidden_files(tmp_path, capsys): (data_dir / ".hidden").write_text("secret") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\nignore:\n - '.*'\n") + config_file.write_text(f"paths:\n - {data_dir}\nignore:\n - '.*'\n") main(str(config_file)) captured = capsys.readouterr() @@ -1172,7 +1172,7 @@ def test_main_config_ignore_excludes_dirs(tmp_path, capsys): (data_dir / "readme.txt").write_text("hi") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\nignore:\n - '.*'\n") + config_file.write_text(f"paths:\n - {data_dir}\nignore:\n - '.*'\n") main(str(config_file)) captured = capsys.readouterr() @@ -1188,7 +1188,7 @@ def test_main_config_ignore_wildcard_extension(tmp_path, capsys): (data_dir / "unwanted.tmp").write_text("junk") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\nignore:\n - '*.tmp'\n") + config_file.write_text(f"paths:\n - {data_dir}\nignore:\n - '*.tmp'\n") main(str(config_file)) captured = capsys.readouterr() @@ -1204,7 +1204,7 @@ def test_main_no_ignore_key_counts_all_files(tmp_path, capsys): (data_dir / ".hidden").write_text("world!") config_file = tmp_path / "config.yaml" - config_file.write_text(f"directories:\n - {data_dir}\n") + config_file.write_text(f"paths:\n - {data_dir}\n") main(str(config_file)) captured = capsys.readouterr()